czwartek, 22 stycznia 2009

Nanoszenie wyników detekcji na obraz źródłowy w CImg

W wyniku segmentacji obrazu otrzymujemy obiekt lub grupę obiektów, które spełniają zadane przez nas kryteria. Dla przykładu, poniżej możemy zobaczyć przekrój mózgu oraz wynik detekcji substancji białej z wykorzystaniem algorytmu Connected Threshold z biblioteki Insight Toolkit. Wydaje się, że całkiem nieźle poszło. Jednak patrzac na te dwa obrazy osobno trudno wizualinie ocenić czy czegoś nie zgubliliśmy lub czy gdzieś nie jest za dużo. Na pewno łatwiej by było po naniesieniu wyniku na obraz źródłowy. O tym właśnie będzie ten wpis.


Korzystając z biblioteki CImg pokażę jak napisać własną funkcję oraz program przydatny w takich sytuacjach.

Podejście pierwsze
Najłatwiej można to oczywiście zrobić iterując po obu obrazach i jeśli w danym punkcie obraz wynikowy ma wartość 255 (biały kolor) to na obrazie źródłowym w tym samym miejscu zmieniamy kolor na inny, wcześniej ustalony. Poniższa funkcja działa właśnie w taki sposób.

template<typename T>
void cimg_nanies_wyniki(CImg<T> &image, CImg<T> &result, unsigned char* color)
{
cimg_forXY(image,x,y) {
if (result(x,y) == 255) {
image(x,y,0) = color[0];
image(x,y,1) = color[1];
image(x,y,2) = color[2];
}
}
}


Patrząc na obraz wynikowy, który powstanie w wyniku wykonania tej funkcji, wydaje się, że mamy to czego potrzebowaliśmy. Jest jednak pewien problem. Pokolorowany obszar przysłania to co jest pod nim i nie widzimy, czy gdzieś nie znajduje się obiekt, który nie należy do poszukiwanego obszaru. Najlepiej w takim wypadku zastosować przeźroczystość podczas kolorowania.




Podejście drugie
Zastosowanie przeźroczystości w CImg wymaga kilku dodatkowych zabiegów aniżeli miało to miejsce w poprzednim przykładzie. Najpierw przygotujemy dodatkowy obraz typy float, który wypełnimy wartością 1.0. Następnie zmienimy wszystkie punkty zgodnie z maską, którą tutaj jest obraz z detekcją. Później ten obraz jest nanoszony na obraz początkowy z użyciem funkcji draw_image, która pozwala na ustalenie przeźroczystości.

template<typename T>
void cimg_nanies_wyniki2(CImg<T> &image, CImg<T> &mask, unsigned char* color, float transp)
{
CImg<T> layer_c = mask;

layer_c.draw_rectangle(0, 0, layer_c.dimx(), layer_c.dimy(), color, 1.0);

CImg<T> layer_f1 = mask;
cimg_forXY(layer_f1,x,y)
layer_f1(x,y) = (layer_f1(x,y,0)==255 && layer_f1(x,y,1)==255 && layer_f1(x,y,2)==255)?0.0f:1.0f;
CImg<T> layer_f2=layer_f1.get_shared_channel(0);

image.draw_image(layer_c,layer_f2,0,0,0,0,1.0f,transp);
}
Po wywołaniu tej funkcji otrzymujemy obraz wejściowy z naniesionym wynikiem detekcji. Teraz już znacznie łatwiej ocenić, czy zastosowany przez nas algorytm segmentacji zadziałał poprawnie.



Przykładowa funkcja main
Dodatkowo została zaprezentowana funkcja main() odbierająca parametry z wiersza poleceń i wywołująca funkcję cimg_nanies_wyniki2(). Po jej skompilowaniu otrzymamy gotowy program, który może być wielokrotnie używany, a nawet dodawany do istniejących skryptów w celu prezentacji wyników.

#include <iostream>
#include <ostream>
#include "../CImg.h"

using namespace std;
using namespace cimg_library;

unsigned char white[3]={255,255,255},
black[3] = {0,0,0},
red[3] = {255,0,0},
green[3] = {0,255,0},
blue[3] = {0,0,255},
yellow[3] = {255,255,0},
magenta[3] = {255,0,255},
orange[3] = {255,90,0},
middle[3] = {127,127,127}
;

//Tutaj powinna być funkcja cimg_nanies_wyniki2

int main(int argc,char **argv)
{
cimg_usage("Nanies wyniki");

const char* file_i = cimg_option("-i","input.bmp","Input image");
const char* file_o = cimg_option("-o","output.bmp","Output image");
const char* file_m = cimg_option("-m","mask.bmp","Mask image");
const char col = cimg_option("-c",'r',"Color (r-red,g-green,b-blue,y-yellow,m-magenta,o-orange)");
float transp = cimg_option("-t",0.2f,"Transparency");

unsigned char* color=red;
switch (col) {
case 'r': color = red; break;
case 'g': color = green; break;
case 'b': color = blue; break;
case 'y': color = yellow; break;
case 'm': color = magenta;break;
case 'o': color = orange; break;
default: color = red;
}

CImg<unsigned char> image_in(file_i), mask_in(file_m);
mask_in.normalize(255,0);

cimg_nanies_wyniki2(image_in,mask_in,color,transp);
image_in.save(file_o);

return 0;
}


Przykład wywołania:
program -i input.bmp -m mask.bmp -o output.bmp -t 0.15 -c o

0 komentarze:

Prześlij komentarz