OpenCV C++案例实战十七《图像去水印》


前言

一、水印定位

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

Mat gray;
	cvtColor(src, gray, COLOR_BGR2GRAY);

	//图像二值化,筛选出白色区域部分
	Mat thresh;
	threshold(gray, thresh, 220, 255, THRESH_BINARY);
//提取图片下方的水印,制作掩模图像
	Mat mask = Mat::zeros(src.size(), CV_8U);
	int height = src.rows;
	int width = src.cols;
	int start = 0.9*height;
	//遍历图像像素,提取出水印部分像素,制作掩模图像
	for (int i = start; i < height; i++)
	{
          
   
		uchar*data = thresh.ptr<uchar>(i);
		for (int j = 0; j < width; j++)
		{
          
   
			if (data[j] == 255)
			{
          
   
				mask.at<uchar>(i, j) = 255;			
			}			
		}
	}

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

二、图像修复

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

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

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

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

三、效果显示

四、源码

#include<iostream>
#include<opencv2/opencv.hpp>
using namespace std;
using namespace cv;

/*
void inpaint(
		InputArray src,   原图
		InputArray inpaintMask, 二进制掩模,指示要修复的像素
		OutputArray dst,  目标图像
		double inpaintRadius, 像素周围的邻域补绘。通常,如果要修复的区域很小,则使用较小的值仅产生较少模糊
		int flags     INPAINT_NS  或 INPAINT_TELEA
		)
*/

/*
图像简单水印去除:定位到水印所在位置,将水印部分提取出来制作二进制掩模图像,使用inpaint API进行图像修复
*/

int main()
{
          
   
	Mat src = imread("test.jpg");
	if (src.empty())
	{
          
   
		cout << "No Image!" << endl;
		system("pause");
		return -1;
	}

	Mat gray;
	cvtColor(src, gray, COLOR_BGR2GRAY);

	//图像二值化,筛选出白色区域部分
	Mat thresh;
	threshold(gray, thresh, 220, 255, THRESH_BINARY);

	//提取图片下方的水印,制作掩模图像
	Mat mask = Mat::zeros(src.size(), CV_8U);
	int height = src.rows;
	int width = src.cols;
	int start = 0.9*height;
	//遍历图像像素,提取出水印部分像素,制作掩模图像
	for (int i = start; i < height; i++)
	{
          
   
		uchar*data = thresh.ptr<uchar>(i);
		for (int j = 0; j < width; j++)
		{
          
   
			if (data[j] == 255)
			{
          
   
				mask.at<uchar>(i, j) = 255;			
			}			
		}
	}

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

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

	imshow("mask", mask);
	imshow("test", result);
	waitKey(0);
	system("pause");
	return 0;
}

总结

本文使用OpenCV C++ 进行简单图像水印去除,关键步骤有以下几点。 1、定位水印位置,制作二值掩模图像。 2、进行图像像素修复。

经验分享 程序员 微信小程序 职场和发展