zoukankan      html  css  js  c++  java
  • c语言数字图像处理(九):边缘检测

    背景知识

    边缘像素是图像中灰度突变的像素,而边缘是连接边缘像素的集合。边缘检测是设计用来检测边缘像素的局部图像处理方法。

    孤立点检测

    使用<https://www.cnblogs.com/GoldBeetle/p/9744625.html>中介绍的拉普拉斯算子

    输出图像为

    卷积模板

    之前有过代码实现,这篇文章中不再进行测试

    基本边缘检测

    图像梯度

    梯度向量大小

    在图像处理过程中,因平方和和开方运算速度较慢,因此简化为如下计算方法

    梯度向量方向与x轴夹角

    对应与不同的偏导数计算方法,得出边缘检测的不同模板

    检测垂直或水平边缘

    原图

     

    使用Sobel模板检测水平边缘

    使用Sobel模板检测垂直边缘

    两者相加

    代码实现

     1 void edge_detection(short** in_array, short** out_array, long height, long width)
     2 {
     3     short gx = 0, gy = 0;
     4     short** a_soble1;
     5     short** a_soble2;
     6 
     7     a_soble1 = allocate_image_array(3, 3);
     8     a_soble2 = allocate_image_array(3, 3);
     9     for (int i = 0; i < 3; i++){
    10         for (int j = 0; j < 3; j++){
    11             a_soble1[i][j] = soble1[i][j];
    12             a_soble2[i][j] = soble2[i][j];
    13         }
    14     }
    15     for (int i = 0; i < height; i++){
    16         for (int j = 0; j < width; j++){
    17             gx = convolution(in_array, i, j, height, width, a_soble1, 3);
    18             gy = convolution(in_array, i, j, height, width, a_soble2, 3);
    19             // out_array[i][j] = gx;
    20             // out_array[i][j] = gy;
    21             out_array[i][j] = gx + gy;
    22             if (out_array[i][j] < 0)
    23                 out_array[i][j] = 0;
    24             else if (out_array[i][j] > 0xff)
    25                 out_array[i][j] = 0xff;
    26         }
    27     }
    28     free_image_array(a_soble1, 3);
    29     free_image_array(a_soble2, 3);
    30 }

     检测对角边缘

    Sobel 45°检测模板

    Sobel -45°检测模板

    两者相加

    代码实现通上,只需替换模板值即可

    Marr-Hildreth边缘检测算法

    1. 对二维高斯函数进行取样,得高斯低通滤波器,对输入图像滤波,滤波器模板大小为大于等于6*σ的最小奇整数

    算法实现

     1 void generate_gaussian_filter(double** gaussian_filter, long sigma)
     2 {
     3     double x, y;
     4     long filter_size = 6 * sigma + 1;
     5 
     6     for (int i = 0; i < filter_size; i++){
     7         for (int j = 0; j < filter_size; j++){
     8             x = i - filter_size / 2;
     9             y = j - filter_size / 2;
    10             gaussian_filter[i][j] = exp(-1.0 * ((pow(x, 2) + pow(y, 2)) / 2 * sigma * sigma));
    11         }
    12     }
    13 }

     2. 计算第一步得到图像的拉普拉斯,利用如下模板

    算法实现

     1 void laplace(short** in_array, short** out_array, long height, long width)
     2 {
     3     short** a_sharpen;
     4 
     5     a_sharpen = allocate_image_array(3, 3);
     6     for (int i = 0; i < 3; i++){
     7         for (int j = 0; j < 3; j++){
     8             a_sharpen[i][j] = sharpen[i][j];
     9         }
    10     }
    11     for (int i = 0; i < height; i++){
    12         for (int j = 0; j < width; j++){
    13             out_array[i][j] = convolution(in_array, i, j, height, width, a_sharpen, 3);
    14         }
    15     }
    16     free_image_array(a_sharpen, 3);
    17 }

     运行结果

    3. 寻找零交叉,对任意像素p,测试上/下,左/右,两个对角线四个位置,当有两对符号不同并且绝对值差大于某一阈值时为零交叉点

    算法实现

     1 int is_cross(short** in_array, long row, long column)
     2 {
     3     int cross_num = 0;
     4 
     5     if (in_array[row-1][column-1] * in_array[row+1][column+1] < 0 && 
     6         abs(abs(in_array[row-1][column-1]) - abs(in_array[row+1][column+1])) > 0x66)
     7         cross_num++;
     8     if (in_array[row-1][column] * in_array[row+1][column] < 0&& 
     9         abs(abs(in_array[row-1][column]) - abs(in_array[row+1][column])) > 0x66)
    10         cross_num++;
    11     if (in_array[row-1][column+1] * in_array[row+1][column-1] < 0&& 
    12         abs(abs(in_array[row-1][column+1]) - abs(in_array[row+1][column-1])) > 0x66)
    13         cross_num++;
    14     if (in_array[row][column-1] * in_array[row][column+1] < 0&& 
    15         abs(abs(in_array[row][column-1]) - abs(in_array[row][column+1])) > 0x66)
    16         cross_num++;
    17 
    18     if (cross_num >= 2)
    19         return 1;
    20     else
    21         return 0;
    22 }
     1 void marr(short** in_array, short** out_array, long height, long width)
     2 {
     3     long sigma = 2;
     4     long filter_size = 6 * sigma + 1;
     5     double** gaussian_filter;
     6     short **gauss_array, **laplace_array;
     7 
     8     gaussian_filter = allocate_double_array(filter_size, filter_size);
     9     gauss_array = allocate_image_array(height, width);
    10     laplace_array = allocate_image_array(height, width);
    11     generate_gaussian_filter(gaussian_filter, sigma);
    12 
    13     for (int i = 0; i < height; i++){
    14         for (int j = 0; j < width; j++){
    15             gauss_array[i][j] = convolutiond(in_array, i, j, height, width, gaussian_filter, filter_size);
    16         }
    17     }
    18     printf("Gasuuian filter done
    ");
    19     laplace(gauss_array, laplace_array, height, width);
    20     printf("Laplace done
    ");
    21     zero_cross(laplace_array, out_array, height, width);
    22     printf("Zero cross done
    ");
    23     
    24     free_double_array(gaussian_filter, filter_size);
    25     free_image_array(gauss_array, height);
    26     free_image_array(laplace_array, height);
    27 }

    最终运行结果

    可以看出,该算法检测出的边缘更加符合物体的真实边缘,但是这些边缘是由离散的点构成的,因此需要进行边缘连接来进一步加工,本文对此不再进行详述,读者有兴趣可以进行更加深入的研究。

  • 相关阅读:
    leetcode 18 4Sum
    leetcode 71 Simplify Path
    leetcode 10 Regular Expression Matching
    leetcode 30 Substring with Concatenation of All Words
    leetcode 355 Design Twitte
    leetcode LRU Cache
    leetcode 3Sum
    leetcode Letter Combinations of a Phone Number
    leetcode Remove Nth Node From End of List
    leetcode Valid Parentheses
  • 原文地址:https://www.cnblogs.com/GoldBeetle/p/9982086.html
Copyright © 2011-2022 走看看