Namai > Tyrinėjimai > Objektų skaičiavimas paveiksliukuose

Objektų skaičiavimas paveiksliukuose

Ką gi, šiuo įrašu startuoju naujos nišos gyvavimą. Abejoju ar tokia Lietuvoje jau yra, net netikrinau kol kas, bet bus įdomu paieškoti. Neskubėsiu klijuoti etiketės apie ką bloginsiu, tegu tai paaiškėja po truputi, su laiku. „Tyrinėjimai. Kūryba. Eksperimentai.“ yra labai taiklus apibūdinimas, tegu taip ir lieka.

Išbandysime vieną labai paprastą idėją, kurios pagalba galima skaičiuoti objektus paveiksliukuose (objects counting in binary pictures). Paimkime binarinį paveiksliuką, kuriame yra 7 objektai.

Vaizdas gerokai išdidintas, kad bloge objektai matytųsi aiškiai, kiekvienas objekto pikselis matomas kaip maždaug 14×14 pikselių dydžio juoda sritis. Kaip šiuos juodus objektus suskaičiuoti programiškai? Galime pasitelkti vieną įdomią savybę, kad skirtumas tarp išorinių objekto kampų ir vidinių visada yra 4. Kad būtų lengviau įsivaizduoti, nuspalvokime objektus pilkai iš pažymėkime išorinius kampus raudonai, o vidinius mėlynai.

Pavyzdžiui pirmas objektas turi keturis išorinius kampus ir nulį vidinių. Antras objektas 8 išorinius ir 4 vidinius. Trečias objektas 9 išorinius ir 5 vidinius. Vizualiai išorinis kampas matomas kaip juodas (šiuo atveju pilkas), o vidinis kaip baltas. Tuomet suskaičiavus visus paveiksliuke esančius išorinius kampus ir vidinius, o jų skirtumą padalinus iš 4, turėtume gauti objektų skaičių. Konkrečiai šiame paveiksliuke būtų (39-11)/4=28/4=7. Iš viso septyni objektai.

Algoritmas gana paprastas. Pradžioje paveiksliukas paverčiamas į binarinį, kad būtų tik dvi intensyvumo reikšmės, arba 0 (juoda) arba 1 (balta). Tada pereinami visi taškai paeiliui tikrinant kokia kiekvieno taško srityje yra 2×2 matrica. Jei tarkim [0 1;1 1], [1 0; 1 1], [1 1; 0 1] arba [1 1; 1 0] (visais atvejais elementų suma yra 3), tuomet tai yra išorinis kampas. Jei [1 0; 0 0], [0 1; 0 0], [0 0; 1 0] arba [0 0; 0 1] (visais atvejais elementų suma 1), tuomet tai yra vidinis kampas.

Selec All Code:
1
2
3
4
5
6
7
8
clc;
close all;
file = 'D:\holes.bmp';
rgb = imread(file);
image(rgb); % patikriname kaip atrodo pradinis vaizdas
BW = im2bw(rgb, 0); % domina binarinis vaizdas
[objects, E, I] = count_objects(BW);
fprintf('Iš viso objektų: %d, E: %d, I: %d\n', objects, E, I);

Objektų skaičiavimo funkcija:

Selec All Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function [result, E, I] = count_objects(BW)
[MaxRow, MaxCol] = size(BW);
E = 0; % išoriniai kampai
I = 0; % vidiniai kampai
for L = 1 : MaxRow - 1
  for P = 1 : MaxCol - 1
    M = BW(L : L + 1, P : P + 1);
    S = sum(M(:));
    if S == 3
      E = E + 1;
    end;
    if S == 1
      I = I + 1;
    end;
  end;
end;
result = (E - I) / 4;

Paimkime vizualiai gerokai sudėtingesnius atvejus:

Programa gauna 9 objektus. Tiek jų ir yra. Nors objektai yra sudėtingi, bet mažai siejasi su realiu gyvenimu, todėl pabandykime paimti ką nors tikro, pavyzdžiui štai tokį vaizdą:

Vaizdas yra spalvotas ir iš realaus gyvenimo. Kaip suskaičiuoti šiuos objektus? Lygiai taip pat, tik pradžiai padidiname šviesumą ir ryškumą, kad atmesti šviesesnes sritis ir konvertuojame į binarinį paveiksliuką:

Kodas keičiasi nežymiai:

Selec All Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
clc;
close all;
file = 'D:\FROG BLOOD 402.jpg';
rgb = imread(file);
rgb = imadjust(rgb, [0 0.4], [0.6 1]);
image(rgb); % patikriname kaip atrodo pradinis vaizdas
BW = im2bw(rgb, 0.9); % domina binarinis vaizdas
[m, n] = size(BW);
N = ones(m + 2, n + 2);
N(2 : m + 1, 2 : n + 1) = BW;
imshow(N);
[objects, E, I] = count_objects(N);
fprintf('Iš viso objektų: %d, E: %d, I: %d\n', objects, E, I);

O rezultatas yra: „Iš viso objektų: 59, E: 1287, I: 1051“. Viso 59 objektai, jų skaičiuoti rankomis jau visai nesinorėtų.

Tiesa, algoritmas neveiks tais atvejais, jei skaičiuojamuose objektuose yra fono spalvos arba objektas nėra apsuptas fono spalva (dėl to paskutinis paveiksliukas padidintas į visas puses per vieną pikselį taip išplečiant baltą foną), todėl algoritmas netobulas, tačiau labai paprastas ir įdomus.

Tyrinėjimai , ,

  1. 2011-09-25 15:19 | #1

    Esu naudojusi ląstelių branduolius kaip objektus skaičiuojančią programą histologiniams preparatams tirti studijų pratybų metu.
    Patikimumas visai neblogas, bet tik tuo atveju, jei pavyksta gerai nusidažyti ląsteles ir neprikrenta kokių pleiskanų :D

    Bet ar galima padaryti taip, kad programa atpažintų pasikartojančių objektų formą ir taip nurodytų persidengiančius objektus? (pvz.: tų ląstelių atveju rastų sulipusius vieną ant kito branduolius arba net įvertintų ar tai dvi ląstelės, ar dvibranduolė ląstelė?)

  2. TakeON
    2011-09-25 21:13 | #2

    Būtų įdomu pamatyti pavyzdį. Tada būtų aišku kaip ląstelės atrodo ir koks yra fonas. Gal ir pabandyčiau tą padaryt kada (gal ir ne, priklausys nuo sudėtingumo ir turimo laiko), jei kur nors įkeltum pavyzdį :)
    Bet atsakymas gana paprastas: suskaičiuoti nedideliu tikslumu tikrai galima. Norint aukšto tikslumo, ypač jei yra triukšmų (pleiskanos ir kt.), jau gali tekti nemažai pasistengti.

  1. 2011-09-29 iš 12:11 | #1