赞
踩
canny边缘检测算法步骤:
1、使用高斯滤波器对图像进行平滑处理。
2、利用一阶偏导算子找到灰度图像沿着水平方向Gx和垂直方向Gy的偏导数,并计算梯度的幅值和方向。
3、对梯度幅值进行NMS非极大值抑制,获取局部梯度的最大值。在3X3窗口中,将给定像素P与沿着梯度线方向的两个像素进行比较,若P的梯度幅值小于该两个像素的梯度幅值,则令P=0;否则保留原幅值。
备注:将梯度方向分为4种来比较梯度幅值的强度:水平方向、垂直方向、正方向、-45°方向。==
4、用双阈值算法检测和边缘连接。分三种情况:
(1)若像素值大于高阈值,则该像素一定是边缘像素(强边缘点),置为255;
(2)若小于低阈值,则一定不是,置为0;
(3)若像素值大于低阈值但小于高阈值,则观察该像素的(3X3)8邻域像素中是否有大于高阈值的像素点,若有则该像素是边缘像素,并将该点置为255,用以连接强边缘点;否则不是,则该点置为0。Canny边缘检测算法原理
详细请看博主这篇文章:【深度学习环境配置】Anaconda +Pycharm + CUDA +cuDNN + Pytorch + Opencv(资源已上传)
/*
函数说明:Mat(int rows, int cols, int type)
函数输入: rows 代表行数
cols 代表列数
type 可以设置为:CV_8UC(n)、CV_8SC(n)、CV_16SC(n)、CV_16UC(n)、CV_32FC(n)、CV_32SC(n)、CV_64FC(n)
其中:8U、8S、16S、16U、32S、32F、64F中的数字,代表Mat中每一个数值的位数
U代表uchar类型、S代表int类型、F代表浮点型(32F为float、64F为double)其他类似。
备注:Mat代表矩阵,该类声明在头文件opencv2/core/core.hpp中
*/
【图像处理】高斯模糊、高斯函数、高斯核、高斯卷积操作
将二维图像先按水平方向进行一维高斯卷积(行卷积),再按垂直方向进行一维高斯卷积(列卷积)。同理:将二维高斯卷积核拆分为一维高斯卷积核。
- (1)对图像使用一维高斯卷积核,在一个方向上进行滤波(例如水平方向);
- (2)将图像进行转置,并使用相同一维高斯卷积核,在相同方向上进行滤波;(由于转置,其实是对垂直方向进行滤波)
- (3)再次转置,将图像还原为原来位置,最终得到二维高斯滤波后的图像。
#include <opencv2/opencv.hpp> #include <math.h> #include <corecrt_math_defines.h> #define _USE_MATH_DEFINES using namespace cv; // 使用命名空间cv。例如:cv::Mat可以省略写为 Mat /* 函数说明:将两个图像拼接,以便在同一个窗口显示 函数输入: dst 输出的拼接后的图像 src1 拼接的第一幅图 src2 拼接的第二幅图 */ void mergeImg(Mat& dst, Mat& src1, Mat& src2) { int rows = src1.rows; int cols = src1.cols + 5 + src2.cols; CV_Assert(src1.type() == src2.type()); dst.create(rows, cols, src1.type()); src1.copyTo(dst(Rect(0, 0, src1.cols, src1.rows))); src2.copyTo(dst(Rect(src1.cols + 5, 0, src2.cols, src2.rows))); } /* 函数说明:一维高斯卷积,对每行进行高斯卷积 函数输入: img 输入原图像 dst 一维高斯卷积后的输出图像 */ void gaussianConvolution(Mat& img, Mat& dst) { int nr = img.rows; int nc = img.cols; int templates[3] = { 1, 2, 1 }; // 按行遍历除每行边缘点的所有点 for (int j = 0; j < nr; j++) { uchar* data = img.ptr<uchar>(j); //提取该行地址 for (int i = 1; i < nc - 1; i++) { int sum = 0; for (int n = 0; n < 3; n++) { sum += data[i - 1 + n] * templates[n]; //相乘累加 } sum /= 4; dst.ptr<uchar>(j)[i] = sum; } } } /* 函数说明:高斯滤波器,利用3*3的高斯模版进行高斯卷积 函数输入: img 输入原图像 dst 高斯滤波后的输出图像 */ void gaussianFilter(Mat& img, Mat& dst) { // 对水平方向进行滤波 Mat dst1 = img.clone(); gaussianConvolution(img, dst1); // 图像矩阵转置 Mat dst2; transpose(dst1, dst2); // 对垂直方向进行滤波 Mat dst3 = dst2.clone(); gaussianConvolution(dst2, dst3); // 再次转置 transpose(dst3, dst); } /* 函数说明:用一阶偏导有限差分计算梯度幅值和方向 函数输入: img 输入原图像 gradXY 输出的梯度幅值 theta 输出的梯度方向 */ void getGrandient(Mat& img, Mat& gradXY, Mat& theta) { gradXY = Mat::zeros(img.size(), CV_8U); theta = Mat::zeros(img.size(), CV_8U); for (int j = 1; j < img.rows - 1; j++) { for (int i = 1; i < img.cols - 1; i++) { double gradY = double(img.ptr<uchar>(j - 1)[i - 1] + 2 * img.ptr<uchar>(j - 1)[i] + img.ptr<uchar>(j - 1)[i + 1] - img.ptr<uchar>(j + 1)[i - 1] - 2 * img.ptr<uchar>(j + 1)[i] - img.ptr<uchar>(j + 1)[i + 1]); double gradX = double(img.ptr<uchar>(j - 1)[i + 1] + 2 * img.ptr<uchar>(j)[i + 1] + img.ptr<uchar>(j + 1)[i + 1] - img.ptr<uchar>(j - 1)[i - 1] - 2 * img.ptr<uchar>(j)[i - 1] - img.ptr<uchar>(j + 1)[i - 1]); gradXY.ptr<uchar>(j)[i] = sqrt(gradX * gradX + gradY * gradY); //计算梯度 theta.ptr<uchar>(j)[i] = atan(gradY / gradX); //计算梯度方向 } } } /* 函数说明:NMS非极大值抑制 函数输入: gradXY 输入的梯度幅值 theta 输入的梯度方向 dst 输出的经局部非极大值抑制后的图像 */ void nonLocalMaxValue(Mat& gradXY, Mat& theta, Mat& dst) { dst = gradXY.clone(); for (int j = 1; j < gradXY.rows - 1; j++) { for (int i = 1; i < gradXY.cols - 1; i++) { double t = double(theta.ptr<uchar>(j)[i]); double g = double(dst.ptr<uchar>(j)[i]); if (g == 0.0) { continue; } double g0, g1; if ((t >= -(3 * M_PI / 8)) && (t < -(M_PI / 8))) { g0 = double(dst.ptr<uchar>(j - 1)[i - 1]); g1 = double(dst.ptr<uchar>(j + 1)[i + 1]); } else if ((t >= -(M_PI / 8)) && (t < M_PI / 8)) { g0 = double(dst.ptr<uchar>(j)[i - 1]); g1 = double(dst.ptr<uchar>(j)[i + 1]); } else if ((t >= M_PI / 8) && (t < 3 * M_PI / 8)) { g0 = double(dst.ptr<uchar>(j - 1)[i + 1]); g1 = double(dst.ptr<uchar>(j + 1)[i - 1]); } else { g0 = double(dst.ptr<uchar>(j - 1)[i]); g1 = double(dst.ptr<uchar>(j + 1)[i]); } if (g <= g0 || g <= g1) { dst.ptr<uchar>(j)[i] = 0.0; } } } } /* 函数说明:弱边缘点补充连接强边缘点 函数输入:img 弱边缘点补充连接强边缘点的输入和输出图像 */ void doubleThresholdLink(Mat& img) { // 循环找到强边缘点,把其领域内的弱边缘点变为强边缘点 for (int j = 1; j < img.rows - 2; j++) { for (int i = 1; i < img.cols - 2; i++) { // 如果该点是强边缘点 if (img.ptr<uchar>(j)[i] == 255) { // 遍历该强边缘点领域 for (int m = -1; m < 1; m++) { for (int n = -1; n < 1; n++) { // 该点为弱边缘点(不是强边缘点,也不是被抑制的0点) if (img.ptr<uchar>(j + m)[i + n] != 0 && img.ptr<uchar>(j + m)[i + n] != 255) { img.ptr<uchar>(j + m)[i + n] = 255; //该弱边缘点补充为强边缘点 } } } } } } for (int j = 0; j < img.rows - 1; j++) { for (int i = 0; i < img.cols - 1; i++) { // 如果该点依旧是弱边缘点,及此点是孤立边缘点 if (img.ptr<uchar>(j)[i] != 255 && img.ptr<uchar>(j)[i] != 255) { img.ptr<uchar>(j)[i] = 0; //该孤立弱边缘点抑制 } } } } /* 函数说明:用双阈值算法检测和连接边缘 函数输入: low 输入的低阈值 high 输入的高阈值 img 输入的原图像 dst 输出的用双阈值算法检测和连接边缘后的图像 */ void doubleThreshold(double low, double high, Mat& img, Mat& dst) { dst = img.clone(); // 区分出弱边缘点和强边缘点 for (int j = 0; j < img.rows - 1; j++) { for (int i = 0; i < img.cols - 1; i++) { double x = double(dst.ptr<uchar>(j)[i]); // 像素点为强边缘点,置255 if (x > high) { dst.ptr<uchar>(j)[i] = 255; } // 像素点置0,被抑制掉 else if (x < low) { dst.ptr<uchar>(j)[i] = 0; } } } // 弱边缘点补充连接强边缘点 doubleThresholdLink(dst); } int main() { // (1)读取图片 Mat img = imread("test.jpg"); if (img.empty()) { printf("读取图像失败!"); system("pause"); return 0; } // 转换为灰度图 Mat img_gray; if (img.channels() == 3) cvtColor(img, img_gray, COLOR_RGB2GRAY); else img_gray = img.clone(); // (2)高斯滤波 Mat gauss_img; gaussianFilter(img_gray, gauss_img); // (3)用一阶偏导有限差分计算梯度幅值和方向 Mat gradXY, theta; getGrandient(gauss_img, gradXY, theta); // (4)NMS非极大值抑制 Mat local_img; nonLocalMaxValue(gradXY, theta, local_img); // (5)用双阈值算法检测和连接边缘 Mat dst; doubleThreshold(40, 80, local_img, dst); // (6)图像显示 Mat outImg; //namedWindow("原始图", 0); //imshow("原始图", img); //namedWindow("灰度图", 0); //imshow("灰度图", img_gray); mergeImg(outImg, img_gray, dst); //图像拼接(维度需相同) namedWindow("img_gray"); //图窗名称 imshow("img_gray", outImg); //图像显示 imwrite("canny.jpg", outImg); //图像保存 waitKey(); //等待键值输入 return 0; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。