当前位置:   article > 正文

拉普拉斯噪声公式_(二十四)用二阶微分(拉普拉斯算子)实现图像锐化

一阶差分算子的弱点 为什么要设计二阶微分

f5986799c1b03d84f2dd18a36eb80847.png

时间为友,记录点滴。

我们已经了解过了梯度(一阶微分)的作用,那么为什么要引入二阶微分呢?

二阶微分的作用是什么?

还是看图说话:

7af2a6308583724f1bd04d376ee9b95d.png

很明显,一阶微分已经可以把轮廓辨识出来,但是,对于变化较缓的地方,一阶微分会给出一个比较长的序列,对应到图像上就是轮廓比较“”, 二阶微分只识别跳变的边缘,对应到图像上就是比较“”。而且对像素的陡变的地方,二阶微分会出现有“零交叉”的两个点,这种点对边缘定位非常有作用。

所以,在细节增强方面,二阶微分要比一阶微分好的多。

怎么实现二阶微分?

我在《数字图像处理》中已经介绍了拉普拉斯算子, 简单的说就是对上一章的梯度再做一次梯度:

拉普拉斯在就为我们定义了二阶微分形式,所以我们就直接把它拓展到二维图像

上:

因为任意阶微分都是线性操作,所以拉普拉斯变换也是一个线性算子。为了离散地表达这个共识,我们套用上一章的一个公式变换:

X方向:

Y方向:

综合一下:

有了公式,就容易得到基于拉普拉斯算子的模板:

a93800805e28f4597a1320fab2ee25b3.png

因为拉普拉斯是一种二阶微分算子,因此其强调的是图像中灰度的突变,并不强调图像的缓慢变换区域。这样一些渐变的浅灰色边线就会变成图片轮廓的背景色。如果我们想要保持原图像并且看到增强的边缘图像,可以把原图和拉普拉斯图像简单叠加。

套用以下公式:

为原图
为拉普拉斯处理后的图像
为处理的系数
为最终保持原图像并且增强边缘的图像

好了,有了上面理论做指导,我们实现一下,看看效果。

在OpenCV中,有现成的API可以给我们使用:

  1. CV_EXPORTS_W void Laplacian( InputArray src, OutputArray dst, int ddepth,
  2. int ksize = 1, double scale = 1, double delta = 0,
  3. int borderType = BORDER_DEFAULT );
  • src_gray,输入图像
  • dst,Laplace操作结果
  • ddepth,输出图像深度,因为输入图像一般为CV_8U,为了避免数据溢出,输出图像深度应该设置为CV_16S或者更高
  • kernel_size,filter mask的规模,我们的mask时3x3的,所以这里应该设置为3
  • scale,delta,BORDER_DEFAULT,默认设置就好

C++:

注意点:

1. 因为拉普拉斯是二阶微分,对噪点非常敏感,所以在做锐化之前可以用kernelSize=3的高斯滤波先。
2. 不知道为什么,做出来的拉普拉斯噪声值比较大。
  1. #include <iostream>
  2. #include <string>
  3. #include <opencv2/opencv.hpp>
  4. using namespace std;
  5. using namespace cv;
  6. static bool laplaceTest(Mat imgOri, bool needResize = false, bool needBlur = false);
  7. static void showImgPara(Mat &img);
  8. int main()
  9. {
  10. Mat imgOri = imread("Fig0338(a)(blurry_moon).tif");
  11. laplaceTest(imgOri);
  12. Mat imgGril = imread("Gril.jpg");
  13. //laplaceTest(imgGril, true, false);
  14. waitKey(0);
  15. return true;
  16. }
  17. static bool laplaceTest(Mat imgOri, bool needResize, bool needBlur)
  18. {
  19. Mat imgLaplace, imgLaplaceDelta, imgLaplaceAdd1;
  20. float fx = 0, fy = 0;
  21. showImgPara(imgOri);
  22. imshow("laplaceTest imgOri", imgOri);
  23. if (needBlur)
  24. {
  25. GaussianBlur(imgOri, imgOri, Size(7, 7), 0, 0);
  26. }
  27. if (needResize)
  28. {
  29. resize(imgOri, imgOri, Size(imgOri.cols * 0.5, imgOri.rows * 0.5), fx = 0, fy = 0, INTER_LINEAR);
  30. }
  31. if (1 != imgOri.channels())
  32. {
  33. cvtColor(imgOri, imgOri, COLOR_BGR2GRAY);
  34. }
  35. // Laplace without delta
  36. Laplacian(imgOri, imgLaplace, CV_16S, 3, 1, 0);
  37. convertScaleAbs(imgLaplace, imgLaplace);
  38. imshow("laplaceTest imgLaplace", imgLaplace);
  39. // Laplace with delta
  40. Laplacian(imgOri, imgLaplaceDelta, CV_16S, 3, 1, 100);
  41. convertScaleAbs(imgLaplaceDelta, imgLaplaceDelta);
  42. imshow("laplaceTest imgLaplaceDelta", imgLaplaceDelta);
  43. // Laplace add original
  44. addWeighted(imgOri, 1.0, imgLaplace, -1.0, 0.0, imgLaplaceAdd1, CV_32F);
  45. convertScaleAbs(imgLaplaceAdd1, imgLaplaceAdd1);
  46. imshow("laplaceTest imgLaplaceAdd1", imgLaplaceAdd1);
  47. return true;
  48. }
  49. static void showImgPara(Mat &img)
  50. {
  51. cout << "sizeof(img) is: " << sizeof(img) << ", img size is: " << img.size << endl;
  52. cout << "rows x cols: (" << img.rows << " x " << img.cols << ")" << endl;
  53. cout << "dims: " << img.dims << endl;
  54. cout << "channels: " << img.channels() << endl;
  55. cout << "type: " << img.type() << endl;
  56. cout << "depth:" << img.depth() << endl;
  57. cout << "elemSize:" << img.elemSize() << " (Bytes per element)" << endl;
  58. cout << "elemSize1:" << img.elemSize1() << "(Bytes per channel)" << endl;
  59. cout << "step[0]: " << img.step[0] << " (Bytes per cows only when 2 dims)" << endl;
  60. cout << "step[1]: " << img.step[1] << " (Bytes per element only when 2 dims)" << endl;
  61. cout << "step1(0): " << img.step1(0) << ", step1(1): " << img.step1(1) << " (step / elemSize1)" << endl;
  62. cout << "----- showImgPara End ----n" << endl;
  63. }

运行结果:

535f0e80395a27a958c39f59fd36be47.png

Python:

  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. # author:lowkeyway time:8/24/2019
  4. import sys
  5. import cv2 as cv
  6. import numpy as np
  7. def laplaceTest(imgOri, needResize = False, needBlur = False):
  8. cv.imshow("imgOri", imgOri)
  9. if len(imgOri.shape) is not 2:
  10. imgOri = cv.cvtColor(imgOri, cv.COLOR_BGR2GRAY)
  11. if needResize:
  12. imgOri = cv.resize(imgOri, (int(imgOri.shape[1]*0.5), int(imgOri.shape[0]*0.5)))
  13. if needBlur:
  14. imgOri = cv.GaussianBlur(imgOri, (3, 3), 1)
  15. # Laplace only
  16. imgLap = cv.Laplacian(imgOri, cv.CV_16S)
  17. imgLap = cv.convertScaleAbs(imgLap)
  18. cv.imshow("imglap", imgLap)
  19. # Laplace Delta
  20. imgLapDelta = cv.Laplacian(imgOri, cv.CV_16S, delta=100)
  21. imgLapDelta = cv.convertScaleAbs(imgLapDelta)
  22. cv.imshow("imgLapDelta", imgLapDelta)
  23. # Laplace Add
  24. imgLapAdd = cv.addWeighted(imgOri, 1.0, imgLap, -1.0, 0, dtype=cv.CV_32F)
  25. imgLapAdd = cv.convertScaleAbs(imgLapAdd)
  26. cv.imshow("imgLapAdd", imgLapAdd)
  27. def main_func(argv):
  28. imgMoon = cv.imread("Fig0338(a)(blurry_moon).tif")
  29. # laplaceTest(imgMoon)
  30. imgGril = cv.imread("Gril.jpg")
  31. laplaceTest(imgGril, True, True)
  32. cv.waitKey(0)
  33. if __name__ == '__main__':
  34. main_func(sys.argv)
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/菜鸟追梦旅行/article/detail/72512
推荐阅读
相关标签
  

闽ICP备14008679号