opencv给图像加水印,简单粗暴的办法是直接用addWeighted函数,但是这会导致背景也会乘以一个权重值,使得背景变暗,比如:
#include
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(j, i)[0] >= 200 && mark.at(j, i)[1] >= 200 && mark.at(j, i)[2] >= 200)
{
mark.at(j, i)[0] = 0;
mark.at(j, i)[1] = 0;
mark.at(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(0, 2) = t_mat.at(0, 2) + (img.cols - mark.cols) / 2 + colMove; //水平平移量
t_mat.at(1, 2) = t_mat.at(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
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(j, i)[0] >= 200 && mark.at(j, i)[1] >= 200 && mark.at(j, i)[2] >= 200)
{
mark.at(j, i)[0] = 0;
mark.at(j, i)[1] = 0;
mark.at(j, i)[2] = 0;
maskA.at(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(0, 2) = t_mat.at(0, 2) + (img.cols - mark.cols) / 2 + colMove; //水平平移量
t_mat.at(1, 2) = t_mat.at(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(j, i) == 0)
{
maskB.at(j, i) = 1;
}
}
}
vector 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);
}
效果如下: