基于图像的拉普拉斯(Laplacian)二维算子的不同模板代码实现

  • Post author:
  • Post category:其他


在前面的博客中,提到了

卷积操作与相关操作



cv::filter2D

指的是图像相关操作,所以本博客直接调用此函数,不再使用代码复现相关操作。

图像的一些定义如下,具体操作请参考冈萨雷斯的数字图像处理:

数字函数的微分可以用不同的术语定义. 也有各种方法定义这些差异.

然而,对于一阶微分的任何定义都必须保证以下几点:

(1) 在恒定灰度区域的微分值为零;

(2) 在灰度台阶或斜坡处微分值非零;

(3) 沿着斜坡的微分值非零.

类似地,任何二阶微分的定义必须保证以下几点:

(1) 在恒定区域为分支为零;

(2) 在灰度台阶或斜坡的起点处微分值为零。

(3) 沿着斜坡的微分值零. –>这个地方冈萨雷斯资料存在不一致性, 请读者自己核实

因为我们处理的是数字量, 其值是有限的, 故最大灰度级的变化也是有限的, 并且变化发生的最短距离是在两相邻像素之间。

对于一维函数f(x),

一阶微分:
















f















x














=


f




(


x


+


1


)





f




(


x


)










f

x

=

f

(

x

+

1

)

f

(

x

)




二阶微分:

























2









f


















x








2





















=


f




(


x


+


1


)


+


f




(


x





1


)





2


f




(


x


)










2

f

x

2

=

f

(

x

+

1

)

+

f

(

x

1

)

2

f

(

x

)


二维函数







f




(


x


,


y




)










f

(

x

,

y

)



:

对x的二阶导数:

























2









f


















x








2





















=


f




(


x


+


1


,


y




)


+


f




(


x





1


,


y




)





2


f




(


x


,


y




)










2

f

x

2

=

f

(

x

+

1

,

y

)

+

f

(

x

1

,

y

)

2

f

(

x

,

y

)




对y的二阶导数:

























2









f


















y










2





















=


f




(


x


,


y




+


1


)


+


f




(


x


,


y







1


)





2


f




(


x


,


y




)










2

f

y

2

=

f

(

x

,

y

+

1

)

+

f

(

x

,

y

1

)

2

f

(

x

,

y

)


拉普拉斯算子:




















2









f




(


x


,


y




)


=




















2









f


















x








2





















+




















2









f


















y










2





























2

f

(

x

,

y

)

=

2

f

x

2

+

2

f

y

2























2









f




(


x


,


y




)


=


f




(


x


+


1


,


y




)


+


f




(


x





1


,


y




)


+


f




(


x


,


y




+


1


)


+


f




(


x


,


y







1


)





4


f




(


x


,


y




)










2

f

(

x

,

y

)

=

f

(

x

+

1

,

y

)

+

f

(

x

1

,

y

)

+

f

(

x

,

y

+

1

)

+

f

(

x

,

y

1

)

4

f

(

x

,

y

)


代码如下:

/**
数字函数的微分可以用不同的术语定义. 也有各种方法定义这些差异.
然而,对于一阶微分的任何定义都必须保证以下几点:
(1) 在恒定灰度区域的微分值为零;
(2) 在灰度台阶或斜坡处微分值非零;
(3) 沿着斜坡的微分值非零.

类似地,任何二阶微分的定义必须保证以下几点:
(1) 在恒定区域为分支为零;
(2) 在灰度台阶或斜坡的起点处微分值为零。
(3) 沿着斜坡的微分值零.          -->这个地方冈萨雷斯资料存在不一致性, 请核实

因为我们处理的是数字量, 其值是有限的, 故最大灰度级的变化也是有限的, 并且变化发生的最短距离是在两相邻像素之间。

对于一维函数f(x),
一阶微分: \frac{\partial f}{\partial x} = f(x+1) - f(x)
二阶微分: \frac{\partial^{2}f} {\partial x^{2}} = f(x+1) + f(x-1)-2f(x)

二维函数f(x,y):
对x的二阶导数: \frac{\partial^{2}f} {\partial x^{2}}=f(x+1,y)+f(x-1,y)-2f(x,y)
对y的二阶导数:  \frac{\partial^{2}f} {\partial y^{2}} = f(x,y+1)+f(x,y-1)-2f(x,y)


拉普拉斯算子:
\nabla^{2}f(x,y) = \frac{\partial^{2}f} {\partial x^{2}} + \frac{\partial^{2}f} {\partial y^{2}}
\nabla^{2}f(x,y) = f(x+1,y) + f(x-1,y) + f(x,y+1) + f(x,y-1) - 4f(x,y)

程序运行信息:
开发环境: VS2015 + OpenCV 3.4.1 + Windows 10
硬件环境: CPU i7-8750H; RAM 8G; Gpu: GTX1050Ti

*/
#include <string>
#include <vector>
#include "opencv2/opencv.hpp"

static void Differential_2D(const cv::Mat& src, cv::Mat& dst, const cv::Mat& kernel)
{
    CV_Assert(src.type() == CV_8UC1);
    cv::filter2D(src, dst, CV_32F, kernel, cv::Point(-1, -1), cv::BORDER_REPLICATE);
}

void test_image_differential()
{
    std::string path = "../Resources/1-SRC.bmp";

    cv::Mat gray = cv::imread(path, cv::ImreadModes::IMREAD_GRAYSCALE);

    // 标准公式
    cv::Mat dst_I;
    cv::Mat kernel2D_I = (cv::Mat_<float>(3, 3) << 0, 1, 0, 1, -4, 1, 0, 1, 0);
    Differential_2D(gray, dst_I, kernel2D_I);
    cv::imshow("第一种", dst_I);

    // 标准公式 乘以 -1
    cv::Mat dst_II;
    cv::Mat kernel2D_II = (cv::Mat_<float>(3, 3) << 0, -1, 0, -1, 4, -1, 0, -1, 0);
    Differential_2D(gray, dst_II, kernel2D_II);
    cv::imshow("第二种", dst_I);

    // 第三种
    cv::Mat dst_III;
    cv::Mat kernel2D_III = (cv::Mat_<float>(3, 3) << 1, 1, 1, 1, -8, 1, 1, 1, 1);
    Differential_2D(gray, dst_III, kernel2D_III);
    cv::imshow("第三种", dst_III);

    cv::Mat dst_IV;
    cv::Mat kernel2D_IV = (cv::Mat_<float>(3, 3) << -1, -1, -1, -1, 8, -1, -1, -1, -1);
    Differential_2D(gray, dst_IV, kernel2D_IV);
    cv::imshow("第四种", dst_IV);

    cv::Mat dst_V;
    cv::Mat kernel2D_V = (cv::Mat_<float>(3, 3) << -1, -2, -1, 0, 0, 0, 1, 2, 1);
    Differential_2D(gray, dst_V, kernel2D_V);
    cv::imshow("第五种", dst_V);

    cv::imshow("原图", gray);
}

代码的效果运行图为:

这里写图片描述

由于经过计算,某些图像矩阵元素中可能会出现负数或者范围不在[0, 255]之间,建议通过imageWatch观察值得变化。



版权声明:本文为wfh2015原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。