边缘检测的一般步骤:
第一步:滤波
边缘检测的算法主要是基于图像强度的一阶和二阶导数,但导数通常对噪声很敏感,因此必须采用滤波器来改善与噪声有关的边缘检测器的性能。常见的滤波方法主要有高斯滤波,即采用离散化的高斯函数产生一组归一化的高斯核,然后基于高斯核函数对图像灰度矩阵的每一点进行加权求和。
第二步:增强
增强边缘的基础是确定图像各个点邻域强度的变化值。增强算法可以将图像灰度点邻域强度值有显著变化的点凸显出来。在具体编程实现时,可通过计算梯度幅值来确定。
第三步:检测
经过增强的图像,往往邻域中有很多点的梯度值比较大,而在特定的应用中,这些点并不是要找的边缘点,所以应该采用某种方法来对这些点进行取舍。实际工程中,常用的方法是通过阈值化方法来检测。
实现步骤:
(1)高斯模糊
(2)边缘梯度
(3)综合梯度
(4)依据梯度方向做非极大值抑制
(5)使用上下阈值检测边缘
(6)连接边缘
canny.cpp#include "iostream"
#include "opencv2/opencv.hpp"
#include "imgproc.h"
#include "characterproc.h"
using namespace cv;
using namespace std;
int main()
{
//1,读取图像
String img_path = "/home/whf/PycharmProjects/Tool/data/motion_data/trafficcone_src/10.jpg";
Mat img_src = imread(img_path);
Mat img_gray = Mat(img_src.rows,img_src.cols,CV_8UC1,Scalar(0));
//1.1 灰度变换
img_gray = rgb2gray(img_src,"eyeperception");
//2,高斯模糊
Mat img_gauss = gaussproc(img_gray);
//3,求梯度
Mat xy_grad = Mat(img_src.rows,img_src.cols,CV_8UC1,Scalar(0));
Mat th_gra = Mat(img_src.rows,img_src.cols, CV_8UC1, Scalar(0));
xy_grad = xy_gradient(img_gauss);
//imshow("th_gra",th_gra);
//4,梯度的非极大值抑制
Mat img_nms = Mat(img_src.rows,img_src.cols,CV_8UC1,Scalar(0));
img_nms = grad_nms(xy_grad);
//5,使用上下阈值检测边缘
Mat img_thresh = Mat(img_src.rows,img_src.cols,CV_8UC1,Scalar(0));
img_thresh = double_thresh(img_nms, 60, 100);
imshow("img_thresh",img_thresh);
//6,抑制独立的弱边缘
Mat img_link = Mat(img_src.rows,img_src.cols,CV_8UC1,Scalar(0));
img_link = link_eage(img_thresh);
imshow("img_link",img_link);
waitKey(0);
return 0;
}
imgproc.cpp#include "imgproc.h"
#include "characterproc.h"
#include "gauss.h"
#include "assert.h"
using namespace cv;
Mat rgb2gray(Mat rgb_img, string type)
{
Mat img_src = rgb_img.clone();
int cols = rgb_img.cols;
int rows = rgb_img.rows;
Mat img = Mat(rows, cols, CV_8UC1, Scalar(0));
if(stringisequal(type, "eyeperception"))
{
for(int i = 0; i<rows; i++)
{
for(int j = 0; j<cols; j++)
{
Vec3b pix = img_src.at<Vec3b>(i,j);
img.at<uchar>(i,j) = (pix[0]*0.114 + pix[1]*0.55 + pix[2]*0.34);
}
}
return img;
}
if(stringisequal(type, "avg"))
{
for(int i = 0; i<cols; i++)
{
for(int j = 0; j<rows; j++)
{
Vec3b pix = rgb_img.at<Vec3b>(i,j);
img.at<uchar>(i,j) = (pix[0] + pix[1] + pix[2])/3;
}
}
return img;
}
}
Mat gaussproc(Mat img)
{
int c = img.channels();
assert(c == 1);
Mat img_src = img.clone();
int cols = img_src.cols;
int rows = img_src.rows;
Mat img_gauss(rows, cols, CV_8UC1, Scalar(0));
float **ker = gauss_kernel(3, 0.01);
//padding
Mat img_pad = Mat(rows+2, cols+2, CV_8UC1, Scalar(0));
img_src.copyTo(img_pad(Rect(1,1,cols,rows)));
for(int i=0; i < rows; i++)
{
for(int j=0;j<cols;j++)
{
img_gauss.at<uchar>(i,j) = ker[0][0]*img_pad.at<uchar>(i-1,j-1) + ker[0][1]*img_pad.at<uchar>(i-1,j) + ker[0][2]*img_pad.at<uchar>(i-1,j+1)
+ ker[1][0]*img_pad.at<uchar>(i,j-1) + ker[1][1]*img_pad.at<uchar>(i,j) + ker[1][2]*img_pad.at<uchar>(i,j+1)
+ ker[2][0]*img_pad.at<uchar>(i+1,j+1) + ker[2][1]*img_pad.at<uchar>(i+1,j) + ker[2][2]*img_pad.at<uchar>(i+1,j+1);
}
}
delete_kernel(ker,3);
return img_gauss;
}
Mat x_gradient(Mat img)
{
Mat img_src = img.clone();
int cols = img_src.cols;
int rows = img_src.rows;
Mat x_gra = Mat(rows, cols, CV_8UC1, Scalar(0));
for(int i = 0; i < rows-1; i++)
{
for (int j = 0; j < cols-1; j++)
{
x_gra.at<uchar>(i,j) = abs(img_src.at<uchar>(i,j) -img_src.at<uchar>(i+1,j) + img_src.at<uchar>(i,j+1) -img_src.at<uchar>(i+1,j+1) )/2;
}
}
return x_gra;
}
Mat y_gradient(Mat img)
{
Mat img_src = img.clone();
int cols = img_src.cols;
int rows = img_src.rows;
Mat y_gra = Mat(rows, cols, CV_8UC1, Scalar(0));
for(int i = 0; i < rows-1; i++)
{
for (int j = 0; j < cols-1; j++)
{
y_gra.at<uchar>(i,j) = abs(img_src.at<uchar>(i,j) - img_src.at<uchar>(i,j+1) + img_src.at<uchar>(i+1,j) - img_src.at<uchar>(i+1,j+1));
}
}
return y_gra;
}
Mat xy_gradient(Mat img)
{
Mat img_src = img.clone();
int cols = img_src.cols;
int rows = img_src.rows;
Mat x_gra = x_gradient(img_src);
Mat y_gra = y_gradient(img_src);
Mat xy_gra = Mat(rows, cols, CV_8UC1, Scalar(0));
for(int i = 0; i < rows-1; i++)
{
for (int j = 0; j < cols-1; j++)
{
//if(y_gra.at<uchar>(i,j)==0) y_gra.at<uchar>(i,j)=1;
//th_gra = atan(abs(x_gra.at<uchar>(i,j))/abs(y_gra.at<uchar>(i,j)))*57.3 + 90;
xy_gra.at<uchar>(i,j) = sqrt( (x_gra.at<uchar>(i,j) * x_gra.at<uchar>(i,j)) + (y_gra.at<uchar>(i,j) * y_gra.at<uchar>(i,j)) );
if (xy_gra.at<uchar>(i,j)>255) xy_gra.at<uchar>(i,j)=255;
//if (xy_gra.at<uchar>(i,j)<200) xy_gra.at<uchar>(i,j)=0;
}
}
return xy_gra;
}
Mat grad_nms(Mat img)
{
Mat img_src = img.clone();
int cols = img_src.cols;
int rows = img_src.rows;
Mat gra_nms = Mat(rows, cols, CV_8UC1, Scalar(0));
for (int i = 1; i < rows-1; i++)
{
for(int j = 1; j<cols-1; j++)
{
int val00 = img_src.at<uchar>(i-1,j-1);
int val01 = img_src.at<uchar>(i-1,j);
int val02 = img_src.at<uchar>(i-1,j + 1);
int val10 = img_src.at<uchar>(i,j-1);
int val11 = img_src.at<uchar>(i,j);
int val12 = img_src.at<uchar>(i,j + 1);
int val20 = img_src.at<uchar>(i+1,j-1);
int val21 = img_src.at<uchar>(i+1,j);
int val22 = img_src.at<uchar>(i+1,j + 1);
if(val11<val00 | val11<val01 | val11 < val02 | val11 < val10 | val11<val12 | val11<val21 | val11<val22 | val11 < val20) img_src.at<uchar>(i,j)=0;
}
}
return img_src;
}
Mat double_thresh(Mat img, int minthresh, int maxthresh)
{
Mat img_src = img.clone();
int cols = img_src.cols;
int rows = img_src.rows;
for (int i = 1; i < rows; i++)
{
for(int j = 1; j<cols; j++)
{
if(img_src.at<uchar>(i,j) > maxthresh) img_src.at<uchar>(i,j) = 255;
if(img_src.at<uchar>(i,j) < minthresh) img_src.at<uchar>(i,j) = 0;
}
}
return img_src;
}
Mat link_eage(Mat img)
{
Mat img_src = img.clone();
int cols = img_src.cols;
int rows = img_src.rows;
Mat img_l = Mat(rows, cols, CV_8UC1, Scalar(0));
for(int i = 1; i < rows-1; i++)
{
for(int j = 1; j < cols-1; j++)
{
if((img_src.at<uchar>(i-1,j-1) == 255) | (img_src.at<uchar>(i-1,j) == 255) | (img_src.at<uchar>(i-1, j+1) == 255)
| (img_src.at<uchar>(i, j-1) == 255) | (img_src.at<uchar>(i, j+1) == 255)
| (img_src.at<uchar>(i+1, j-1) == 255) | (img_src.at<uchar>(i+1,j) == 255) | (img_src.at<uchar>(i+1,j+1) == 255))
{
img_l.at<uchar>(i,j) = 255;
}
else
{
img_l.at<uchar>(i,j) = img_src.at<uchar>(i,j);
}
}
}
return img_l;
}
imgproc.h
#include "opencv2/opencv.hpp"
#include "math.h"
using namespace cv;
using namespace std;
Mat rgb2gray(Mat rgb_img, string type);
Mat gaussproc(Mat img);
Mat x_gradient(Mat img);
Mat y_gradient(Mat img);
Mat xy_gradient(Mat img);
Mat grad_nms(Mat img);
Mat double_thresh(Mat img, int minthresh, int maxthresh);
Mat link_eage(Mat img);
gauss.cpp#include <gauss.h>
#include <math.h>
#define pi 3.1415926
using namespace std;
float** gauss_kernel(int k, float sigm)
{
//printf("k: %d, sigm: %f\n",k,sigm);
float **M;
float sum = 0;
M = new float *[k];
for(int i = 0; i < k; i++)
{
M[i] = new float[k];
}
for(int i = -(k-1)/2; i < (k-1)/2+1; i++)
{
for(int j = -(k-1)/2; j < (k-1)/2+1; j++)
{
float f1 = 1./(2*pi*pow(sigm, 2));
float f2 = -(pow(i,2)+pow(j,2));
float f3 = f2/(2*pow(sigm, 2));
M[i+(k-1)/2][j+(k-1)/2] = f1*exp(f3);
sum = sum+M[i+(k-1)/2][j+(k-1)/2];
//printf("%f\t",M[i+(k-1)/2][j+(k-1)/2]);
}
//printf("\n");
}
//归一化
for(int i = 0; i < k; i++)
{
for(int j = 0; j < k; j++)
{
M[i][j] = M[i][j]/sum;
}
}
return M;
}
void delete_kernel(float** M,int k)
{
for(int i = 0; i < k; i++)
{
delete[] M[i];
M[i] = nullptr;
}
delete[] M;
M = nullptr;
}
gauss.h#include "iostream"
float** gauss_kernel(int k, float sigm);
void delete_kernel(float** M,int k);
characterproc.cpp
#include "characterproc.h"
bool stringisequal(string A, string B)
{
int lenA = A.length();
int lenB = B.length();
if(lenA!=lenB) return false;
for(int i = 0; i<lenA; i++)
{
if(A[i]!=B[i]) return false;
}
return true;
}
characterproc.h
#include "iostream"
using namespace std;
bool stringisequal(string A, string B);
原文链接: https://www.cnblogs.com/zhibei/p/12201452.html
欢迎关注
微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍
原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/192010
非原创文章文中已经注明原地址,如有侵权,联系删除
关注公众号【高性能架构探索】,第一时间获取最新文章
转载文章受原作者版权保护。转载请注明原作者出处!