OpenCV Sobel函数的手动实现
我有一张图片,使用OpenCV的Sobel函数处理后,
Sobel(Img,gradX,CV_16S,1,0,3);
convertScaleAbs(gradX,absGradX);
imshow("Gradient Image",absGradX);
得到了一个很不错的梯度图像。
我想用filter2D和一个自定义的卷积核来计算我的x方向梯度。我的Sobel卷积核是:
1 0 -1 2 0 -2 1 0 -1
但是当我尝试这样做时,得到的结果却是一张全黑的图像。
float xVals[9] = {.125,0,-.125,.25,0,-.25,.125,0,-.125};
Mat xKernel = Mat(3,3,CV_32F,xVals);
Mat gradXManual,absGradXManual;
filter2D(Img,gradXManual,-1,xKernel,Point(-1,-1),0,BORDER_DEFAULT);
convertScaleAbs(gradXManual,absGradXManual);
imshow("Manual Gradient",absGradXManual);
最终的梯度图像全是黑色。请问我哪里出错了?谢谢!
1 个回答
3
我实际上从你创建的自定义内核得到了输出。我使用的是Python的OpenCV来实现这个功能,不过在OpenCV中调用函数的方式基本上是一样的。为了让你更清楚,这里是我用Sobel和你的自定义内核处理你那张图片的Python代码:
import cv2
import numpy as np
im = cv2.imread('Nj9fM.png'); #// Save image to computer first
#// Call using built-in Sobel
out1 = cv2.Sobel(im, cv2.CV_16S, 0, 1, 3)
out1 = cv2.convertScaleAbs(out1.copy())
#// Create custom kernel
xVals = np.array([0.125,0,-0.125,0.25,0,-0.25,0.125,0,-0.125]).reshape(3,3)
#// Call filter2D
out2 = cv2.filter2D(im, cv2.CV_32F, xVals, None, (-1,-1), 0, cv2.BORDER_DEFAULT)
out2 = cv2.convertScaleAbs(out2.copy())
cv2.imshow('Output 1', out1)
cv2.imshow('Output 2', out2)
cv2.waitKey(0)
cv2.destroyAllWindows()
如果用C++来写的话是这样的:
#include <opencv2/opencv.hpp>
using namespace cv;
int main(int argc, char* argv[])
{
Mat im = imread("Nj9fM.png", CV_LOAD_IMAGE_COLOR); // Save image to computer first
// Call using built-in Sobel
Mat out1, out2;
Sobel(img, out1, CV_16S, 1, 0, 3);
convertScaleAbs(out1, out2);
// Create custom kernel
Mat xVals = Mat_<float>(3, 3) << 0.125, 0, -0.125, 0.25, 0, -0.25, 0.125, 0, -0.125;
// Call filter2D
filter2D(im, out2, -1, xVals, Point(-1,-1), 0 ,BORDER_DEFAULT);
convertScaleAbs(out2, out2);
imshow("Output 1", out1);
imshow("Output 2", out1);
waitKey(0);
destroyWindow("Output 1");
destroyWindow("Output 2");
}
如果你运行这段代码,你会看到两张图片,第一张是用内置的Sobel处理的,第二张是用你的自定义内核处理的。我注意到Sobel实现和你的梯度之间的主要区别是,你把Sobel内核的每个元素都除以了8。因此,你检测到的任何梯度都会导致对比度降低,这就是我看到的效果。实际上,你基本上是把梯度结果除以8,所以输出的强度降低了8倍。你可以试试这样做:float xVals2[9] = {1f,0f,-1f,2f,0f,-2f,1f,0f,-1f};
这是实际的Sobel内核,然后再运行你的代码。你应该会看到对比度有更明显的提升。对于Python来说,这段代码是:
xVals2 = np.array([1.,0.,-1.,2.,0,-2.,1.,0,-1.]).reshape(3,3)
同样在C++中:
Mat xVals2 = Mat_<float>(3, 3) << 1f, 0f, -1f, 2f, 0f, -2f, 1f, 0f, -1f;
如果你使用这个内核运行你的代码,你会发现对比度更高了。不过,你会看到噪声也更多,因为梯度值变大了。