Objektų žymėjimas
Objektų žymėjimas (connected components labeling, objects labeling) yra atliekamas visus objektus vieną nuo kito išskiriant, pavyzdžiui nudažant skirtinga spalva arba priklijuojant etiketę (label). Išbandysim abu šiuos variantus.
Paimkim binarinį paveiksliuką:
Algoritmas (recursive labeling):
- skenuojamas visas paveiksliukas ieškant juodos spalvos ir jeigu tokia rasta – nuspalvosime išskirtine intensyvumo spalva (pilku atspalviu);
- sudaromas rasto taško kaimynų sąrašas ir pas kiekvieną jo kaimyną apsilankoma, nudažant juos visus vienodu intensyvumu. Lankyti kaimynus galima su rekursija, tuomet visi objekto taškai bus tikrai apeiti ir pažymėti;
- ieškomas naujas objektas.
Programos kodas žemiau:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | tic; clc; close all; file = 'D:\objektai.bmp'; rgb = imread(file); image(rgb); global I; I = rgb2gray(rgb); label = 0; labelDelta = 20; [MaxRow, MaxCol] = size(I); % set(0,'RecursionLimit',1500); didesniems objektams gali reikėti didinti % rekursijų kiekio limitą for L = 1 : MaxRow for P = 1 : MaxCol if I(L, P) == 0 % aptiktas objektas label = label + labelDelta; % kiekvienam objektui kitoks intensyvumas search(label, L, P); % nuspalvoti visus objekto pikselius vienodu intensyvumu end; end; end; imshow(I); disp(toc); |
Rekursija apeinanti visus kaimynus:
1 2 3 4 5 6 7 8 9 10 11 12 | function [] = search(label, L, P) global I; I(L, P) = label; % keičiamas pikselio intensyvumas [Nset] = neighbors(I, L, P); % randami 4 pikselio kaimynai s = size(Nset); n = s(3); for i = 1 : n % kiekvienas kaimynas tikrinamas atskirai value = Nset(:, :, i); if value(3) == 0 search(label, value(1), value(2)); end; end; |
Galima rasti ir 8 ir 4 kaimynus. Šiuo atveju randami tik keturi:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | function [res] = neighbors(I, L, P) [MaxRow, MaxCol] = size(I); res = []; cur = -1; if L > 1 % viršutinis kaimynas cur = cur + 1; res(:, :, cur + 1) = int16([L - 1 P int16(I(L - 1, P))]); end; if L < MaxRow % apatinis kaimynas cur = cur + 1; res(:, :, cur + 1) = int16([L + 1 P int16(I(L + 1, P))]); end; if P > 1 % kairysis kaimynas cur = cur + 1; res(:, :, cur + 1) = int16([L P - 1 int16(I(L, P - 1))]); end; if P < MaxCol % dešinysis kaimynas cur = cur + 1; res(:, :, cur + 1) = int16([L P + 1 int16(I(L, P + 1))]); end; |
Apdorojus pirmąjį paveiksliuką:
Algoritmas bėga per visus pikselius nuo viršaus apačion ir nuo kairės dešinėn, todėl pirmiausia aptinkamas trečias objektas ir po to visi kiti. Rezultate matosi kaip kiekvieno objekto intensyvumas skiriasi.
Pabandom lygiai tą patį padaryti su paveiksliuku, kurį naudojom skaičiuojant objektus, tik intensyvumo pokytį pakeičiam į 4, nes objektų gerokai daugiau ir reiktų, kad visi sutilptų į 255 reikšmes:
Labiausiai skiriasi vienas nuo kito objektai, kurie buvo pažymėti pirmiausiai ir paskiausiai. Tokį paveikslą gali būti sunku naudoti, nes nėra kaip pasakyti apie kurias ląsteles norima diskutuoti, juk nesakysi, kad „ląstelė, kurios intensyvumas 74 % …“, todėl geriausia, jei kiekvienam objektui suteiksim identifikatorius. Kodas žemiau (funkcijos nekeistos):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | tic; clc; close all; file = 'D:\FROG BLOOD binary.bmp'; rgb = imread(file); file2 = 'D:\FROG BLOOD 402 rgb.bmp'; rgb2 = imread(file2); imshow(rgb2); global I; I = rgb2gray(rgb); label = 0; labelDelta = 4; [MaxRow, MaxCol] = size(I); % set(0,'RecursionLimit',1500); didesniems objektams gali reikėti didinti % rekursijų kiekio limitą for L = 1 : MaxRow for P = 1 : MaxCol if I(L, P) == 0 % aptiktas objektas label = label + labelDelta; % kiekvienam objektui kitoks intensyvumas search(label, L, P); % nuspalvoti visus objekto pikselius vienodu intensyvumu text('units','pixels','position',[P MaxRow-L],'fontsize',7,'string',num2str(label/labelDelta),'BackgroundColor',[0.9 0.9 0.9]) end; end; end; % imshow(I); disp(toc); |
Rezultatas:
Visi 59 objektai pažymėti.
Šio algoritmo didžiausias trūkumas, kad netinka dideliems objektams, nes tada reikia didinti rekursijų kiekio limitą. O ir padidinus ne visada to pakanka, nes viršijus Matlab galimybes, jis lūžta. Tačiau šiai problemai spręsti yra ir daugiau algoritmų: “row-by-row labeling”, naudojant “union-find structure” arba “run-length encoding” ir kt.







