sobel算子边缘提取及程序优化(C语言)
1. 利用高斯模糊
直接使用边缘检测算子,提取出的信息过多,使用高斯模糊滤去一些不必要的信息
根据正态分布,获取高斯模糊的归一化卷积核如下
直接对原图进行高斯模糊(以大小为120*188的灰度图为例)
void Gaussain_Blur() {
uint8_t* map;
uint8_t* my_map;
//float Gaussain_Blur[9] = {0.075, 0.124, 0.075, 0.124, 0.204, 0.124, 0.075, 0.124, 0.075};
float Gaussain_Blur[9] = { 0.0947416, 0.118318, 0.0947416, 0.118318, 0.147761, 0.118318, 0.0947416, 0.118318, 0.0947416 };
uint8_t temp_fix[9];
uint8_t Blur_image[CAMERA_H][CAMERA_W];
map = fullBuffer; // 获取原灰度图
for (int j = 0; j < CAMERA_W; ++j) { // 第一行不做处理
Blur_image[0][j] = *(map);
map++;
}
for (int i = 1; i < CAMERA_H - 1; ++i) {
Blur_image[i][0] = *(map); // 第一列不做处理
map++;
/* 高斯模糊 */
for (int j = 1; j < CAMERA_W - 1; ++j) {
temp_fix[0] = *(map - CAMERA_W - 1);
temp_fix[1] = *(map - CAMERA_W);
temp_fix[2] = *(map - CAMERA_W + 1);
temp_fix[3] = *(map - 1);
temp_fix[4] = *(map);
temp_fix[5] = *(map + 1);
temp_fix[6] = *(map + CAMERA_W - 1);
temp_fix[7] = *(map + CAMERA_W);
temp_fix[8] = *(map + CAMERA_W + 1);
float fix_sum = 0;
for (int k = 0; k < 9; ++k) {
fix_sum += (float)temp_fix[k] * Gaussain_Blur[k];
}
Blur_image[i][j] = (int)fix_sum;
map++;
}
Blur_image[i][CAMERA_W - 1] = *(map); // 最后一列不做处理
map++;
}
for (int j = 0; j < CAMERA_W; ++j) { // 最后一行不做处理
Blur_image[CAMERA_H - 1][j] = *(map);
map++;
}
}
2. sobel算子提取边缘的原理
s o b e l sobel sobel算子是 3*3 的矩阵,利用如下矩阵对图像进行卷积可以获取图像大的竖直边界和水平边界信息。
G Y = [ − 1 0 1 − 2 0 2 − 1 0 1 ] G_Y=\begin{bmatrix}-1 & 0 & 1 \\ -2 & 0 & 2 \\ -1 & 0 & 1 \\ \end{bmatrix} GY=⎣ ⎡−1−2−1000121⎦ ⎤ G X = [ − 1 − 2 − 1 0 0 0 1 2 1 ] G_X =\begin{bmatrix}-1 & -2 & -1 \\ 0 & 0 & 0 \\ 1 & 2 & 1 \\ \end{bmatrix} GX=⎣ ⎡−101−202−101⎦ ⎤
对图像的某九宫格进行卷积后,获取到的边缘像素信息如下
G i m a g e = [ f ( x − 1 , y − 1 ) f ( x , y − 1 ) f ( x + 1 , y − 1 ) f ( x − 1 , y ) f ( x , y ) f ( x + 1 , y ) f ( x − 1 , y + 1 ) f ( x , y + 1 ) f ( x + 1 , y + 1 ) ] G_{image}= \begin{bmatrix} f(x-1, y-1) & f(x, y-1) & f(x+1, y-1) \\ f(x-1, y) & f(x, y) & f(x+1, y)\\ f(x-1, y+1) & f(x, y+1) & f(x+1, y+1)\\ \end{bmatrix} Gimage=⎣ ⎡f(x−1,y−1)f(x−1,y)f(x−1,y+1)f(x,y−1)f(x,y)f(x,y+1)f(x+1,y−1)f(x+1,y)f(x+1,y+1)⎦ ⎤
为了方便理解,将图像九宫格信息标号
G i m a g e = [ p i x 1 p i x 2 p i x 3 p i x 4 p i x 5 p i x 6 p i x 7 p i x 8 p i x 9 ] G_{image}= \begin{bmatrix} pix_1 & pix_2 & pix_3 \\ pix_4 & pix_5 & pix_6\\ pix_7 & pix_8 & pix_9\\ \end{bmatrix} Gimage=⎣ ⎡pix1pix4pix7pix2pix5pix8pix3pix6pix9⎦ ⎤
G E D G E c o l o m = G X ∗ G i m a g e = − p i x 1 − 2 p i x 2 − p i x 3 + p i x 7 + 2 p i x 8 + p i x 9 G_{EDGE_{colom}} = G_X * G_{image} = -pix_1 -2pix_2 - pix_3 + pix_7 + 2pix_8 + pix_9 GEDGEcolom=GX∗Gimage=−pix1−2pix2−pix3+pix7+2pix8+pix9
G E D G E r o w = G Y ∗ G i m a g e = − p i x 1 − 2 p i x 4 − p i x 7 + p i x 3 + 2 p i x 6 + p i x 9 G_{EDGE_{row}} = G_Y * G_{image} = -pix_1 - 2pix_4 - pix_7 + pix_3 + 2pix_6 + pix_9 GEDGErow=GY∗Gimage=−pix1−2pix4−pix7+pix3+2pix6+pix9
最后根据卷积结果获得一个灰度值
G p i x 5 = G E D G E c o l o m 2 + G E D G E r o w 2 G_{pix_5} = \sqrt{G_{EDGE_{colom}}^2 + G_{EDGE_{row}}^2} Gpix5=GEDGEcolom2+GEDGErow2
2. sobel算子的C语言实现
代码实现
void Sobel_get_edge(void) {
uint8_t* map;
uint8_t* my_map;
uint8_t pix_1 = 0;
uint8_t pix_2 = 0;
uint8_t pix_3 = 0;
uint8_t pix_4 = 0;
uint8_t pix_5 = 0;
uint8_t pix_6 = 0;
uint8_t pix_7 = 0;
uint8_t pix_8 = 0;
uint8_t pix_9 = 0;
map = &Blur_image[0][0]; // 对高斯模糊之后的图像进行边缘提取
for (int i = 0; i < CAMERA_H - 2; i++) {
IMG[i][0] = *(map); // 处理结果存储在IMG中
map++;
my_map = &IMG[i][1];
for (int j = 1; j < 188 - 1; j++) {
pix_1 = *(map - 1);
pix_2 = *(map);
pix_3 = *(map + 1);
pix_4 = *(map + CAMERA_W - 1);
pix_5 = *(map + CAMERA_W);
pix_6 = *(map + CAMERA_W + 1);
pix_7 = *(map + CAMERA_W + CAMERA_W - 1);
pix_8 = *(map + CAMERA_W + CAMERA_W);
pix_9 = *(map + CAMERA_W + CAMERA_W + 1);
int G_x = -pix_1 - 2 * pix_2 - pix_3 + pix_7 + 2 * pix_8 + pix_9;
int G_y = -pix_1 - 2 * pix_4 - pix_7 + pix_3 + 2 * pix_6 + pix_9;
*(my_map) = sqrt(G_x * G_x + G_y * G_y);
map++;
my_map++;
}
IMG[i][CAMERA_W - 1] = *(map);
map++;
my_map++;
}
for (int j = 0; j < CAMERA_W; ++j) {
IMG[CAMERA_H - 1][j] = *(map);
map++;
}
}
直接对原图进行边缘提取效果并不好,会出现断线、边缘检测过于敏锐等情况
未进行高斯模糊的边界提取效果如下
阈值为100时的二值化结果:
使用SCHARR算子结果如下
阈值为100时的二值化结果:
阈值改为150
高斯模糊后的边界提取效果如下
可以看到,高斯模糊之后的边界提取效果更好