Watermarking Images: preserve quality, control opacity
I set myself a task to create a simple OpenCV program to watermark image. The program will overlay a logo on the bottom right of an image. It will place the logo there with full opacity or slightly transparent. I have some questions whether I have done things correctly and what I can improve.
- Q1: How can I control the opacity of the logo when I call
cv::addWeighted()
? I have tried different beta values but they always turn out the same more or less - Q2: Does my code preserve the image quality? I don't think it does, for example; the image I load in is 2mb and when I watermark then save it as a JPEG it is 100kb so I've lost quality. How can I preserve quality?
Q3: The logo image will always be a PNG with transparent (black?) background. When I threshold to create a mask of the logo I get artifacts or an unclean extraction of the logo. How could I accurately extract the logo without artifacts or losing detail?
Mat src = imread("./images/pan1.jpg"); Mat logo = imread("./images/logo.png"); // Watermark image: overlay logo slightly faded/transparent Mat watermarked; Mat logoResized = Mat(src.rows, src.cols, CV_8UC3); // Make the logo image same size as the src image copyMakeBorder(logo, logoResized, src.rows - logo.rows, 0, src.cols - logo.cols, 0, BORDER_CONSTANT, { 0,0,0 }); addWeighted(src, 1.0, logoResized, 1.0, 0, watermarked); // Q1 imshow("Watermarked Opacity", watermarked); imwrite("./images/pan-watermarked1.jpg", watermarked); // Overlay logo Mat logoGray, thresh; cvtColor(logo, logoGray, CV_BGR2GRAY); threshold(logoGray, thresh, 1, 255, CV_THRESH_BINARY); Rect r(res.cols-logo.cols, res.rows-logo.rows, logo.cols, logo.rows); logo.copyTo(src(r), thresh); imshow("Watermarked", src); imwrite("./images/pan-watermarked2.jpg", src);
you CAN'T achieve transparency with 3 channels only
@berak my understanding is that the png is loaded/read in as a 4 channel Mat where the 4th channel is the alpha. So I am considering the transparency.
well, IF your alpha channel is binary, you can use copyTo() and use that alpha as a mask.
if it's NOT binary, but continuous -- you'll have to write your own, low-level alpha blending code. (please look it up). addWeighted does linear blending, and can't help you here.
and again, opencv is a computer-vision library. it's not meant to be photoshop.