文章目录
Laplacian算子说明
普拉斯算子是最简单的各向同性微分算子,具有旋转不变性。一个二维图像函数 的拉普拉斯变换是各向同性的二阶导数,定义为:
在一个二维函数f(x,y)中,x,y两个方向的二阶差分分别为,
为了更适合于数字图像处理,将该方程表示为离散形式:
写成filter mask的形式如下,
注意该(a)的mask的特点,mask在上下左右四个90度的方向上结果相同,也就是说在90度方向上无方向性。为了让该mask在45度的方向上也具有该性质,对该filter mask进行扩展定义为(b)。
将Laplace算子写成filter mask后,其操作大同小异于其他的空间滤波操作。将filter mask在原图上逐行移动,然后mask中数值与其重合的像素相乘后求和,赋给与mask中心重合的像素,对图像的第一,和最后的行和列无法做上述操作的像素赋值零,就得到了拉普拉斯操作结果。
OpenCV Laplacian函数说明
函数介绍
Imgproc.Laplacian(Mar src, Mat dst, int ddepth, int ksize, double scale, double delta, int borderType);
src :图片
dst :目标图
ddepth :目标图像的深度。因为输入图像一般为CV_8U,为了避免数据溢出,输出图像深度应该设置为CV_16S
ksize : 内核尺寸
scale : 计算Laplacian的时候可选的比例因子,默认为1。具体说明在下面讲述
delta : 额外加的数值,就是在卷积过程中该数值会添加到每个像素上。具体说明在下面讲述
borderType : 边界填充方式。默认BORDER_DEFAULT。边界填充说明
OpenCV Laplacian源码
下面的代码选自Opencv2.4.9源码文件opencv\sources\modules\imgproc\src文件夹下的deriv.cpp文件,该cpp文件中的Laplacian(…)函数源码,下面只显示了ksize=1or3的情况,
void cv::Laplacian( InputArray _src, OutputArray _dst, int ddepth, int ksize,
double scale, double delta, int borderType )
{
Mat src = _src.getMat();
if (ddepth < 0)
ddepth = src.depth();
_dst.create( src.size(), CV_MAKETYPE(ddepth, src.channels()) );
Mat dst = _dst.getMat();
if( ksize == 1 || ksize == 3 )
{
float K[2][9] =
{{0, 1, 0, 1, -4, 1, 0, 1, 0},
{2, 0, 2, 0, -8, 0, 2, 0, 2}};
Mat kernel(3, 3, CV_32F, K[ksize == 3]);
if( scale != 1 )
kernel *= scale;
filter2D( src, dst, ddepth, kernel, Point(-1,-1), delta, borderType );
}else
{
//ksize等于其他值的情况
}
}
函数效果
代码
public static void main(String[] args) {
//读入图片
Mat src = Imgcodecs.imread("G:\\opencvPhoto\\photo\\timg.jpg");
//Laplacian算子对噪音敏感,事先去噪
Imgproc.GaussianBlur(src, src, new Size(3, 3), 0);
//灰度化
Imgproc.cvtColor(src, src, Imgproc.COLOR_BGR2GRAY);
Mat dst = new Mat();
Imgproc.Laplacian(src, dst, CvType.CV_16S, 3, 1, 0, Core.BORDER_DEFAULT);
Imgcodecs.imwrite("G:\\opencvPhoto\\result\\dst.jpg", dst);
}
原图
效果
运行原理
- 以OpenCV的Laplacian内核大小为3时的内核为例
- filter2D函数说明
public static void main(String[] args) {
//读入图片
Mat src = Imgcodecs.imread("G:\\opencvPhoto\\photo\\picture2.jpg");
//Laplacian算子对噪音敏感,事先去噪
Imgproc.GaussianBlur(src, src, new Size(3, 3), 0);
//灰度化
Imgproc.cvtColor(src, src, Imgproc.COLOR_BGR2GRAY);
//OpenCV自带的Laplacian函数
Mat temp = new Mat();
Imgproc.Laplacian(src, temp, CvType.CV_16S, 3, 1, 0, Core.BORDER_DEFAULT);
//手动实现
//内核
Mat kernel = new Mat(new Size(3,3), CvType.CV_32F, new Scalar(255));
kernel.put(0, 0, 2); kernel.put(0, 1, 0); kernel.put(0, 2, 2);
kernel.put(1, 0, 0); kernel.put(1, 1, -8); kernel.put(1, 2, 0);
kernel.put(2, 0, 2); kernel.put(2, 1, 0); kernel.put(2, 2, 2);
Mat dst = new Mat();
Imgproc.filter2D(src, dst, CvType.CV_16S, kernel, new Point(-1, -1), 0, Core.BORDER_DEFAULT);
//验证图片是否相同
boolean flag = true;
for (int row = 0; row < dst.rows(); row++) {
for (int col = 0; col < dst.cols(); col++) {
if (temp.get(row, col)[0] != dst.get(row, col)[0]) {
flag = false;
break;
}
}
if (!flag) {
break;
}
}
System.out.println(flag);
}
结果输出
OpenCV Laplacian 参数说明
scale
public static void main(String[] args) {
//图片
Mat src = new Mat(new Size(3, 3), CvType.CV_8UC1);
src.put(0, 0, 1); src.put(0, 1, 2); src.put(0, 2, 3);
src.put(1, 0, 4); src.put(1, 1, 5); src.put(1, 2, 6);
src.put(2, 0, 7); src.put(2, 1, 8); src.put(2, 2, 9);
Mat dst1 = new Mat();
Imgproc.Laplacian(src, dst1, CvType.CV_16S, 1, 1, 0, Core.BORDER_DEFAULT);
System.out.println("------------------scale=1---------------------");
for (int row = 0; row < dst1.rows(); row++) {
for (int col = 0; col < dst1.cols(); col++) {
System.out.print(dst1.get(row, col)[0] + " ");
}
System.out.println();
}
Mat dst2 = new Mat();
Imgproc.Laplacian(src, dst2, CvType.CV_16S, 1, 2, 0, Core.BORDER_DEFAULT);
System.out.println("------------------scale=2---------------------");
for (int row = 0; row < dst2.rows(); row++) {
for (int col = 0; col < dst2.cols(); col++) {
System.out.print(dst2.get(row, col)[0] + " ");
}
System.out.println();
}
Mat dst3 = new Mat();
Imgproc.Laplacian(src, dst3, CvType.CV_16S, 1, 3, 0, Core.BORDER_DEFAULT);
System.out.println("------------------scale=3---------------------");
for (int row = 0; row < dst3.rows(); row++) {
for (int col = 0; col < dst3.cols(); col++) {
System.out.print(dst3.get(row, col)[0] + " ");
}
System.out.println();
}
}
结果输出
------------------scale=1---------------------
8.0 6.0 4.0
2.0 0.0 -2.0
-4.0 -6.0 -8.0
------------------scale=2---------------------
16.0 12.0 8.0
4.0 0.0 -4.0
-8.0 -12.0 -16.0
------------------scale=3---------------------
24.0 18.0 12.0
6.0 0.0 -6.0
-12.0 -18.0 -24.0
结论:scale为目标图片在计算后得出的结果上再翻scale倍
delta
public static void main(String[] args) {
//图片
Mat src = new Mat(new Size(3, 3), CvType.CV_8UC1);
src.put(0, 0, 1); src.put(0, 1, 2); src.put(0, 2, 3);
src.put(1, 0, 4); src.put(1, 1, 5); src.put(1, 2, 6);
src.put(2, 0, 7); src.put(2, 1, 8); src.put(2, 2, 9);
Mat dst1 = new Mat();
Imgproc.Laplacian(src, dst1, CvType.CV_16S, 1, 1, 0, Core.BORDER_DEFAULT);
System.out.println("------------------delta=0---------------------");
for (int row = 0; row < dst1.rows(); row++) {
for (int col = 0; col < dst1.cols(); col++) {
System.out.print(dst1.get(row, col)[0] + " ");
}
System.out.println();
}
Mat dst2 = new Mat();
Imgproc.Laplacian(src, dst2, CvType.CV_16S, 1, 1, 0, Core.BORDER_DEFAULT);
System.out.println("------------------delta=1---------------------");
for (int row = 0; row < dst2.rows(); row++) {
for (int col = 0; col < dst2.cols(); col++) {
System.out.print(dst2.get(row, col)[0] + " ");
}
System.out.println();
}
Mat dst3 = new Mat();
Imgproc.Laplacian(src, dst3, CvType.CV_16S, 1, 1, 2, Core.BORDER_DEFAULT);
System.out.println("------------------delta=2---------------------");
for (int row = 0; row < dst3.rows(); row++) {
for (int col = 0; col < dst3.cols(); col++) {
System.out.print(dst3.get(row, col)[0] + " ");
}
System.out.println();
}
}
结果输出
------------------delta=0---------------------
8.0 6.0 4.0
2.0 0.0 -2.0
-4.0 -6.0 -8.0
------------------delta=1---------------------
9.0 7.0 5.0
3.0 1.0 -1.0
-3.0 -5.0 -7.0
------------------delta=2---------------------
10.0 8.0 6.0
4.0 2.0 0.0
-2.0 -4.0 -6.0
结论:delta为目标图片在计算后得出的结果上再加delta
scale和delta综合验证
public static void main(String[] args) {
//图片
Mat src = new Mat(new Size(3, 3), CvType.CV_8UC1);
src.put(0, 0, 1); src.put(0, 1, 2); src.put(0, 2, 3);
src.put(1, 0, 4); src.put(1, 1, 5); src.put(1, 2, 6);
src.put(2, 0, 7); src.put(2, 1, 8); src.put(2, 2, 9);
//OpenCV自带的Laplacian函数
Mat dst1 = new Mat();
Imgproc.Laplacian(src, dst1, CvType.CV_16S, 1, 1, 0, Core.BORDER_DEFAULT);
System.out.println("------------------scale=1,delta=0---------------------");
for (int row = 0; row < dst1.rows(); row++) {
for (int col = 0; col < dst1.cols(); col++) {
System.out.print(dst1.get(row, col)[0] + " ");
}
System.out.println();
}
Mat dst2 = new Mat();
Imgproc.Laplacian(src, dst2, CvType.CV_16S, 1, 2, 3, Core.BORDER_DEFAULT);
System.out.println("------------------scale=2,delta=3---------------------");
for (int row = 0; row < dst2.rows(); row++) {
for (int col = 0; col < dst2.cols(); col++) {
System.out.print(dst2.get(row, col)[0] + " ");
}
System.out.println();
}
}
结果输出
------------------scale=1,delta=0---------------------
8.0 6.0 4.0
2.0 0.0 -2.0
-4.0 -6.0 -8.0
------------------scale=2,delta=3---------------------
19.0 15.0 11.0
7.0 3.0 -1.0
-5.0 -9.0 -13.0
过程说明
8*2+3 6*2+3 4*2+3
2*2+3 0*2+3 -2*2+3
-4*2+3 -6*2+3 -8*2+3
参考链接
https://www.cnblogs.com/polly333/p/7269843.html
https://blog.csdn.net/u010551600/article/details/80357267