在前面的博客中,提到了
卷积操作与相关操作
,
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观察值得变化。