• 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 }

    最终运行结果

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

  • 相关阅读:
    cygwin mysql forget root password
    emacs 复制粘贴的正确姿势
    yarn
    mysql 和 postgresql 区别
    hdfs
    spark
    hbase
    kafka
    flume
    java jar
  • 原文地址:https://www.cnblogs.com/GoldBeetle/p/9982086.html
Copyright © 2020-2023  润新知