理论
相关API
cv::Sobel(
InputArray src, //输入图像
OutputArray dst, //输出图像
int depth, //输出图像深度,填-1表示跟输入图像一致, 由于灰度图是CV_8U,所以Sobel一般使用CV_16S/CV_32F, 需要比输入的灰度图的深度更高, 结果才会更明显
int dx, //x方向,几阶导数, sobel取1
int dy, //y方向,几阶导数, sobel取1
int ksize, //算子(kernel)大小,Sobel算子必须是奇数, 常见的是3
double scale = 1, //输出图像放大或缩小倍数
double delta = 0, //偏移量
int borderType = BORDER_DEFAULT
)
cv::Scharr(
InputArray src, //输入图像
OutputArray dst, //输出图像
int depth, //输出图像深度,填-1表示跟输入图像一致, 由于灰度图是CV_8U,所以Sobel一般使用CV_16S/CV_32F, 需要比输入的灰度图的深度更高, 结果才会更明显
int dx, //x方向,几阶导数, sobel取1
int dy, //y方向,几阶导数, sobel取1
int ksize, //算子(kernel)大小,Sobel算子必须是奇数, 常见的是3
double scale = 1, //输出图像放大或缩小倍数
double delta = 0, //偏移量
int borderType = BORDER_DEFAULT
)
代码示例
using namespace cv;
int main(int argc, char** argv){
Mat src,dst;
int ksize = 0;
src = imread(...);
if( !src.data ){
return -1;
}
//原图
char INPUT_WIN[] = "input image";
namedWindow(INPUT_WIN, CV_WINDOW_AUTOSIZE);
imshow(INPUT_WIN, src);
//先高斯模糊, 再转灰度图
Mat gray_src;
GaussianBlur(src, dst, Size(3,3), 0, 0);
cvtColor(dst, gray_src, CV_BGR2GRAY);
imshow("gray image",gray_src);
/*//cv::Scharr操作, 可以看最后的效果截图, 它的提取效果非常强烈, 根本不怕干扰
Mat xgrad, ygrad;
Scharr(gray_src, xgrad, CV_16S, 1, 0);
Scharr(gray_src, ygrad, CV_16S, 0, 1);*/
//cv::Sobel操作(输出深度为CV_16S,且有convertScaleAbs转换)
Mat xgrad, ygrad;
Scharr(gray_src, xgrad, CV_16S, 1, 0);
Scharr(gray_src, ygrad, CV_16S, 0, 1);
Sobel(gray_src, xgrad, CV_16S, 1, 0, 3); //这里为什么用CV_16S, 因为灰度图是CV_8U,我们设置输出图像的深度比灰度图更大, 就可以容纳更大的特征值, 提取效果也就更明显, 你也可以填-1等同于输入图像的深度,但是反正不能小于输入图像的深度。
Sobel(gray_src, ygrad, CV_16S, 0, 1, 3);
convertScaleAbs(xgrad, xgrad); //这个函数的作用是保证Sobel算子操作过后有些负数结果值不被置为0, 也就是不被截取掉
convertScaleAbs(ygrad, ygrad);
imshow("xgrad", xgrad);
imshow("ygrad", ygrad);
/*//cv::Sobel操作(输出深度填-1,且没有convertScaleAbs转换)
Mat xgrad, ygrad;
Sobel(gray_src, xgrad, -1, 1, 0, 3);
Sobel(gray_src, ygrad, -1, 0, 1, 3);
imshow("xgrad", xgrad);
imshow("ygrad", ygrad);*/
//最终线性混合图:手动写线性混合,去掉权重影响, 可以看最后的效果截图,更明显
Mat xygrad = Mat(xgrad.size(), xgrad.type());
int width = xgrad.cols;
int height = ygrad.rows;
for(int row = 0; row < weight; row++){
for(int col = 0;col < width;col++){
int xg = xgrad.at(row, col);
int yg = ygrad.at(row, col); //因为灰度图是CV_8U,所以用uchar
int xy = xg + yg; //直接相加, 没有权重影响, 更亮更明显
xygrad.at(row, col) = saturate_cast(xy); //saturate_cast这个东西的作用是保证最终值不超过0~255
}
}
imshow("Final Result", xygrad);
/*//最终线性混合图:直接调用addWeighted接口
Mat xygrad;
addWeighted(xgrad, 0.5, ygrad, 0.5, 0, xygrad);
imshow("Final Result", xygrad);*/
waitKey(0);
return 0;
}
效果截图:
使用cv::Sobel(两个方向的输出深度都填CV_16S且有convertScaleAbs转换) x梯度图 与 y梯度图:
使用cv::Sobel(两个方向的输出深度都填-1且没有convertScaleAbs转换) x梯度图 与 y梯度图:
使用cv::Sobel(两个方向的输出深度都填CV_16S且有convertScaleAbs转换, 直接调用addWeighted接口) 最终线性混合图:
使用cv::Sobel(两个方向的输出深度都填CV_16S且有convertScaleAbs转换, 手动写线性混合) 最终线性混合图:
使用cv::Scharr(两个方向的输出深度都填CV_16S且有convertScaleAbs转换, 且手动写线性混合) 最终线性混合图: