常用的边缘检测滤波器

使用常见的边缘检测滤波器(3 × 3 3\times3 3 ×3)大小,对 fate.jpeg进行图像处理。

边缘检测用于检测图像中的线。通常这样提取图像中的信息的操作被称为 特征提取
MAX-MIN滤波器是一种常见的 边缘检测滤波器,其使用网格内像素的最大值和最小值的差值对网格内像素重新赋值。

边缘检测通常在 灰度图像上进行。

MAX-MIN滤波器:


cv::Mat max_min_filter(cv::Mat img, int kernel_size)
{
    int row = img.rows;
    int col = img.cols;
    int channel = img.channels();

    cv::Mat new_image = cv::Mat::zeros(row, col, CV_8UC1);

    int pad = floor(kernel_size / 2);

    double max_val = 0, min_val = 10000, val = 0;
    for (int i = 0; i < row; i++)
    {
        for (int j = 0; j < col; j++)
        {
            max_val = 0;
            min_val = 10000;
            for (int di = -pad; di < pad + 1; di++) {
                for (int dj = -pad; dj < pad + 1; dj++) {
                    if (((di + i) >= 0) && ((di + i) < row) && ((dj + j) >= 0) && ((dj + j) < col)) {
                        val = img.at<uchar>(i + di, j + dj);
                    }
                    if (val > max_val) {
                        max_val = val;
                    }
                    if (val < min_val) {
                        min_val = val;
                    }
                }
            }
            new_image.at<uchar>(i, j) = (uchar)(max_val - min_val);
        }
    }

    return new_image;
}

输入图像 (fate.jpeg)MAX-MIN滤波图像 (fate_max_min.jpeg)

差分滤波器对图像亮度急剧变化的边缘有提取效果,可以获得邻接像素的差值。

纵向:
K = [ 0 − 1 0 0 1 0 0 0 0 ] K=\left[ \begin{matrix} 0&-1&0\ 0&1&0\ 0&0&0 \end{matrix} \right]K =​0 0 0 ​−1 1 0 ​0 0 0 ​​
横向:
K = [ 0 0 0 − 1 1 0 0 0 0 ] K=\left[ \begin{matrix} 0&0&0\ -1&1&0\ 0&0&0 \end{matrix} \right]K =​0 −1 0 ​0 1 0 ​0 0 0 ​​


cv::Mat diff_filter(cv::Mat img, int kernel_size, bool horizontal)
{
    int row = img.rows;
    int col = img.cols;

    cv::Mat new_image = cv::Mat::zeros(row, col, CV_8UC1);

    int pad = floor(kernel_size / 2);
    int kernel[3][3] = {{0, -1, 0}, {0, 1, 0}, {0, 0, 0}};

    if (horizontal)
    {
        kernel[0][1] = 0;
        kernel[1][0] = -1;
    }

    double val = 0;
    for (int i = 0; i < row; i++)
    {
        for (int j = 0; j < col; j++)
        {
            val = 0;
            for (int di = -pad; di < pad + 1; di++)
            {
                for (int dj = -pad; dj < pad + 1; dj++)
                {
                    if (((di + i) >= 0) && ((di + i) < row) && ((dj + j) >= 0) && ((dj + j) < col))
                    {
                        val += img.at<uchar>(i + di, j + dj) * kernel[di + pad][dj + pad];
                    }
                }
            }
            val = fmax(val, 0);
            val = fmin(val, 255);
            new_image.at<uchar>(i, j) = (uchar)val;
        }
    }

    return new_image;
}

输入图像 (fate.jpeg)纵向滤波图像 (fate_diff_v.jpeg)横向滤波图像 (fate_diff_h.jpeg)

Sobel滤波器可以提取特定方向(纵向或横向)的边缘,滤波器按下式定义:

纵向:
K = [ 1 2 1 0 0 0 − 1 − 2 − 1 ] K=\left[ \begin{matrix} 1&2&1\ 0&0&0\ -1&-2&-1 \end{matrix} \right]K =​1 0 −1 ​2 0 −2 ​1 0 −1 ​​
横向:
K = [ 1 0 − 1 2 0 − 2 1 0 − 1 ] K=\left[ \begin{matrix} 1&0&-1\ 2&0&-2\ 1&0&-1 \end{matrix} \right]K =​1 2 1 ​0 0 0 ​−1 −2 −1 ​​


cv::Mat sobel_filter(cv::Mat img, int kernel_size, bool horizontal)
{
    int row = img.rows;
    int col = img.cols;

    cv::Mat new_image = cv::Mat::zeros(row, col, CV_8UC1);

    int pad = floor(kernel_size / 2);
    int kernel[3][3] = {{1, 2, 1}, {0, 0, 0}, {-1, -2, -1}};

    if (horizontal){
        kernel[0][1] = 0;
        kernel[2][1] = 0;
        kernel[1][0] = 2;
        kernel[1][2] = -2;
    }

    double val = 0;
    for (int i = 0; i < row; i++)
    {
        for (int j = 0; j < col; j++)
        {
            val = 0;
            for (int di = -pad; di < pad + 1; di++)
            {
                for (int dj = -pad; dj < pad + 1; dj++)
                {
                    if (((di + i) >= 0) && ((di + i) < row) && ((dj + j) >= 0) && ((dj + j) < col))
                    {
                        val += img.at<uchar>(i + di, j + dj) * kernel[di + pad][dj + pad];
                    }
                }
            }
            val = fmax(val, 0);
            val = fmin(val, 255);
            new_image.at<uchar>(i, j) = (uchar)val;
        }
    }

    return new_image;
}

输入图像 (fate.jpeg)纵向滤波图像 (fate_sobel_v.jpeg)横向滤波图像 (fate_sobel_h.jpeg)

Prewitt滤波器是用于边缘检测的一种滤波器,使用下式定义:

纵向:
K = [ − 1 − 1 − 1 0 0 0 1 1 1 ] K=\left[ \begin{matrix} -1&-1&-1\ 0&0&0\ 1&1&1 \end{matrix} \right]K =​−1 0 1 ​−1 0 1 ​−1 0 1 ​​
横向:
K = [ − 1 0 − 1 − 1 0 1 − 1 0 1 ] K=\left[ \begin{matrix} -1&0&-1\ -1&0&1\ -1&0&1 \end{matrix} \right]K =​−1 −1 −1 ​0 0 0 ​−1 1 1 ​​


cv::Mat prewitt_filter(cv::Mat img, int kernel_size, bool horizontal)
{
    int row = img.rows;
    int col = img.cols;

    cv::Mat new_image = cv::Mat::zeros(row, col, CV_8UC1);

    int pad = floor(kernel_size / 2);
    int kernel[3][3] = {{-1, -1, -1}, {0, 0, 0}, {1, 1, 1}};

    if (horizontal){
        kernel[0][1] = 0;
        kernel[0][2] = 1;
        kernel[1][0] = -1;
        kernel[1][2] = 1;
        kernel[2][0] = -1;
        kernel[2][1] = 0;
    }

    double val = 0;
    for (int i = 0; i < row; i++)
    {
        for (int j = 0; j < col; j++)
        {
            val = 0;
            for (int di = -pad; di < pad + 1; di++)
            {
                for (int dj = -pad; dj < pad + 1; dj++)
                {
                    if (((di + i) >= 0) && ((di + i) < row) && ((dj + j) >= 0) && ((dj + j) < col))
                    {
                        val += img.at<uchar>(i + di, j + dj) * kernel[di + pad][dj + pad];
                    }
                }
            }
            val = fmax(val, 0);
            val = fmin(val, 255);
            new_image.at<uchar>(i, j) = (uchar)val;
        }
    }

    return new_image;
}

输入图像 (fate.jpeg)纵向滤波图像 (fate_prewitt_v.jpeg)横向滤波图像 (fate_prewitt_h.jpeg)

Laplacian滤波器是对图像亮度进行二次微分从而检测边缘的滤波器。由于数字图像是离散的,x x x方向和y y y方向的一次微分分别按照以下式子计算:
I x ( x , y ) = I ( x + 1 , y ) − I ( x , y ) ( x + 1 ) − x = I ( x + 1 , y ) − I ( x , y ) I y ( x , y ) = I ( x , y + 1 ) − I ( x , y ) ( y + 1 ) − y = I ( x , y + 1 ) − I ( x , y ) I_x(x,y)=\frac{I(x+1,y)-I(x,y)}{(x+1)-x}=I(x+1,y)-I(x,y)\ I_y(x,y) =\frac{I(x, y+1) – I(x,y)}{(y+1)-y}= I(x, y+1) – I(x,y)I x ​(x ,y )=(x +1 )−x I (x +1 ,y )−I (x ,y )​=I (x +1 ,y )−I (x ,y )I y ​(x ,y )=(y +1 )−y I (x ,y +1 )−I (x ,y )​=I (x ,y +1 )−I (x ,y )
因此二次微分按照以下式子计算:
I x x ( x , y ) = I x ( x , y ) − I x ( x − 1 , y ) x − ( x − 1 ) = I x ( x , y ) − I x ( x − 1 , y ) = [ I ( x + 1 , y ) − I ( x , y ) ] − [ I ( x , y ) − I ( x − 1 , y ) ] = I ( x + 1 , y ) − 2 I ( x , y ) + I ( x − 1 , y ) I_{xx}(x,y) =\frac{I_x(x,y) – I_x(x-1,y)}{x – (x-1)} =I_x(x,y) – I_x(x-1,y)\ =[I(x+1, y) – I(x,y)] – [I(x, y) – I(x-1,y)]= I(x+1,y) – 2\ I(x,y) + I(x-1,y)I xx ​(x ,y )=x −(x −1 )I x ​(x ,y )−I x ​(x −1 ,y )​=I x ​(x ,y )−I x ​(x −1 ,y )=[I (x +1 ,y )−I (x ,y )]−[I (x ,y )−I (x −1 ,y )]=I (x +1 ,y )−2 I (x ,y )+I (x −1 ,y )
同理:
I y y ( x , y ) = I ( x , y + 1 ) − 2 I ( x , y ) + I ( x , y − 1 ) I_{yy}(x,y)=I(x,y+1)-2\ I(x,y)+I(x,y-1)I yy ​(x ,y )=I (x ,y +1 )−2 I (x ,y )+I (x ,y −1 )
特此,Laplacian 表达式如下:
∇ 2 I ( x , y ) = I x x ( x , y ) + I y y ( x , y ) = I ( x − 1 , y ) + I ( x , y − 1 ) − 4 ∗ I ( x , y ) + I ( x + 1 , y ) + I ( x , y + 1 ) \nabla^2\ I(x,y)=I_{xx}(x,y)+I_{yy}(x,y)=I(x-1,y) + I(x,y-1) – 4 * I(x,y) + I(x+1,y) + I(x,y+1)∇2 I (x ,y )=I xx ​(x ,y )+I yy ​(x ,y )=I (x −1 ,y )+I (x ,y −1 )−4 ∗I (x ,y )+I (x +1 ,y )+I (x ,y +1 )
如果把这个式子表示为卷积核是下面这样的:
K = [ 0 1 0 1 − 4 1 0 1 0 ] K= \left[ \begin{matrix} 0&1&0\ 1&-4&1\ 0&1&0 \end{matrix} \right]K =​0 1 0 ​1 −4 1 ​0 1 0 ​​


#include
#include
#include

cv::Mat BGR2GRAY(cv::Mat img)
{

    int row = img.cols;
    int col = img.rows;

    cv::Mat new_image = cv::Mat::zeros(row, col, CV_8UC1);

    for (int i = 0; i < row; i++)
    {
        for (int j = 0; j < col; j++)
        {

            new_image.at<uchar>(i, j) = 0.2126 * (float)img.at<cv::Vec3b>(i, j)[2] \
        + 0.7152 * (float)img.at<cv::Vec3b>(i, j)[1] \
        + 0.0722 * (float)img.at<cv::Vec3b>(i, j)[0];
        }
    }
    return new_image;
}

cv::Mat laplacian_filter(cv::Mat img, int kernel_size)
{
    int row = img.rows;
    int col = img.cols;

    cv::Mat new_image = cv::Mat::zeros(row, col, CV_8UC1);

    int pad = floor(kernel_size / 2);
    int kernel[3][3] = {{0, 1, 0}, {1, -4, 1}, {0, 1, 0}};

    double val = 0;
    for (int i = 0; i < row; i++)
    {
        for (int j = 0; j < col; j++)
        {
            val = 0;
            for (int di = -pad; di < pad + 1; di++)
            {
                for (int dj = -pad; dj < pad + 1; dj++)
                {
                    if (((di + i) >= 0) && ((di + i) < row) && ((dj + j) >= 0) && ((dj + j) < col))
                    {
                        val += img.at<uchar>(i + di, j + dj) * kernel[di + pad][dj + pad];
                    }
                }
            }
            val = fmax(val, 0);
            val = fmin(val, 255);
            new_image.at<uchar>(i, j) = (uchar)val;
        }
    }

    return new_image;
}

int main(){

    cv::Mat img = cv::imread("../fate.jpeg", cv::IMREAD_COLOR);

    cv::Mat gray = BGR2GRAY(img);

    cv::Mat new_image = laplacian_filter(gray, 3);

    cv::imwrite("../fate_laplacian.jpeg", new_image);
    cv::imshow("vv", new_image);

    cv::waitKey(0);
    cv::destroyAllWindows();

    return 0;
}

输入图像 (fate.jpeg)laplacian滤波图像 (fate_laplacianjpeg)

Emboss滤波器可以使物体轮廓更加清晰,定义如下:
K = [ − 2 − 1 0 − 1 1 1 0 1 2 ] K= \left[ \begin{matrix} -2&-1&0\ -1&1&1\ 0&1&2 \end{matrix} \right]K =​−2 −1 0 ​−1 1 1 ​0 1 2 ​​


#include
#include
#include

cv::Mat BGR2GRAY(cv::Mat img)
{

    int row = img.cols;
    int col = img.rows;

    cv::Mat new_image = cv::Mat::zeros(row, col, CV_8UC1);

    for (int i = 0; i < row; i++)
    {
        for (int j = 0; j < col; j++)
        {

            new_image.at<uchar>(i, j) = 0.2126 * (float)img.at<cv::Vec3b>(i, j)[2] \
        + 0.7152 * (float)img.at<cv::Vec3b>(i, j)[1] \
        + 0.0722 * (float)img.at<cv::Vec3b>(i, j)[0];
        }
    }
    return new_image;
}

cv::Mat emboss_filter(cv::Mat img, int kernel_size)
{
    int row = img.rows;
    int col = img.cols;

    cv::Mat new_image = cv::Mat::zeros(row, col, CV_8UC1);

    int pad = floor(kernel_size / 2);
    int kernel[3][3] = {{-2, -1, 0}, {-1, 1, 1}, {0, 1, 2}};

    double val = 0;
    for (int i = 0; i < row; i++)
    {
        for (int j = 0; j < col; j++)
        {
            val = 0;
            for (int di = -pad; di < pad + 1; di++)
            {
                for (int dj = -pad; dj < pad + 1; dj++)
                {
                    if (((di + i) >= 0) && ((di + i) < row) && ((dj + j) >= 0) && ((dj + j) < col))
                    {
                        val += img.at<uchar>(i + di, j + dj) * kernel[di + pad][dj + pad];
                    }
                }
            }
            val = fmax(val, 0);
            val = fmin(val, 255);
            new_image.at<uchar>(i, j) = (uchar)val;
        }
    }

    return new_image;
}

int main(){

    cv::Mat img = cv::imread("../fate.jpeg", cv::IMREAD_COLOR);

    cv::Mat gray = BGR2GRAY(img);

    cv::Mat new_image = emboss_filter(gray, 3);

    cv::imwrite("../1-10/fate_emboss.jpeg", new_image);
    cv::imshow("vv", new_image);

    cv::waitKey(0);
    cv::destroyAllWindows();

    return 0;
}

输入图像 (fate.jpeg)emboss滤波图像 (fate_emboss.jpeg)

Original: https://blog.csdn.net/hahahanba/article/details/123449674
Author: hahahanba
Title: 常用的边缘检测滤波器

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/640718/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球