【发布时间】:2015-12-29 22:02:52
【问题描述】:
我正在尝试在 C++ 中使用 Opencv 3.0 实现主动轮廓模型算法。 该算法基于我为 MatLab 编写的脚本,并没有按预期工作。 这两张图展示了两种算法运行的结果。
MatLab 脚本:
和 OpenCV 之一:
在它们中,我为所有 ACM 参数使用了相同的值,因此它们应该返回相同的东西,即白色圆圈轮廓。 我怀疑问题出在我的图像能量函数上,因为 opencv 和 matlab 中的梯度操作不一样。图像能量的matlab脚本为:
function [Eext] = get_eext(wl, we, wt, image)
%External Energy
[row,col] = size(image);
eline = image; %eline is simply the image intensities
[grady,gradx] = gradient(image);
eedge = -1 *(gradx .* gradx + grady .* grady);
%masks for taking various derivatives
m1 = [-1 1];
m2 = [-1;1];
m3 = [1 -2 1];
m4 = [1;-2;1];
m5 = [1 -1;-1 1];
cx = conv2(image,m1,'same');
cy = conv2(image,m2,'same');
cxx = conv2(image,m3,'same');
cyy = conv2(image,m4,'same');
cxy = conv2(image,m5,'same');
eterm = zeros(row, col);
for i = 1:row;
for j= 1:col;
% eterm as deined in Kass et al Snakes paper
eterm(i,j) = (cyy(i,j)*cx(i,j)*cx(i,j) -2 *cxy(i,j)*cx(i,j)...
*cy(i,j) + cxx(i,j)*cy(i,j)*cy(i,j))/((1+cx(i,j)*cx(i,j)...
+ cy(i,j)*cy(i,j))^1.5);
end;
end;
Eext = (wl*eline + we*eedge + wt*eterm);
在 C++ 中,我的函数变成了这样:
Mat get_eext(float wl, float we, float wt, Mat image){
Mat eline, gradx, grady, img_gray, eedge;
//bitdepth defined as CV_32F
image.convertTo(img_gray, bitdepth);
//Convolution Kernels
Mat m1, m2, m3, m4, m5;
m1 = (Mat_<float>(1, 2) << -1, 1);
m2 = (Mat_<float>(2, 1) << -1, 1);
m3 = (Mat_<float>(1, 3) << 1, -2, 1);
m4 = (Mat_<float>(3, 1) << 1, -2, 1);
m5 = (Mat_<float>(2, 2) << 1, -1, -1, 1);
//cvtColor(image, img_gray, CV_BGR2GRAY); <- Not required since image already in grayscale
img_gray.copyTo(eline);
Mat kernelx = (Mat_<float>(1, 3) << -0.5, 0, 0.5);
Mat kernely = (Mat_<float>(3, 1) << -0.5, 0, 0.5);
filter2D(img_gray, gradx, -1, kernelx);
filter2D(img_gray, grady, -1, kernely);
//Edge Energy
eedge = -1 * (gradx.mul(gradx) + grady.mul(grady));
//Termination Energy Convolution
Mat cx, cy, cxx, cyy, cxy, eterm, cxm1, den, cxcx, cxcxm1, cxcxcy, cxcycxy, cycycxx;
filter2D(img_gray, cx, bitdepth, m1);
filter2D(img_gray, cy, bitdepth, m2);
filter2D(img_gray, cxx, bitdepth, m3);
filter2D(img_gray, cyy, bitdepth, m4);
filter2D(img_gray, cxy, bitdepth, m5);
//element wise operations to find Eterm
cxcx = cx.mul(cx);
cxcx.convertTo(cxcxm1, -1, 1, 1);
den = cxcxm1 + cy.mul(cy);
cv::pow(den, 1.5, den);
cxcxcy = cxcx.mul(cy);
cxcycxy = cx.mul(cy);
cxcycxy = cxcycxy.mul(cxy);
cycycxx = cy.mul(cy);
cycycxx = cycycxx.mul(cxx);
eterm = (cxcxcy - 2 * cxcycxy + cycycxx);
cv::divide(eterm,den,eterm,-1);
//Image energy
Mat eext;
eext = wl*eline + we*eedge + wt*eterm;
return eext;}
有谁知道可能出了什么问题?
【问题讨论】:
-
你把你的梯度图和matlab的梯度图对比了吗?
-
filter2D在 OpenCV 中执行相关。在 MATLAB 中,conv2执行 卷积。不同之处在于,对于 MATLAB 执行此操作的filter2D,内核不旋转 180 度。如果您想为filter2D和 OpenCV 实现相同的结果,您需要在 OpenCV 中将内核旋转 180 度。关于这一点,Micka 是正确的,因为您应该比较渐变图像。他们可能不一样。imgradient使用 Sobel 内核作为梯度,因此请确保您的内核在 OpenCV 中是正确的。 -
渐变图确实不一样。旋转 180 度是指使用 [1 -1] 而不是 [-1 1]?
-
@Andrei 很抱歉这么晚才回复您。对,那是正确的。在 OpenCV 中,您可以通过先转置,然后沿列翻转来实现 180 度旋转,因此使用
cv::transpose,然后使用cv::flip,将flipCode设置为 0。