poniedziałek, 8 czerwca 2009

Inpainting


Czasami, z różnych powodów, na obrazie pojawiają się wady, które możemy łatwo dostrzec. Wady takie, mogą przyczynić się do pogorszenia wyników (np. wykrycie nadmiarowych krawędzi). W OpenCV możemy takie wady usunąć (musimy jednak je określić...). Za wszystko odpowiedzialna jest funkcja cvInpaint.
void cvInpaint( const CvArr* src, const CvArr* inpaint_mask, CvArr* dst, double inpaintRange, int flags );

Obrazy wejsciowy i źródłowy muszą być tego samego typu i rozmiaru. Maska musi posiadać ten sam rozmiar co obraz, ponadto musi posiadać 8-bitową głębię i 1 kanał. inpaintRange określa w jakim promień obszaru przetwarzania dla danego piksela. Za duży może powodować uwzględnianie pikseli dosyć odległych i dla małych wad powodować rozmywanie obrazu. Flaga oznacza wybór metody. Są dwie do wyboru: CV_INPAINT_NS oraz CV_INPAINT_TELEA.

Poniższe obrazy przedstawiają obraz oryginalny, a dalej obrazy z wadą oraz obrazy o po naprawianiu i różnica pomiędzy obrazem oryginalnym i naprawionym. Jak będzie można zauważyć, dla małej wady wynik jest zadowalający. Dla większych, już nie jest tak dobrze. Niemniej, może być to pomocne, gdy chcemy usunać wadę wpływającą niekorzystnie na wynik programu.

Obraz oryginalny

Obraz z cienką krzywą
Obraz oryginalny

Po naprawie

Różnica


Obraz z grubą krzywą
Obraz oryginalny

Po naprawie

Różnica


Obraz z półprzezroczystą plamą
Obraz oryginalny

Po naprawie

Różnica


Przykład wykorzystania. Jest to program z poprzedniego wpisu (o myszce), tym razem rysujący większe punkty (okresla to zmienna promien). Po naciśnięciu klawisza "i", w miejscach zaznaczonych myszką, wykonany zostanie inpaintig. Z linii poleceń należy przekazać ścieżkę do pliku z obrazem.
bool wcisniety = false;
CvScalar kolor;
char* nazwa = "Rysowanie";
IplImage* maska; // maska okreslajaca piksele do zmiany
double promien = 3.0; // promien rysowanych kolek

void obsluga_myszki(int e, int x, int y, int fl, void* par)
{
IplImage * obraz = (IplImage*) par;

// zmiany zapisujemy na obrazie i w masce
switch (e)
{
case CV_EVENT_LBUTTONDOWN:
cvCircle(obraz, cvPoint(x, y), promien, kolor, -1);
cvCircle(maska, cvPoint(x, y), promien, kolor, -1);
wcisniety = true;
break;
case CV_EVENT_LBUTTONUP:
wcisniety = false;
break;
case CV_EVENT_MOUSEMOVE:
if (wcisniety)
{
cvCircle(obraz, cvPoint(x, y), promien, kolor, -1);
cvCircle(maska, cvPoint(x, y), promien, kolor, -1);
}
break;
}
}

void inpaint(IplImage * obraz)
{
IplImage* naprawiony = cvCreateImage(cvGetSize(obraz), obraz->depth, obraz->nChannels);

// funkcja naprawiajaca obraz
cvInpaint(obraz, maska, naprawiony, 3, CV_INPAINT_TELEA);

cvReleaseImage(&obraz);
obraz = cvCloneImage(naprawiony);
cvReleaseImage(&naprawiony);
}

void program_gl(char * sciezka)
{
cvNamedWindow(nazwa, CV_WINDOW_AUTOSIZE);
IplImage* wys = cvLoadImage(sciezka, CV_LOAD_IMAGE_ANYCOLOR);
// maska zawsze musi byc 8-bitowa i 1-kanalowa
maska = cvCreateImage(cvGetSize(wys), 8, 1);
cvZero(maska);
kolor = cvScalarAll(1.0);
cvSetMouseCallback(nazwa, obsluga_myszki, wys);

while (true)
{
cvShowImage(nazwa, wys);
int key = cvWaitKey(10);
if (key == 'k')
break;
if (key == 'i')
{
inpaint(wys);
cvZero(maska);
}
}

cvReleaseImage(&wys);
cvReleaseImage(&maska);
cvDestroyWindow(nazwa);

}

/*
* Inpainting
* autor: ratixu.blogspot.com
*/
int main(int argc, char** argv)
{
program_gl(argv[1]);
return (EXIT_SUCCESS);
}

wtorek, 2 czerwca 2009

Mysz w OpenCV


Kolejny post niezwiązany stricte z wizją komputerową, ale opisujący przydatną w pracy nad programem/algorytmem funkcjonalność. W OpenCV brakuje zaawansowanych elementów GUI, biblioteka ma inny cel. Jednak interakcja pozwala na znaczne przyspieszenie testowania programu. OpenCV udostępnia kilka podstawowych operacji w części zwanej HighGUI (związany z nią jest plik highgui.h). Jedną z nich jest tworzenie okien. Dzisiaj opiszę inną: obsługę myszy.

Obsługa myszki rozwiązana jest czymś na wzór "callbacku". Aby jej użyć musimy napisać funkcję o określonym nagłówku (ważna jest tylko kolejność i typ parametrów):
void obsluga_myszki(int zdarzenie, int x, int y, int flagi, void* parametry);

Proste jej użycie pokzauje poniższy przykład:
// czy przycisk jest wcisniety
bool wcisniety = false;
// kolor ktorym rysujemy
CvScalar kolor;
// nazwa okna
char* nazwa = "Rysowanie";

void obsluga_myszki(int e, int x, int y, int fl, void* par)
{
// rzutujemy parametr na wskaznik na obraz
IplImage * obraz = (IplImage*) par;

switch (e)
{
case CV_EVENT_LBUTTONDOWN:
cvSet2D(obraz, y, x, kolor);
wcisniety = true;
break;
case CV_EVENT_LBUTTONUP:
wcisniety = false;
break;
case CV_EVENT_MOUSEMOVE:
if (wcisniety)
{
cvSet2D(obraz, y, x, kolor);
}
break;
}
}

void program_gl()
{

// tworzymy okno
cvNamedWindow(nazwa, CV_WINDOW_AUTOSIZE);

// wyswietlany obraz
IplImage* wys = cvCreateImage(cvSize(500, 500), 8, 3);
cvZero(wys);

// ustawiamy funkcje obslugi myszy
// kolejno podajemy nazwe okna, nazwe funkcji obslugi
// nasze dane (jako wskaznik), ktore otrzymamy w funkcji
// obslugi w parametrze void* par
cvSetMouseCallback(nazwa,obsluga_myszki,wys);

while(true)
{

cvShowImage(nazwa,wys);

if(cvWaitKey(10) == 'k')
break;
}

cvReleaseImage(&wys);
cvDestroyWindow(nazwa);

}

/*
* Rysowanie
* autor: ratixu.blogspot.com
*/
int main(int argc, char** argv)
{
kolor = cvScalarAll(255.0);
program_gl();
return (EXIT_SUCCESS);
}

Po uruchomieniu możemy rysować białym kolorem na czarnym tle.

Oczywiście zastosowań jest tyle, ile wyobraźnia podpowie :)