• OpenCV实现图像去水印功能(inpaint)


    水印定位

    需要根据图像特征获取水印的位置。

    如图所示,图像左下角、右下角有水印。第一步,我们首先得定位水印所在位置。

    1. Mat gray;
    2. cvtColor(src, gray, COLOR_BGR2GRAY);
    3. //图像二值化,筛选出白色区域部分
    4. Mat thresh;
    5. threshold(gray, thresh, 220, 255, THRESH_BINARY);

     如图为二值化后得到的效果图。接下来,我们需要提取水印区域的像素。

     

    1. //提取图片下方的水印,制作掩模图像
    2.     Mat mask = Mat::zeros(src.size(), CV_8U);
    3.     int height = src.rows;
    4.     int width = src.cols;
    5.     int start = 0.9*height;
    6.     //遍历图像像素,提取出水印部分像素,制作掩模图像
    7.     for (int i = start; i < height; i++)
    8.     {
    9.         uchar*data = thresh.ptr<uchar>(i);
    10.         for (int j = 0; j < width; j++)
    11.         {
    12.             if (data[j] == 255)
    13.             {
    14.                 mask.at<uchar>(i, j) = 255;            
    15.             }            
    16.         }
    17.     }

     

     如图所示,至此我们已经得到水印部分的二值掩模图像。接下来,使用OpenCV 内置inpaint API进行图像像素修复。

    图像修复

    1. //使用inpaint进行图像修复
    2. Mat result;
    3. inpaint(src, mask, result, 1, INPAINT_NS);

     如图所示,这是直接使用提取出的二值掩模进行图像修复得到的结果,可以看出效果不是很好。原因是,提取出来的掩模未能覆盖完全待修复像素。故我们需要将掩模图像进行膨胀操作,扩大掩模范围。

    1. //将掩模进行膨胀,使其能够覆盖图像更大区域
    2. Mat kernel = getStructuringElement(MORPH_RECT, Size(5, 5));
    3. dilate(mask, mask, kernel);

     如图为进行膨胀过后的掩模图像。这时,我们使用这张掩模图像再进行图像修复工作,得到效果如图所示。

     源码

    1. #include<iostream>
    2. #include<opencv2/opencv.hpp>
    3. using namespace std;
    4. using namespace cv;
    5. /*
    6. void inpaint(
    7.         InputArray src,   原图
    8.         InputArray inpaintMask, 二进制掩模,指示要修复的像素
    9.         OutputArray dst,  目标图像
    10.         double inpaintRadius, 像素周围的邻域补绘。通常,如果要修复的区域很小,则使用较小的值仅产生较少模糊
    11.         int flags     INPAINT_NS  或 INPAINT_TELEA
    12.         )
    13. */
    14. /*
    15. 图像简单水印去除:定位到水印所在位置,将水印部分提取出来制作二进制掩模图像,使用inpaint API进行图像修复
    16. */
    17. int main()
    18. {
    19.     Mat src = imread("test.jpg");
    20.     if (src.empty())
    21.     {
    22.         cout << "No Image!" << endl;
    23.         system("pause");
    24.         return -1;
    25.     }
    26.     Mat gray;
    27.     cvtColor(src, gray, COLOR_BGR2GRAY);
    28.     //图像二值化,筛选出白色区域部分
    29.     Mat thresh;
    30.     threshold(gray, thresh, 220, 255, THRESH_BINARY);
    31.     //提取图片下方的水印,制作掩模图像
    32.     Mat mask = Mat::zeros(src.size(), CV_8U);
    33.     int height = src.rows;
    34.     int width = src.cols;
    35.     int start = 0.9*height;
    36.     //遍历图像像素,提取出水印部分像素,制作掩模图像
    37.     for (int i = start; i < height; i++)
    38.     {
    39.         uchar*data = thresh.ptr<uchar>(i);
    40.         for (int j = 0; j < width; j++)
    41.         {
    42.             if (data[j] == 255)
    43.             {
    44.                 mask.at<uchar>(i, j) = 255;            
    45.             }            
    46.         }
    47.     }
    48.     //将掩模进行膨胀,使其能够覆盖图像更大区域
    49.     Mat kernel = getStructuringElement(MORPH_RECT, Size(5, 5));
    50.     dilate(mask, mask, kernel);
    51.     //使用inpaint进行图像修复
    52.     Mat result;
    53.     inpaint(src, mask, result, 1, INPAINT_NS);
    54.     imshow("mask", mask);
    55.     imshow("test", result);
    56.     waitKey(0);
    57.     system("pause");
    58.     return 0;
    59. }

  • 相关阅读:
    毕业设计-机器学习人眼检测活体检测-opencv
    深究为啥Vue管理的函数不能是箭头函数
    【运维篇】5.6 Redis server 主从复制配置
    在Java中如何优雅的停止一个线程?可别再用Thread.stop()了!
    【网络奇遇记】那年我与计算机网络的初相识 —— 网络的体系结构
    面向开发者的Android
    apisix~lua插件开发与插件注册
    访问控制1
    qt主窗体
    ESP8266-Arduino编程实例-LTR390紫外光传感器驱动
  • 原文地址:https://blog.csdn.net/hulinhulin/article/details/133102302