2012-04-25 2 views
4

Есть ли какая-либо прямая opencv-функция для функции matlab conv2? Я попытался использовать cvFilter2D(), но, похоже, это дает мне разные результаты, чем conv2().Есть ли какая-либо функция в opencv, эквивалентная matlab conv2

Например:

CvMat * Aa = cvCreateMat(2, 2, CV_32FC1); 
CvMat * Bb = cvCreateMat(2, 2, CV_32FC1); 
CvMat * Cc = cvCreateMat(2, 2, CV_32FC1); 
cvSetReal2D(Aa, 0, 0, 1); 
cvSetReal2D(Aa, 0, 1, 2); 
cvSetReal2D(Aa, 1, 0, 3); 
cvSetReal2D(Aa, 1, 1, 4); 
cvSetReal2D(Bb, 0, 0, 5); 
cvSetReal2D(Bb, 0, 1, 5); 
cvSetReal2D(Bb, 1, 0, 5); 
cvSetReal2D(Bb, 1, 1, 5); 
cvFilter2D(Aa, Cc, Bb); 

This produces the matrix [20 30; 40 50] 


In MATLAB: 
>> A=[1 2; 3 4] 
A = 
1 2 
3 4 

>> B=[5 5; 5 5] 
B = 
5 5 
5 5 

>> conv2(A,B,'shape') 
ans = 
50 30 
35 20 

Пожалуйста Помощь me.its очень полезно для me.thank вас.

С уважением

Arangarajan.

+0

minor edit: правильный вызов 'conv2 (A, B, 'same')' – Amro

ответ

5

Если вы используете свертку, на краю матрицы есть проблема. Маска свертки требует значений, которые находятся вне матрицы. Алгоритмы OpenCV и Matlab используют разные стратегии для решения этой проблемы. OpenCV просто реплицирует пиксели границы, тогда как Matlab просто предполагает, что все эти пиксели равны нулю.

Итак, если вы хотите эмулировать поведение matlab в OpenCV, вы можете добавить это нулевое дополнение вручную. Для этого даже есть специальная функция. Позвольте мне привести вам пример того, как ваш код может быть изменен:

CvMat * Ccb = cvCreateMat(3, 3, CV_32FC1); 
CvMat * Aab = cvCreateMat(3, 3, CV_32FC1); 
cvCopyMakeBorder(Aa,Aab, cvPoint(0,0),IPL_BORDER_CONSTANT, cvScalarAll(0)); 
cvFilter2D(Aab, Ccb, Bb); 

В результате это дает является:

20.000 30.000 20.000 
40.000 50.000 30.000 
30.000 35.000 20.000 

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

+0

Спасибо. Очень много ... – aranga

+4

+1 Имейте в виду, что функция 'cvFilter2D' выполняет корреляцию, а' conv2' выполняет свертку. Для примера выше это не имеет значения, но если ядро ​​не было симметричным, вам нужно повернуть его на 180 градусов для соответствия результатов. – Amro

7

Численная вычислительная среда Matlab (или, например, ее свободная альтернатива GNU Octave) предоставляет функцию conv2 для двумерной свертки заданной матрицы с ядром свертки. При написании кода на C++, основанного на бесплатной библиотеке обработки изображений OpenCV, я обнаружил, что OpenCV в настоящее время не предлагает эквивалентного метода.

Хотя существует метод filter2D(), который реализует двумерную корреляцию, и которые могут быть использованы для свернутые изображение с заданным ядром (листать, что ядро ​​и перемещение точки привязки в правильное положение, как объяснено на соответствующая страница документации OpenCV), было бы неплохо иметь метод, предлагающий такие же параметры обработки границ, как Matlab («полная», «действительная» или «такая же» свертка), например для сравнения результатов того же алгоритма, реализованного как в Matlab, так и в C++ с использованием OpenCV.

Вот что я придумал:

enum ConvolutionType { 
/* Return the full convolution, including border */ 
    CONVOLUTION_FULL, 

/* Return only the part that corresponds to the original image */ 
    CONVOLUTION_SAME, 

/* Return only the submatrix containing elements that were not influenced by the border  
*/ 
    CONVOLUTION_VALID 
}; 

void conv2(const Mat &img, const Mat& kernel, ConvolutionType type, Mat& dest) { 
    Mat source = img; 
    if(CONVOLUTION_FULL == type) { 
    source = Mat(); 
    const int additionalRows = kernel.rows-1, additionalCols = kernel.cols-1; 
    copyMakeBorder(img, source, (additionalRows+1)/2, additionalRows/2,  
(additionalCols+1)/2, additionalCols/2, BORDER_CONSTANT, Scalar(0)); 
    } 

    Point anchor(kernel.cols - kernel.cols/2 - 1, kernel.rows - kernel.rows/2 - 1); 
    int borderMode = BORDER_CONSTANT; 
    filter2D(source, dest, img.depth(), flip(kernel), anchor, 0, borderMode); 

    if(CONVOLUTION_VALID == type) { 
    dest = dest.colRange((kernel.cols-1)/2, dest.cols - kernel.cols/2) 
      .rowRange((kernel.rows-1)/2, dest.rows - kernel.rows/2); 
    } 
} 

В моих модульных тестов, эта реализация дала результаты, которые были практически идентичны с реализацией Matlab. Обратите внимание, что как OpenCV, так и Matlab выполняют свертку в пространстве Фурье, если ядро ​​достаточно велико. Определение «большой» варьируется в обеих реализациях, но результаты все равно должны быть очень похожими даже для больших ядер.

Кроме того, производительность этого метода может быть проблемой для «полного» случая свертки, так как всю исходную матрицу нужно скопировать, чтобы добавить границу вокруг нее. Наконец, если вы получаете исключение в вызове filter2D(), и используете ядро ​​только с одним столбцом, это может быть вызвано этой ошибкой. В этом случае установите для параметра borderMode значение, например. BORDER_REPLICATE, или используйте последнюю версию библиотеки из соединительной линии OpenCV.

+0

+1 Лучший ответ до сих пор. Фрагмент кода хорош и выполняет что-то очень похожее на 'conv2' MATLAB. Плюс неплохо напомнить, что «filter2D» OpenCV выполняет корреляцию, а не свертку. –

+0

Отличный ответ! – Itay

+0

Не должен ли flip() принимать по крайней мере два параметра? Согласно doc C++: void flip (InputArray src, OutputArray dst, int flipCode). Поэтому это должно быть cv :: flip (kernel, kernel, 0) – iqbalnaved

Смежные вопросы