OpenCV图像修复

编程实验

72人已加入

描述

  前言

        在实际应用中,我们的图像常常会被噪声腐蚀,这些噪声或是镜头上的灰尘或水滴,或是旧照片的划痕,或者是图像遭到人为的涂画(比如马赛克)或者图像的部分本身已经损坏。如果我们想让这些受到破坏的额图片尽可能恢复到原样,Opencv能帮我们做到吗?

  OpenCV真的有这个妙手回春的功能!别以为图像修补的工作只能用PS或者美图秀秀那些软件去做,其实由程序员自己写代码去做更加高效!

  图像修复技术的原理是什么呢?

  简而言之,就是利用那些已经被破坏的区域的边缘, 即边缘的颜色和结构,根据这些图像留下的信息去推断被破坏的信息区的信息内容,然后对破坏区进行填补 ,以达到图像修补的目的。

  在OpenCV的“photo.hpp”中定义了一个inpaint函数,可以用来实现图像的修复和复原功能,inpaint函数的原型如下:

  void inpaint( InputArray src, InputArray inpaintMask,

  OutputArray dst, double inpaintRadius, int flags );

  第一个参数src,输入的单通道或三通道图像;

  第二个参数inpaintMask,图像的掩码,单通道图像,大小跟原图像一致,inpaintMask图像上除了需要修复的部分之外其他部分的像素值全部为0;

  第三个参数dst,输出的经过修复的图像;

  第四个参数inpaintRadius,修复算法取的邻域半径,用于计算当前像素点的差值;

  第五个参数flags,修复算法,有两种:INPAINT_NS 和I NPAINT_TELEA;

  函数实现关键是图像掩码的确定,可以通过阈值筛选或者手工选定,按照这个思路,用三种方法生成掩码,对比图像修复的效果。

  方法一、全区域阈值处理+Mask膨胀处理

  [cpp] view plain copy print?

  #include 《imgprocimgproc.hpp》

  #include 《highguihighgui.hpp》

  #include 《photophoto.hpp》

  using namespace cv;

  //全区域阈值处理+Mask膨胀处理

  int main()

  {

  Mat imageSource = imread(“Test.jpg”);

  if (!imageSource.data)

  {

  return -1;

  }

  imshow(“原图”, imageSource);

  Mat imageGray;

  //转换为灰度图

  cvtColor(imageSource, imageGray, CV_RGB2GRAY, 0);

  Mat imageMask = Mat(imageSource.size(), CV_8UC1, Scalar::all(0));

  //通过阈值处理生成Mask

  threshold(imageGray, imageMask, 240, 255, CV_THRESH_BINARY);

  Mat Kernel = getStructuringElement(MORPH_RECT, Size(3, 3));

  //对Mask膨胀处理,增加Mask面积

  dilate(imageMask, imageMask, Kernel);

  //图像修复

  inpaint(imageSource, imageMask, imageSource, 5, INPAINT_TELEA);

  imshow(“Mask”, imageMask);

  imshow(“修复后”, imageSource);

  waitKey();

  }

  原始图像:

 

  根据阈值处理得到的图像掩码:

 

  图像复原结果:

 

  由于是图像全区域做阈值处理获得的掩码,图像上部分区域也被当做掩码对待,导致部分图像受损。

  方法二、鼠标框选区域+阈值处理+Mask膨胀处理

  [cpp] view plain copy print?

  #include 《imgproc/imgproc.hpp》

  #include 《highgui/highgui.hpp》

  #include 《core/core.hpp》

  #include 《photo/photo.hpp》

  using namespace cv;

  Point ptL, ptR; //鼠标画出矩形框的起点和终点

  Mat imageSource, imageSourceCopy;

  Mat ROI; //原图需要修复区域的ROI

  //鼠标回调函数

  void OnMouse(int event, int x, int y, int flag, void *ustg);

  //鼠标圈定区域阈值处理+Mask膨胀处理

  int main()

  {

  imageSource = imread(“Test.jpg”);

  if (!imageSource.data)

  {

  return -1;

  }

  imshow(“原图”, imageSource);

  setMouseCallback(“原图”, OnMouse);

  waitKey();

  }

  void OnMouse(int event, int x, int y, int flag, void *ustg)

  {

  if (event == CV_EVENT_LBUTTONDOWN)

  {

  ptL = Point(x, y);

  ptR = Point(x, y);

  }

  if (flag == CV_EVENT_FLAG_LBUTTON)

  {

  ptR = Point(x, y);

  imageSourceCopy = imageSource.clone();

  rectangle(imageSourceCopy, ptL, ptR, Scalar(255, 0, 0));

  imshow(“原图”, imageSourceCopy);

  }

  if (event == CV_EVENT_LBUTTONUP)

  {

  if (ptL != ptR)

  {

  ROI = imageSource(Rect(ptL, ptR));

  imshow(“ROI”, ROI);

  waitKey();

  }

  }

  //单击鼠标右键开始图像修复

  if (event == CV_EVENT_RBUTTONDOWN)

  {

  imageSourceCopy = ROI.clone();

  Mat imageGray;

  cvtColor(ROI, imageGray, CV_RGB2GRAY); //转换为灰度图

  Mat imageMask = Mat(ROI.size(), CV_8UC1, Scalar::all(0));

  //通过阈值处理生成Mask

  threshold(imageGray, imageMask, 235, 255, CV_THRESH_BINARY);

  Mat Kernel = getStructuringElement(MORPH_RECT, Size(3, 3));

  dilate(imageMask, imageMask, Kernel); //对Mask膨胀处理

  inpaint(ROI, imageMask, ROI, 9, INPAINT_TELEA); //图像修复

  imshow(“Mask”, imageMask);

  imshow(“修复后”, imageSource);

  }

  }

  鼠标圈定的ROI:

 

  图像复原结果:

  

  选定区域之外的图像不受修复影响,没有额外的损伤。

  方法三、鼠标划定整个区域作为修复对象

  这个方法选定一个矩形区域,把整个矩形区域作为要修复的对象,该方法适用于图像结构比较简单,特别是纯色图像,并且选定区域面积占比不大的情况,效果较好。

  [cpp] view plain copy print?

  #include 《imgproc/imgproc.hpp》

  #include 《highgui/highgui.hpp》

  #include 《core/core.hpp》

  #include 《photo/photo.hpp》

  using namespace cv;

  Point ptL, ptR; //鼠标画出矩形框的起点和终点

  Mat imageSource, imageSourceCopy;

  Mat ROI; //原图需要修复区域的ROI

  //鼠标回调函数

  void OnMouse(int event, int x, int y, int flag, void *ustg);

  //鼠标圈定区域

  int main()

  {

  imageSource = imread(“Test.jpg”);

  if (!imageSource.data)

  {

  return -1;

  }

  imshow(“原图”, imageSource);

  setMouseCallback(“原图”, OnMouse);

  waitKey();

  }

  void OnMouse(int event, int x, int y, int flag, void *ustg)

  {

  if (event == CV_EVENT_LBUTTONDOWN)

  {

  ptL = Point(x, y);

  ptR = Point(x, y);

  }

  if (flag == CV_EVENT_FLAG_LBUTTON)

  {

  ptR = Point(x, y);

  imageSourceCopy = imageSource.clone();

  rectangle(imageSourceCopy, ptL, ptR, Scalar(255, 0, 0));

  imshow(“原图”, imageSourceCopy);

  }

  if (event == CV_EVENT_LBUTTONUP)

  {

  if (ptL != ptR)

  {

  ROI = imageSource(Rect(ptL, ptR));

  imshow(“ROI”, ROI);

  waitKey();

  }

  }

  //单击鼠标右键开始图像修复

  if (event == CV_EVENT_RBUTTONDOWN)

  {

  imageSourceCopy = Mat(imageSource.size(), CV_8UC1, Scalar::all(0));

  Mat imageMask = imageSourceCopy(Rect(ptL, ptR));

  //生成一个跟ROI大小一样的值全为1的区域

  Mat imageMaskCopy = Mat(imageMask.size(), CV_8UC1, Scalar::all(1));

  imageMaskCopy.copyTo(imageMask);

  inpaint(imageSource, imageSourceCopy, imageSource, 9, INPAINT_TELEA); //图像修复

  imshow(“Mask”, imageSourceCopy);

  imshow(“修复后”, imageSource);

  }

  }

  原始图像:

  

  图像复原结果:

   

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分