Перейти к содержимому
Compvision.ru
Vicul

Separable kernels

Recommended Posts

Всем привет,

изучаю пакет OpenCV по книге О'Релли "OpenCV..." и не могу сделать одно упражнение

*****************

Separable kernels. Create a 3-by-3 Gaussian kernel using rows [(1/16, 2/16, 1/16), (2/16, 4/16, 2/16), (1/16, 2/16, 1/16)] and with anchor point in the middle.

a. Run this kernel on an image and display the results.

b. Now create two one-dimensional kernels with anchors in the center: one going “across” (1/4, 2/4, 1/4), and one going down (1/4, 2/4, 1/4). Load the same original image and use cvFilter2D() to convolve the image twice, once with the first 1D kernel and once with the second 1D kernel. Describe the results.

************************

я сделал три этих фильтра, но они не меняют исходное изображение, уже сижу третий день не могу найти где ошибка.

Вот мой код

		IplImage* src = cvLoadImage("4.jpg");

cvNamedWindow("src", 1);

cvShowImage("src", src);

IplImage* rgb[3];

float L45[]={

1./16., 2./16., 1./16.,

2./16., 4./16., 2./16.,

1./16., 2./16., 1./16.};//

CvMat* rgbMat = cvCreateMat(3, 3, CV_32FC1);

for (int y = 0; y < 3; y++)

{

for (int x = 0; x < 3; x++)

cvmSet(rgbMat, y, x, L45[y*3 + x]);

}

IplImage* dst = cvCreateImage(cvSize(src->width, src->height), src->depth, 3);

IplImage* dstRGB[3];

for (int i = 0; i < 3; i++)

{

rgb = cvCreateImage(cvSize(src->width, src->height), src->depth, 1);

dstRGB = cvCreateImage(cvSize(src->width, src->height), src->depth, 1);

}

cvSplit(src, rgb[0], rgb[1], rgb[2], NULL);

for (int i = 0; i < 3; i++)

{

cvFilter2D(rgb, dstRGB, rgbMat);

}

cvReleaseMat(&rgbMat);

cvMerge(dstRGB[0], dstRGB[1], dstRGB[2], NULL, dst);

cvNamedWindow("dst", 1);

cvShowImage("dst", dst);

//across

float D[] = {1./4., 2./4., 1./4.};

rgbMat = cvCreateMat(1, 3, CV_32FC1);

for (int x = 0; x < 3; x++)

cvmSet(rgbMat, 0, x, D[x]);

for (int i = 0; i < 3; i++)

{

cvZero(dstRGB);

cvFilter2D(rgb, dstRGB, rgbMat, cvPoint(1, 0));

}

cvReleaseMat(&rgbMat);

cvZero(dst);

cvMerge(dstRGB[0], dstRGB[1], dstRGB[2], NULL, dst);

cvNamedWindow("Across", 1);

cvShowImage("Across", dst);

//down

rgbMat = cvCreateMat(3, 1, CV_32FC1);

for (int y = 0; y < 3; y++)

cvmSet(rgbMat, y, 0, D[y]);

for (int i = 0; i < 3; i++)

{

cvZero(dstRGB);

cvFilter2D(rgb, dstRGB, rgbMat, cvPoint(0, 1));

}

cvReleaseMat(&rgbMat);

cvZero(dst);

cvMerge(dstRGB[0], dstRGB[1], dstRGB[2], NULL, dst);

cvNamedWindow("Down", 1);

cvShowImage("Down", dst);

cvReleaseImage(&dst);

for (int i = 0; i < 3; i++)

{

cvReleaseImage(&rgb);

cvReleaseImage(&dstRGB);

}

cvWaitKey(0);

cvReleaseImage(&src);

cvDestroyWindow("src");

cvDestroyWindow("dst");

cvDestroyWindow("Across");

cvDestroyWindow("Down");

Буду благодарен за любую идею в этом вопросе.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Вот проект вычисления скелета изображения (тема есть на форуме), там как раз свертка применяется и все работает, посмотрите, если будут вопросы, задавайте: http://www.compvision.ru/forum/index.php?a...=post&id=55

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Вот проект вычисления скелета изображения (тема есть на форуме

Спасибо за инфу, помоему это единственный форум, где я нашел единомышленников.

С градусными коэффициентами с Вашего проекта у меня все работает (в книге это предыдущее задание).

У меня большие сомнения в моих исходных коэф-тах - [(1/16, 2/16, 1/16), (2/16, 4/16, 2/16), (1/16, 2/16, 1/16)] и

(1/4, 2/4, 1/4). Я их тупо впихиваю в матрицу. Интуиция мне подсказывает здесь необходима дополнительная

обработка, ведь не зря они написали "Separable kernels".

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Спасибо за инфу, помоему это единственный форум, где я нашел единомышленников.

С градусными коэффициентами с Вашего проекта у меня все работает (в книге это предыдущее задание).

У меня большие сомнения в моих исходных коэф-тах - [(1/16, 2/16, 1/16), (2/16, 4/16, 2/16), (1/16, 2/16, 1/16)] и

(1/4, 2/4, 1/4). Я их тупо впихиваю в матрицу. Интуиция мне подсказывает здесь необходима дополнительная

обработка, ведь не зря они написали "Separable kernels".

Вот здесь статейка о разделяемых ядрах. Насколько я понял, разделяемым называется двумерное ядро свертки, которое можно представить в виде матричного произведения одномерных ядер.

Из этого следует, что применение двумерного ядра эквивалентно последовательному применению к изображению одномерных ядер, являющихся множителями на которые раскладывается исходная матрица.

То есть, я предполагаю (считать лень), что квадратная матрица [(1/16, 2/16, 1/16), (2/16, 4/16, 2/16), (1/16, 2/16, 1/16)], есть матричное произведение двух одномерных матриц строки (1/4, 2/4, 1/4) и столбца (1/4, 2/4, 1/4). И результат после применения 2Д ядра свертки, и после последовательного применения 1Д ядер свертки результат должен быть одинаковый.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Линк у меня не работает, можно повторить.

Вот:

http://blogs.mathworks.com/steve/2006/10/0...le-convolution/

И сверху поправил.

Кстати, ядро из примера, это размытие, его действие сложно заметить. Я переделал на оператор Собеля все работает.

У меня посл. свертка работает (собель из статьи выше):

//---------------------------------------------------------------------------

void ProcessFrame( IplImage* src )

{

IplImage* rgb[3];

CvMat* rgbMat;

IplImage* dst = cvCreateImage(cvSize(src->width, src->height), src->depth, 3);

IplImage* dstRGB[3];

for (int i = 0; i < 3; i++)

{

rgb = cvCreateImage(cvSize(src->width, src->height), src->depth, 1);

dstRGB = cvCreateImage(cvSize(src->width, src->height), src->depth, 1);

}

cvSplit(src, rgb[0], rgb[1], rgb[2], NULL);

//across

float D[] = {1, 2, 1}; // Первая часть ядра

rgbMat = cvCreateMat(1, 3, CV_32FC1);

for (int x = 0; x < 3; x++)

cvmSet(rgbMat, 0, x, D[x]);

for ( i = 0; i < 3; i++)

{

cvZero(dstRGB);

cvFilter2D(rgb, dstRGB, rgbMat, cvPoint(1, 0));

}

cvReleaseMat(&rgbMat);

cvZero(dst);

cvMerge(dstRGB[0], dstRGB[1], dstRGB[2], NULL, dst);

//down

rgbMat = cvCreateMat(3, 1, CV_32FC1);

D[0]=-1; // Вторая часть ядра

D[1]=0;

D[2]=1;

for (int y = 0; y < 3; y++)

cvmSet(rgbMat, y, 0, D[y]);

for ( i = 0; i < 3; i++)

{

// cvZero(dstRGB);

cvFilter2D(dstRGB, dstRGB, rgbMat, cvPoint(0, 1)); // и здесь поправил (чтобы фильтры последовательно применялись)

}

cvReleaseMat(&rgbMat);

cvZero(dst);

cvMerge(dstRGB[0], dstRGB[1], dstRGB[2], NULL, dst);

for ( i = 0; i < 3; i++)

{

cvReleaseImage(&rgb);

cvReleaseImage(&dstRGB);

}

APIDrawIpl(10,10,src,Form1->Handle);

APIDrawIpl(400,10,dst,Form1->Handle);

cvReleaseImage(&dst);

}

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Спасибо за линк, теперь более менее понятно

Вот:

Кстати Тут по моему нестыковочка:

		for (int x = 0; x < 3; x++)

cvmSet(rgbMat, 0, x, D[x]); // здесь 0,x

for (int i = 0; i < 3; i++)

{

cvZero(dstRGB);

cvFilter2D(rgb, dstRGB, rgbMat, cvPoint(1, 0)); // а якорь здесь cvPoint(1, 0)

}

Помоему здесь все в норьме. cvmSet() берет вторым параметром ряды y (у нас их 1, нулевой)и три значения столбцов x. Ну а якорь идет по определению CvPoint(int x, int y), т.е (1,0) указывает на центр . В принципе его можно не указывать, оставить по умолчанию, это я уже потом его прилепил для успокоения совести.

Ладно, вопрос остается, почему все эти три фильтра не меняют картинку? Т.е,

1. Пропускаем через cvFilter2D(src, ... ) матрицу [(1/16, 2/16, 1/16), (2/16, 4/16, 2/16), (1/16, 2/16, 1/16)]. Допустим эта матрица ничего не меняет.

2. Тогда используем через cvFilter2D(src, ... ) одноядерную матрицу по горизонтале (1/4, 2/4, 1/4). Должно же что-то поменяться?

3. А вот теперь если пропустить через полученный результат вертикальную матрицу мы должны получить результат для п.1., ведь если перемножить две одноядеорные матрицы, то мы получим первый фильтр.

Резюмирую. Хоть в одном из трех случаев cvFilter2D() должен был изменить изображения. У меня все одиноковое.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

> float D[] = {1, 2, 1};

Да если поставить эти коэф-ты, то будет что-то меняться, но у меня они дробные.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
> float D[] = {1, 2, 1};

Да если поставить эти коэф-ты, то будет что-то меняться, но у меня они дробные.

На всякий случай перевел все на float.

//---------------------------------------------------------------------------

void ProcessFrame( IplImage* img )

{

IplImage* rgb[3];

CvMat* rgbMat;

IplImage* dst = cvCreateImage(cvSize(img->width, img->height), IPL_DEPTH_32F, 3);

IplImage* src = cvCreateImage(cvSize(img->width, img->height), IPL_DEPTH_32F, 3);

cvConvert(img,src);

IplImage* dstRGB[3];

for (int i = 0; i < 3; i++)

{

rgb = cvCreateImage(cvSize(src->width, src->height), IPL_DEPTH_32F, 1);

dstRGB = cvCreateImage(cvSize(src->width, src->height), IPL_DEPTH_32F, 1);

}

cvSplit(src, rgb[0], rgb[1], rgb[2], NULL);

//across

float D[] = {0.25, 0.5, 0.25};

rgbMat = cvCreateMat(1, 3, CV_32FC1);

for (int x = 0; x < 3; x++)

cvmSet(rgbMat, 0, x, D[x]);

for ( i = 0; i < 3; i++)

{

cvZero(dstRGB);

cvFilter2D(rgb, dstRGB, rgbMat);

}

cvReleaseMat(&rgbMat);

//down

rgbMat = cvCreateMat(3, 1, CV_32FC1);

cvZero(dst);

cvMerge(dstRGB[0], dstRGB[1], dstRGB[2], NULL, dst);

for (int y = 0; y < 3; y++)

cvmSet(rgbMat, y, 0, D[y]);

for ( i = 0; i < 3; i++)

{

// cvZero(dstRGB);

cvFilter2D(dstRGB, dstRGB, rgbMat, cvPoint(0, 1)); // è çäåñü ïîïðàâèë (÷òîáû ôèëüòðû ïîñëåäîâàòåëüíî ïðèìåíÿëèñü)

}

cvReleaseMat(&rgbMat);

cvZero(dst);

cvMerge(dstRGB[0], dstRGB[1], dstRGB[2], NULL, dst);

//cvConvertScale( dst, dst,25000,0);

APIDrawIpl(10,10,src,Form1->Handle);

APIDrawIpl(400,10,dst,Form1->Handle);

cvZero(dst);

for ( i = 0; i < 3; i++)

{

cvReleaseImage(&rgb);

cvReleaseImage(&dstRGB);

}

cvReleaseImage(&src);

cvReleaseImage(&dst);

}

Вообще-то разница (правое немного размыто) есть:

Filter2D.png

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах
Вообще-то разница (правое немного размыто) есть:

Хрен его знает, избражение почти не меняется, я пытался сравнивать данные в матрицах изображений, вначале все одинаково. Далее идти - можно "резьбу сорвать". Думаю коэф-ты ядер слишком маленькие, чтобы визуально что-то определить. В принципе идея понятна, вопрос закрыт, спасибо за помощь.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Создайте учётную запись или войдите для комментирования

Вы должны быть пользователем, чтобы оставить комментарий

Создать учётную запись

Зарегистрируйтесь для создания учётной записи. Это просто!

Зарегистрировать учётную запись

Войти

Уже зарегистрированы? Войдите здесь.

Войти сейчас


  • Сейчас на странице   0 пользователей

    Нет пользователей, просматривающих эту страницу

×