用c++ 实现 canny算子,并且达到最优水平
时间: 2023-12-25 10:42:45 浏览: 50
Canny算子是一种广泛使用的边缘检测算法,它的实现可以分为以下几个步骤:
1. 高斯滤波:使用高斯滤波器对原始图像进行平滑处理,以减少噪声对边缘检测结果的影响。
2. 计算梯度:对平滑后的图像进行梯度计算,得到每个像素的梯度方向和梯度幅值。
3. 非极大值抑制:对梯度幅值进行非极大值抑制,将不可能是边缘的像素点去除。
4. 双阈值检测:设置两个阈值,对梯度幅值进行分类,得到强边缘和弱边缘。
5. 边缘连接:将强边缘与连接的弱边缘形成一条边缘线。
下面是一个简单的C++实现:
```c++
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
using namespace std;
int main()
{
// Load image
Mat img = imread("test.jpg", IMREAD_GRAYSCALE);
if (img.empty()) {
cout << "Failed to load image" << endl;
return -1;
}
// Step 1: Gaussian smoothing
Mat img_gaussian;
GaussianBlur(img, img_gaussian, Size(5, 5), 0);
// Step 2: Gradient calculation
Mat img_dx, img_dy;
Scharr(img_gaussian, img_dx, CV_32F, 1, 0);
Scharr(img_gaussian, img_dy, CV_32F, 0, 1);
Mat img_gradient, img_angle;
cartToPolar(img_dx, img_dy, img_gradient, img_angle, true);
// Step 3: Non-maximum suppression
Mat img_suppressed;
img_suppressed = img_gradient.clone();
for (int i = 1; i < img.rows - 1; i++) {
for (int j = 1; j < img.cols - 1; j++) {
float angle = img_angle.at<float>(i, j);
float g1, g2, g;
if ((angle >= -22.5 && angle < 22.5) || angle >= 157.5 || (angle >= -180 && angle < -157.5)) {
g1 = img_gradient.at<float>(i, j+1);
g2 = img_gradient.at<float>(i, j-1);
}
else if ((angle >= 22.5 && angle < 67.5) || (angle >= -157.5 && angle < -112.5)) {
g1 = img_gradient.at<float>(i+1, j+1);
g2 = img_gradient.at<float>(i-1, j-1);
}
else if ((angle >= 67.5 && angle < 112.5) || (angle >= -112.5 && angle < -67.5)) {
g1 = img_gradient.at<float>(i+1, j);
g2 = img_gradient.at<float>(i-1, j);
}
else {
g1 = img_gradient.at<float>(i+1, j-1);
g2 = img_gradient.at<float>(i-1, j+1);
}
g = img_gradient.at<float>(i, j);
if (g < g1 || g < g2) {
img_suppressed.at<float>(i, j) = 0;
}
}
}
// Step 4: Double thresholding
Mat img_edge(img.size(), CV_8U, Scalar(0));
float max_val = 0;
for (int i = 0; i < img_suppressed.rows; i++) {
for (int j = 0; j < img_suppressed.cols; j++) {
float val = img_suppressed.at<float>(i, j);
if (val > max_val) {
max_val = val;
}
}
}
float threshold_low = 0.1 * max_val;
float threshold_high = 0.3 * max_val;
for (int i = 0; i < img_suppressed.rows; i++) {
for (int j = 0; j < img_suppressed.cols; j++) {
float val = img_suppressed.at<float>(i, j);
if (val > threshold_high) {
img_edge.at<uchar>(i, j) = 255;
}
else if (val > threshold_low) {
img_edge.at<uchar>(i, j) = 128;
}
}
}
for (int i = 1; i < img_edge.rows - 1; i++) {
for (int j = 1; j < img_edge.cols - 1; j++) {
if (img_edge.at<uchar>(i, j) == 128) {
if (img_edge.at<uchar>(i-1, j-1) == 255 ||
img_edge.at<uchar>(i-1, j) == 255 ||
img_edge.at<uchar>(i-1, j+1) == 255 ||
img_edge.at<uchar>(i, j-1) == 255 ||
img_edge.at<uchar>(i, j+1) == 255 ||
img_edge.at<uchar>(i+1, j-1) == 255 ||
img_edge.at<uchar>(i+1, j) == 255 ||
img_edge.at<uchar>(i+1, j+1) == 255)
{
img_edge.at<uchar>(i, j) = 255;
}
else {
img_edge.at<uchar>(i, j) = 0;
}
}
}
}
// Step 5: Output
imshow("Original Image", img);
imshow("Canny Edge Detection", img_edge);
waitKey(0);
return 0;
}
```
这个实现可能并不是最优的,但它具有基本的Canny算法实现步骤,你可以根据你的需要进行修改和优化。