![]() |
|
|
|||||||
| Регистрация | << Правила форума >> | FAQ | Пользователи | Календарь | Поиск | Сообщения за сегодня | Все разделы прочитаны |
![]() |
|
|
Опции темы | Поиск в этой теме | Опции просмотра |
|
#1
|
|||
|
|||
|
Доброго времени суток!
Задача состоит в следующем: из загруженной картинки (для начала BMP) необходимо получить количество пикселов каждого цвета, которые содержит картинка. Задача простая, но как решить не знаю, с графикой дела не имел! Поможите плиз! )) |
|
#2
|
||||
|
||||
|
самый простой способ - перебор, может есть и другие
Код:
function ColorCount(const Pic: TImage; const Color: TColor): Integer; var i, j: Integer; begin Result:=0; for i:=1 to Pic.Width do for j:=1 to Pic.Height do if Pic.Canvas.Pixels[i][j] = Color then Inc(Result); end; |
|
#3
|
|||
|
|||
|
неее, нужно посчитать сколько всего цветов в картинке и вывести какие это конкретно цвета! Как посчитать сколько цветов я нашел:
Код:
function HowManyColors(Bitmap: TBitmap): Integer;
type
TRGB = record
B, G, R: Byte;
end;
pRGB = ^TRGB;
var
i: Byte;
x, y: Integer;
Dest: pRGB;
RGBArray: array[0..255, 0..255] of array of Byte;
begin
Bitmap.PixelFormat := pf24Bit;
Result := 0;
for y := 0 to Bitmap.Height - 1 do
begin
Dest := Bitmap.ScanLine[y];
for x := 0 to Bitmap.Width - 1 do
begin
with Dest^ do
if RGBArray[r, g] <> nil then
for i := 0 to High(RGBArray[r, g]) do
begin
//если такой цвет уже есть, то выходим из цыкла
if RGBArray[r, g][i] = b then
Break;
//если это последний круг цикла, то такого цвета нет
if i = High(RGBArray[r, g]) then
begin
Inc(Result); //прибавляем один цвет
SetLength(RGBArray[r, g], Length(RGBArray[r, g]) + 1);
RGBArray[r, g][High(RGBArray[r, g])] := b;
end;
end
else
begin
Inc(Result);
SetLength(RGBArray[r, g], 1);
RGBArray[r, g][0] := b;
end;
Inc(Dest);
end;
end;
end;
Пример использования:
procedure TForm1.MMHowManyColorsClick(Sender: TObject);
var
str: string;
begin
Screen.Cursor := crHourGlass;
try
str := Format('Изображение содержит %d цветов.', [HowManyColors(FBitmap)]);
finally
Screen.Cursor := crDefault;
end;
Application.MessageBox(PChar(str), PChar(Application.Title), MB_OK);
end;А вот как получить эти цета??? То есть например если цветов на картинке встречается 3 штуки, то вывести: Цвет 1 - код цвета; Цвет 2 - код цвета; Цвет 3 - код цвета; |
|
#4
|
||||
|
||||
|
что нибудь такое (неоптимизированно, скорее всего есть варианты вроде того, что вы привели в качестве примера для вычисления числа цветов изображения
)Код:
var i, j: Cardinal; Colors: array [$FF000000..$FFFFFFFF] of integer; begin for i:=1 to Image.Picture.Width do for j:=1 to Image.Picture.Height do Inc(Colors[Image.Canvas.Pixels[i, j]]); for i:=$FF000000 to $FFFFFFFF do if Colors[Image.Canvas.Pixels[i, j]] > 0 then Memo1.Lines.Add(IntToStr(i) + ' ' + IntToStr(Colors[i]) + ' раз'); |
|
#5
|
|||
|
|||
|
Переполнение стека пишет! А как приведенный мною код поправить как мне надо??? Я чето не могу понять что там делается...
|
|
#6
|
||||
|
||||
|
со ScanLine'ми не работал, вроде в факе были примеры какие то
|
|
#7
|
|||
|
|||
|
Цитата:
))) при отработке алгоритма, потребуется создание массива длинною 16 777 216 элементов, и потребуется выделения памяти более чем на 67 мегабайт))) Лучше создать пустой массив и добавлять в него найденные цвета, в данном случае максимальное кол-во цветов не превысит Height * Width. Обращение через Canvas.Pixels[,] - оооочень медленное, в данном случае ScanLine работает в сотню! раз быстрее) |
|
#8
|
|||
|
|||
|
Цитата:
Очень понравилась задача, решил попробовать свои силы) Идея проста, но сложно реализована для повышения производительности. желательно на время работы функции блокировать вызывающий ее обработчик. Код:
function TForm1.HowManyColors(const Bitmap: TBitmap; const Memo:TMemo): Integer;
type //это лучше определять в начале модуля
TRGB = record
B, G, R: Byte;
end;
ARGB = array[0..1] of TRGB;
PARGB = ^ARGB;
const
CArrayLengthInc = 10000;
type //а это в функции
TColorCnt = record
FColor:TColor; //Одна ячейка массива содержит цвет
FCount:Integer; //и его кол-во
end;
var
x, y, i, l, tmp:integer;
p: PARGB;
Colors: Array of TColorCnt; //Массив всех найденых цветов
begin
//Подготовимся)
l:=CArrayLengthInc;
SetLength(Colors,l); //для начала создадим массив на 10000 элементов
//Функция SetLength будет тормозить весь процесс, лучше
//ее вызывать поменьше)
with Colors[0] do
begin
FColor:=0; //один цвет (черный) определим заранее
FCount:=0;
end;
Result:=1; //Result - кол-во найденных элементов)
with Bitmap do
for y := 0 to Height - 1 do //перебираем строки массива(линии картинки)
begin
p := ScanLine[y];
for x := 0 to Width - 1 do//перебираем элементы массива (пиксели)
begin
with p[x] do tmp:=(r*g*b); //берем цвет пикселя
for i:=0 to Result - 1 do //перебираем цвета
if Colors[i].FColor = tmp then // если у нас есть такой цвет
begin
Inc(Colors[i].FCount); //то увеличиваем у него счетчик
Break; //и покидаем цикл перебора цветов
end;
if Length(Colors)=Result then //иначе проверяем не достигнут ли
begin //конец массива
Inc(l,CArrayLengthInc); //если да, то увеличиваем его еще
SetLength(Colors, l); //на 10000 элементов
end;
with Colors[Result] do //и сохраняем новый цвет
begin
FColor:=tmp;
FCount:=1;
end;
Inc(Result);
//результаты можно вставить вывод результата статуса
// выполнения данной функции, к примеру если ты хочешь
//показывать состояние выполнения)
Application.ProcessMessages; //Это что бы приложение не висло
end;
end;
//Вот вывести все элементы - безумие, так как цветов может быть
//очень большое кол-во и займет это чуть меньше времени, чем
//первая чать функции, я бы отказался от этой затеи)
with Memo.Lines do
begin
BeginUpdate;
Clear;
if (Result-Ord(Colors[0].FCount=0))>0 then
for i:=0+Ord(Colors[0].FCount=0) to Result-1 do
with Colors[i] do
Add('Код цвета: '+IntToStr(FColor)+' - '+IntToStr(FCount)+' раз');
EndUpdate;
end;
//пора покинуть функцию, но вдруг у картинки не было черного цвета,
if Colors[0].FCount = 0 then Dec(Result); // не будем врать)
SetLength(Colors,0); //и освободим массив
end;
procedure TForm1.MMHowManyColorsClick(Sender: TObject);
begin
ShowMessage('Изображение содержит '+Inttostr(
HowManyColors(Image1.Picture.Bitmap,Memo1))+' цветов');
end;При больших и многокрасочных изображениях, процесс выполнения будет длительным (в этом случае, как минимум стоит удалить вывод всех элементов, блок with Memo Lines do begin .. end)! Удачи) Последний раз редактировалось Asinkrit, 31.10.2009 в 01:56. |
|
#9
|
|||
|
|||
|
А как решить вопрос с памятью? При загрузке файла размером больше 500 мб, выскакивает сообщение о нехватке памяти!
|
|
#10
|
||||
|
||||
|
Да не нужно загружать картинку вообще, работай напрямую с файлом.
|
|
#11
|
|||
|
|||
|
Цитата:
|
|
#12
|
||||
|
||||
|
Можешь мне не верить, но будет работать вполне приемлимо
![]() Вот только писать код только ради того чтобы проверить его на скорость - мне как-то лениво. |
|
#13
|
|||
|
|||
|
Тогда вопрос что значит работать с файлом напрямую? Соответствует ли этому принципу последний код, написанный Asinkrit'ом???
|
|
#14
|
||||
|
||||
|
Цитата:
|
|
#15
|
||||
|
||||
|
Цитата:
|