Распознавание образов - применение на практике |
||||
---|---|---|---|---|
Статья будет полезна фотографам и просто любителям изобразительного искусства, а также программистам в области графики. Со временем накапливается множество графических файлов, среди которых часто нужно найти, например, портреты. Распознавание образов - тема обширная и довольно сложная. Активное участие в ней принимают и нейросети, и различные статистические анализы. Алгоритм, о котором будет рассказано, лишь отдаленно можно назвать алгоритмом распознавания образов. Скорее, это алгоритм быстрого сканирования изображения с использованием нескольких критериев сравнения. В приведенный алгоритм встроен ряд простых базовых алгоритмов работы с данными: волновой алгоритм поиска пути, вычисление максимума величины, а также встроенные в Delphi и Pascal функции: инициализация генератора случайных чисел Randomize, получение квадратного корня sqrt, выделение компонент цвета GetRValue, GetGValue, GetBValue. Код алгоритма написан на Delphi 5, используются стандартные возможности без дополнительных модулей и компонентов. В совокупности алгоритм является авторским, но может использоваться программистами совершенно безвозмездно. Описание переменных и констант: const min_i = 1; max_i = 2; r_index = 1; // индексы для работы с массивом - маской g_index = 2; b_index = 3; max_arr_x = 2001; // максимальные размеры обрабатываемого изображения max_arr_y = 1701; var aPic : array[-1..max_arr_x, -1..max_arr_y] of byte; массив волны BitmapBig : TBitMap; - объект для хранения изображения rgb_value: array[1..3, 1..2] of byte; - маска критерия отбора пикселей по цвету i, j, rnd, x : integer; - вспомогательные переменные, счетчики циклов myColor : TColor; - храним текущий пиксель r_color, g_color, b_color : byte; - составляющие цвета текущего пикселя co1, co2 : integer; - нужны для следующей переменной my_percent : integer; - отношение всего изображения к выбранной части max_wave : integer; - максимальное значение волны img_x, img_y : integer; - размеры картинки r_sqrt : integer; - для определения квадратного корня от большей стороны Формальное описание алгоритма:
Шаг номер 1 - формируем критерии выбора точек Randomize; // включаем генератор случайных чисел. // вводим диапазоны на отбор цвета тела. // используя другие значения, можно настроиться на поиск, // например, синего неба или зеленого леса rgb_value[r_index, min_i] := 180; rgb_value[r_index, max_i] := 250; rgb_value[g_index, min_i] := 140; rgb_value[g_index, max_i] := 220; rgb_value[b_index, min_i] := 120; rgb_value[b_index, max_i] := 210; // инициализируем вспомогательные переменные img_x := BitmapBig.Width; img_y := BitmapBig.Height; if img_x < img_y then r_sqrt := round(abs(sqrt(img_y))) else r_sqrt := round(abs(sqrt(img_x))); co1 := img_x*img_y; co2 := 0; max_wave := 0; Шаг номер 2 - по маске зажигаем точки матрицы for i := 0 to img_x-1 do begin for j := 0 to img_y-1 do begin // берем цвет текущего пикселя myColor := BitmapBig.Canvas.pixels[i,j]; r_color := GetRValue(MyColor); g_color := GetGValue(MyColor); b_color := GetBValue(MyColor); x := (r_color+g_color+b_color) div 3; // средний серый цвет пикселя // сопоставляем значение цвета пикселя с некоторым условием // случайная величина нужна для простого усреднения результатов rnd := random(10)+1; if (r_color > (rgb_value[r_index, min_i]-rnd)) and (r_color < (rgb_value[r_index, max_i]+rnd)) and (g_color > (rgb_value[g_index, min_i]-rnd)) and (g_color < (rgb_value[g_index, max_i]+rnd)) and (b_color > (rgb_value[b_index, min_i]-rnd)) and (b_color < (rgb_value[b_index, max_i]+rnd)) and ( ((r_color < x-2) or (r_color > x+2)) and ((g_color < x-2) or (g_color > x+2)) and ((b_color < x-2) or (b_color > x+2)) ) and ( ((b_color < g_color-4) or (b_color > g_color+4)) ) then begin // этот пиксель подпадает под критерий отбора Inc(co2); aPic[i,j] := 1; end else begin // этот пиксель не попадает под критерий отбора aPic[i,j] := 0; end; end; my_percent := Round((co2/co1)*100); end; В результате массив aPic содержит "рисунок" искомого объекта. Шаг номер 3 - пускаем волну Оригинальный алгоритм ворлны отличается от используемого в нашем случае. Подробнее - после кода. for i := 0 to img_x-1 do begin for j := 0 to img_y-1 do begin x := aPic[i,j]; if x > 0 then begin if x >250 then x := 250; if aPic[i-1,j-1] = 1 then begin aPic[i-1,j-1] := x +1; if x > max_wave then max_wave := x+1; end; if aPic[i+1,j-1] = 1 then begin aPic[i+1,j-1] := x +1; if x > max_wave then max_wave := x+1; end; end; end; end; Это обычная волна идущая слева - направо, сверху - вниз. Но просматриваются не все восемь соседних пикселей, а лишь два: верхний левый и нижний левый. Чтобы было более понятно: это клавиши 7 и 1 по отношению к клавише 5 на цифровой клавиатуре. Такая форма выбрана из-за крайне большого брака при использовании других форм. 7** Дополнительно ко всему вычисляется максимальная величина волны, которая будет использоваться на завершающем этапе алгоритма - сравнении полученных данных с граничными условиями. Шаг номер 4 - анализируем собранные данные // my_percent - это некоторая величина отношения общего размера картинки // к выбранному изображению в ходе шага номер 2 if ((max_wave > my_percent) and (my_percent>7) and (max_wave>r_sqrt) ) or (my_percent>25) or ( (max_wave>r_sqrt) and (my_percent>6) ) then // ShowMessage ('Нашли искомое изображение'); else // ShowMessage ('Изображение не удовлетворяет критериям поиска'); Разумеется, алгоритм не оптимизирован, встречаются лишние переменные. Но в данной статье преследуется цель показать, как работать с массивом пикселей, а не оптимизации кода. Этот алгоритм можно оформить как функцию и встроить её вызов в процедуру сканирования каталогов. Таким образом, перед нами простой и быстрый инструмент поиска картинок на компьютере. Работающий пример алгоритма реализован в SP-Мониторе (ссылка ведет на страницу программы). Возможное развитие данного алгоритма распознавания образов - использование различных направлений волны:
с группировкой максимальных значений волн по каждому из направлений распространения волны, что позволит улучшить процент распознавания образов.
|