opencv给图像加水印不改变背景像素值

opencv给图像加水印,简单粗暴的办法是直接用addWeighted函数,但是这会导致背景也会乘以一个权重值,使得背景变暗,比如:

#include <opencv2/opencv.hpp>

using namespace std;
using namespace cv;

int AddWatermarkEasy(Mat &img, Mat &mark)
{
	if (img.empty() || mark.empty())
		return 0;

	//水印素材白色部分置0
	for (int i = 0; i < mark.cols; i++)
	{
		for (int j = 0; j < mark.rows; j++)
		{
			if (mark.at<Vec3b>(j, i)[0] >= 200 && mark.at<Vec3b>(j, i)[1] >= 200 && mark.at<Vec3b>(j, i)[2] >= 200)
			{
				mark.at<Vec3b>(j, i)[0] = 0;
				mark.at<Vec3b>(j, i)[1] = 0;
				mark.at<Vec3b>(j, i)[2] = 0;
			}
		}
	}

	Mat t_mat; //水印的变换矩阵
	Point center = Point(mark.cols / 2, mark.rows / 2); //旋转中心
	float angle = 20; //旋转角
	float scale = 0.8; //缩放尺度
	t_mat = getRotationMatrix2D(center, angle, scale); //旋转and缩放矩阵
	int colMove = 0.2 * img.cols; //水平平移
	int rowMove = 0.1 * img.rows; //垂直平移
	t_mat.at<double>(0, 2) = t_mat.at<double>(0, 2) + (img.cols - mark.cols) / 2 + colMove; //水平平移量
	t_mat.at<double>(1, 2) = t_mat.at<double>(1, 2) + (img.rows - mark.rows) / 2 + rowMove; //竖直平移量
	
	cv::warpAffine(mark, mark, t_mat, img.size(), INTER_LINEAR, BORDER_CONSTANT, Scalar(0, 0, 0)); //对水印做变换
	
	float alpha = 0.5; //水印透明度
	cv::addWeighted(img, 1 - alpha, mark, alpha, 0, img);

	return 1;
}

void main()
{
	Mat img = imread("E:\\bg.jpg");
	imshow("原始背景", img);

	Mat mark = imread("E:\\mark.jpg");
	imshow("水印素材", mark);

	AddWatermarkEasy(img, mark);

	imshow("加水印", img);
	waitKey(0);
	
}

结果如下,可以看出加了水印后背景变暗了:

一个解决办法是做个mask,只对有水印的部分做权重操作,代码如下:

#include <opencv2/opencv.hpp>

using namespace std;
using namespace cv;

int AddWatermark(Mat &img, Mat &mark)
{
	if (img.empty() || mark.empty())
		return 0;

	Mat maskA = Mat::ones(mark.size(), CV_8UC1);

	//水印素材白色部分置0 并做一个水印的mask
	for (int i = 0; i < mark.cols; i++)
	{
		for (int j = 0; j < mark.rows; j++)
		{
			if (mark.at<Vec3b>(j, i)[0] >= 200 && mark.at<Vec3b>(j, i)[1] >= 200 && mark.at<Vec3b>(j, i)[2] >= 200)
			{
				mark.at<Vec3b>(j, i)[0] = 0;
				mark.at<Vec3b>(j, i)[1] = 0;
				mark.at<Vec3b>(j, i)[2] = 0;
				maskA.at<uchar>(j, i) = 0;
			}
		}
	}

	Mat t_mat; //水印的变换矩阵
	Point center = Point(mark.cols / 2, mark.rows / 2); //旋转中心
	float angle = 30; //旋转角
	float scale = 0.8; //缩放尺度
	t_mat = getRotationMatrix2D(center, angle, scale); //旋转and缩放矩阵
	int colMove = 0.2 * img.cols; //水平平移
	int rowMove = 0.2 * img.rows; //垂直平移
	t_mat.at<double>(0, 2) = t_mat.at<double>(0, 2) + (img.cols - mark.cols) / 2 + colMove; //水平平移量
	t_mat.at<double>(1, 2) = t_mat.at<double>(1, 2) + (img.rows - mark.rows) / 2 + rowMove; //竖直平移量

	cv::warpAffine(mark, mark, t_mat, img.size(), INTER_LINEAR, BORDER_CONSTANT, Scalar(0, 0, 0)); //对水印做变换
	cv::warpAffine(maskA, maskA, t_mat, img.size(), INTER_LINEAR, BORDER_CONSTANT, 0); //对maskA做变换

	//maskA取反生成maskB
	Mat maskB = Mat::zeros(maskA.size(), CV_8UC1);
	for (int i = 0; i < maskA.cols; i++)
	{
		for (int j = 0; j < maskA.rows; j++)
		{
			if (maskA.at<uchar>(j, i) == 0)
			{
				maskB.at<uchar>(j, i) = 1;
			}
		}
	}

	vector<Mat> channelA, channelB;
	Mat mv[3], imgA, imgB;
	cv::split(img, mv); //三通道分离
	channelA.push_back(mv[0].mul(maskA)); //分别乘以maskA
	channelA.push_back(mv[1].mul(maskA));
	channelA.push_back(mv[2].mul(maskA));
	channelB.push_back(mv[0].mul(maskB)); //分别乘以maskB
	channelB.push_back(mv[1].mul(maskB));
	channelB.push_back(mv[2].mul(maskB));
	cv::merge(channelA, imgA); //合并通道 imgA为水印部分
	cv::merge(channelB, imgB); //合并通道 imgB为非水印部分

	float alpha = 0.5; //水印透明度
	cv::addWeighted(imgA, 1 - alpha, mark, alpha, 0, imgA);
	cv::add(imgB, imgA, img);

	return 1;
}

void main()
{
	Mat img = imread("E:\\bg.jpg");
	imshow("原始背景", img);

	Mat mark = imread("E:\\mark.jpg");
	imshow("水印素材", mark);

	AddWatermark(img, mark);

	imshow("加水印", img);
	waitKey(0);
	
}

效果如下:

猜你喜欢

转载自blog.csdn.net/oZincO/article/details/89678544