原文:http://blog.csdn.net/autocyz/article/details/43193123
- #include <opencv2\core\core.hpp>
- #include <opencv2\highgui\highgui.hpp>
- #include <opencv2\opencv.hpp>
- #include <iostream>
- using namespace cv;
- using namespace std;
- typedef unsigned char byte;
- void gradientGray(Mat &src, Mat &mag);
- int main(){
- Mat src = imread("1.jpg", 0);//以灰度形式读取图片
- Mat dst;
- gradientGray(src, dst);
- imwrite("2.jpg",dst); //保存文件,梯度图
- imshow("src", src);
- imshow("dst", dst);
- waitKey(0);
- }
- void gradientGray(Mat &src, Mat &mag)
- {
- const int H = src.rows, W = src.cols;
- Mat Ix(H, W, CV_32S), Iy(H, W, CV_32S);
- //因为计算出的梯度值可能有正有负,且值也可能会很大,故数据类型为整形
- // 求水平方向梯度,处理左右边缘像素
- for (int y = 0; y < H; y++){
- Ix.at<int>(y, 0) = abs(src.at<byte>(y, 1) - src.at<byte>(y, 0)) * 2;
- for (int x = 1; x < W - 1; x++)
- Ix.at<int>(y, x) = abs(src.at<byte>(y, x + 1) - src.at<byte>(y, x - 1));
- Ix.at<int>(y, W - 1) = abs(src.at<byte>(y, W - 1) - src.at<byte>(y, W - 2))*2;
- }
- // 求垂直方向梯度,处理左右边缘像素
- for (int x = 0; x < W; x++) {
- Iy.at<int>(0, x) = abs(src.at<byte>(1, x) - src.at<byte>(0, x)) * 2;
- for (int y = 1; y < H - 1; y++)
- Iy.at<int>(y, x) = abs(src.at<byte>(y + 1, x) - src.at<byte>(y - 1, x));
- Iy.at<int>(H - 1, x) = abs(src.at<byte>(H - 1, x) - src.at<byte>(H - 2, x)) * 2;
- }
- /*for (int j = 0; j < H; j++)
- for (int k = 0; k < W; k++)
- {
- mag.at<byte>(j, k) = min(Ix.at<int>(j,k) + Iy.at<int>(j, k), 255);
- }*/
- convertScaleAbs(min(Ix + Iy, 255), mag); //这句话和上面的for循环是同样的功能
- }
- </span>
另外,我采用的梯度求解方法为,当前像素的后一个像素减前一个像素的差值,作为当前像素的当前方向的梯度值。因为梯度本质上是求微分,因此对与图像,其存在两个方向上的梯度,即水平和垂直方向。这也是程序中求了两次灰度的原因。
在求了两个方向的梯度之后,再如何求出当前像素的梯度值,其方法也是很多的。我采用的是将水平和垂直梯度的绝对值相加,也可以采用平方和再开根号的方法,或者直接取二者最大值都行。
另外,解释一下,最后的那个类型转换函数,其作用是将当前数据类型的图像转换为unsigned char型,另外,在OpenCV中,其重载了很多算术运算符,比如这个函数里面的Ix+Iy就是代表对应位相加。
下面给出原图和效果图:
原图:
效果图:
是不是比较像素描~~~~