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

在前面的博客中,提到了卷积操作与相关操作cv::filter2D指的是图像相关操作,所以本博客直接调用此函数,不再使用代码复现相关操作。
图像的一些定义如下,具体操作请参考冈萨雷斯的数字图像处理:

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

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

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

对于一维函数f(x),
一阶微分: fx=f(x+1)f(x) ∂ f ∂ x = f ( x + 1 ) − f ( x )
二阶微分: 2fx2=f(x+1)+f(x1)2f(x) ∂ 2 f ∂ x 2 = f ( x + 1 ) + f ( x − 1 ) − 2 f ( x )

二维函数 f(x,y) f ( x , y ) :
对x的二阶导数: 2fx2=f(x+1,y)+f(x1,y)2f(x,y) ∂ 2 f ∂ x 2 = f ( x + 1 , y ) + f ( x − 1 , y ) − 2 f ( x , y )
对y的二阶导数: 2fy2=f(x,y+1)+f(x,y1)2f(x,y) ∂ 2 f ∂ y 2 = f ( x , y + 1 ) + f ( x , y − 1 ) − 2 f ( x , y )

拉普拉斯算子:
2f(x,y)=2fx2+2fy2 ∇ 2 f ( x , y ) = ∂ 2 f ∂ x 2 + ∂ 2 f ∂ y 2
2f(x,y)=f(x+1,y)+f(x1,y)+f(x,y+1)+f(x,y1)4f(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观察值得变化。

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值