在canny函数 ,中如何利用grad_x,grad_y
时间: 2023-02-08 11:40:35 浏览: 136
Canny函数是一种用于图像边缘检测的算法。它使用梯度值来检测图像中的边缘。在Canny函数中,grad_x和grad_y是通过使用Sobel算子来计算图像的水平和垂直梯度。这两个值可以用来计算图像的梯度幅值和梯度方向,并用于检测图像中的边缘。
相关问题
使用Canny函数处理图像,x,y分别是3求出来的梯度,低阈值50,高阈值150代码
在使用Canny边缘检测算法处理图像时,你需要通过计算图像的梯度来确定哪些像素被认为是边缘。Canny算子通常包含以下几个步骤:
1. **高斯滤波**:首先,对图像应用高斯滤波器(gaussian blur),用于平滑并减少噪声,`x` 和 `y` 分别表示两个方向上的梯度。
```c++
cv::Mat img_blur; // 创建一个空矩阵存储高斯模糊后的结果
cv::GaussianBlur(src, img_blur, cv::Size(3, 3), 0);
```
这里的`src`是你原始的输入图像,`cv::Size(3, 3)`指定了3x3的高斯核大小。
2. **计算梯度**:然后计算图像在每个像素处的梯度强度和方向。`Sobel`操作可以做到这一点,例如:
```c++
cv::Mat grad_x, grad_y; // 存储水平和垂直方向的梯度
cv::Sobel(img_blur, grad_x, CV_64F, 1, 0); // 水平梯度
cv::Sobel(img_blur, grad_y, CV_64F, 0, 1); // 垂直梯度
```
3. **计算梯度幅值和方向**:
- 应用公式计算梯度幅值 `sqrt(grad_x * grad_x + grad_y * grad_y)`
- 将方向转换成弧度 `atan2(grad_y, grad_x)`
4. **非极大值抑制**(Non-Maximum Suppression, NMS):消除方向不是局部最大值的响应点。
5. **双阈值处理**:
- 找到大于高阈值 `150` 的像素,并标记为强边缘
- 对于小于低阈值 `50` 的像素,取消标记(除非它与强边缘相邻)
```c++
cv::Mat edges;
cv::Canny(img_blur, edges, 50, 150, 3); // 第三个参数是二阶导数检测的迭代次数
```
完整的代码片段如下:
```cpp
#include <opencv2/opencv.hpp>
// ...
cv::Mat src, img_blur, grad_x, grad_y, edges;
// ... (加载图片)
// ...
cv::GaussianBlur(src, img_blur, cv::Size(3, 3), 0);
cv::Sobel(img_blur, grad_x, CV_64F, 1, 0);
cv::Sobel(img_blur, grad_y, CV_64F, 0, 1);
cv::Mat grad_mag, angle;
grad_mag = cv::sqrt((grad_x * grad_x) + (grad_y * grad_y));
angle = cv::arctan2(grad_y, grad_x) / CV_PI * 180;
// ... (继续进行NMS和双阈值处理)
edges = cv::Canny(img_blur, edges, 50, 150, 3);
// ... (后续处理,保存结果等)
```
根据anny算法的原理自定义一个my_canny函数来实现边缘检测
以下是一个基于anny算法实现的my_canny函数,用于边缘检测:
```python
import numpy as np
import cv2
def my_canny(image, low_threshold, high_threshold, aperture_size=3):
# 1. 首先进行灰度化处理
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# 2. 对图像进行高斯滤波
blurred = cv2.GaussianBlur(gray, (aperture_size, aperture_size), 0)
# 3. 计算图像边缘的梯度和方向
grad_x = cv2.Sobel(blurred, cv2.CV_16S, 1, 0)
grad_y = cv2.Sobel(blurred, cv2.CV_16S, 0, 1)
gradient = cv2.addWeighted(np.abs(grad_x), 0.5, np.abs(grad_y), 0.5, 0)
theta = np.arctan2(grad_y, grad_x)
theta = np.rad2deg(theta) % 180
# 4. 计算图像中的非极大值点
rows, cols = gradient.shape
non_max_sup = np.zeros((rows, cols), dtype=np.uint8)
for i in range(1, rows-1):
for j in range(1, cols-1):
if (0 <= theta[i,j] < 22.5) or (157.5 <= theta[i,j] <= 180):
if (gradient[i,j] >= gradient[i,j-1]) and (gradient[i,j] >= gradient[i,j+1]):
non_max_sup[i,j] = gradient[i,j]
elif (22.5 <= theta[i,j] < 67.5):
if (gradient[i,j] >= gradient[i-1,j-1]) and (gradient[i,j] >= gradient[i+1,j+1]):
non_max_sup[i,j] = gradient[i,j]
elif (67.5 <= theta[i,j] < 112.5):
if (gradient[i,j] >= gradient[i-1,j]) and (gradient[i,j] >= gradient[i+1,j]):
non_max_sup[i,j] = gradient[i,j]
else:
if (gradient[i,j] >= gradient[i-1,j+1]) and (gradient[i,j] >= gradient[i+1,j-1]):
non_max_sup[i,j] = gradient[i,j]
# 5. 使用双阈值算法进行边缘检测
thresholded = np.zeros((rows, cols), dtype=np.uint8)
strong_edges = (non_max_sup > high_threshold)
thresholded[strong_edges] = 255
weak_edges = (non_max_sup >= low_threshold) & (non_max_sup <= high_threshold)
thresholded[weak_edges] = 127
# 使用连通性分析来增强弱边缘
_, contours, hierarchy = cv2.findContours(thresholded, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
for contour in contours:
if cv2.contourArea(contour) < 100:
continue
contour = contour.reshape(-1, 2)
for x, y in contour:
if thresholded[y, x] == 127:
thresholded[y, x] = 255
# 6. 返回检测到的边缘图像
return thresholded
```
上述函数中,使用的参数和方法与anny算法中的一致:
- aperture_size表示高斯滤波的卷积核大小,一般设置为3;
- low_threshold和high_threshold表示双阈值算法的两个阈值;
- 在计算非极大值点时,根据梯度方向来判断当前像素是否为非极大值点;
- 在进行弱边缘的增强时,先使用cv2.findContours函数找到所有的轮廓,然后对每个轮廓进行面积大小的判断,只有面积大于一定值的轮廓才会被认为是真正的边缘。
阅读全文