OpenCV图像修复

RapHqi 3年前
   <p>在OpenCV的“photo.hpp”中定义了一个inpaint函数,可以用来实现图像的修复和复原功能,inpaint函数的原型如下:</p>    <pre>  <code class="language-cpp">void inpaint( InputArray src, InputArray inpaintMask,                             OutputArray dst, double inpaintRadius, int flags );</code></pre>    <p>第一个参数src,输入的单通道或三通道图像;</p>    <p>第二个参数inpaintMask,图像的掩码,单通道图像,大小跟原图像一致,inpaintMask图像上除了需要修复的部分之外其他部分的像素值全部为0;</p>    <p>第三个参数dst,输出的经过修复的图像;</p>    <p>第四个参数inpaintRadius,修复算法取的邻域半径,用于计算当前像素点的差值;</p>    <p>第五个参数flags,修复算法,有两种:INPAINT_NS 和I NPAINT_TELEA;</p>    <p> </p>    <p>函数实现关键是图像掩码的确定,可以通过阈值筛选或者手工选定,按照这个思路,用三种方法生成掩码,对比图像修复的效果。</p>    <p><strong>方法一、全区域阈值处理+Mask膨胀处理</strong></p>    <pre>  <code class="language-cpp">#include <imgproc\imgproc.hpp>  #include <highgui\highgui.hpp>  #include <photo\photo.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();  }</code></pre>    <p>原始图像:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/55cc439d25e044a5ae521fa8570d93a4.jpg"></p>    <p>根据阈值处理得到的图像掩码:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/4f394db09596c8a47291fb48559b4104.jpg"></p>    <p>图像复原结果:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/5c309a5887d3d77ec8b8074e0e45a5c6.jpg"></p>    <p>由于是图像全区域做阈值处理获得的掩码,图像上部分区域也被当做掩码对待,导致部分图像受损。</p>    <p><strong>方法二、鼠标框选区域+阈值处理+Mask膨胀处理</strong></p>    <pre>  <code class="language-cpp">#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);   }  }</code></pre>    <p>鼠标圈定的ROI:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/79db62a1fdaab8b5a3f5ea8aaca36d14.jpg"></p>    <p>图像复原结果:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/99589fc8a831fd8d8cb12a262c358abd.jpg"></p>    <p>选定区域之外的图像不受修复影响,没有额外的损伤。</p>    <p><strong>方法三、鼠标划定整个区域作为修复对象</strong></p>    <p>这个方法选定一个矩形区域,把整个矩形区域作为要修复的对象,该方法适用于图像结构比较简单,特别是纯色图像,并且选定区域面积占比不大的情况,效果较好。</p>    <pre>  <code class="language-cpp">#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);   }  }</code></pre>    <p>原始图像:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/14c781e8369f4b8b67f21d3b37626e4c.jpg"></p>    <p>图像复原结果:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/532cd0cbea28a212e10c5e3817d7ccf9.jpg"></p>    <p> </p>    <p>来自:http://blog.csdn.net/dcrmg/article/details/53792061</p>    <p> </p>