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);
}

3 komentarze:

Anonimowy pisze...

Witam

Jak można wyświetlić obraz z kamery w PictureBox w Visual C++ ?

Prosze o rade

Anonimowy pisze...

Hej,
nie wiem jak inaczej się z Tobą skontaktować jak tylko przez ten komentarz.

Chciałbym skonsulować kwestię rozpoznawania punktów świecących przez opencv.

Jeżeli masz chwilę to odezwij się na mail: thre@o2.pl

dzięki
pozdrawiam

Łukasz pisze...

Poza blogiem to ratixu@gmail.com

Maila staram się przeglądać codziennie, ale nie zawsze mi się to udaje.

Pozdrawiam :)