Closed exilon closed 7 years ago
Can you provide the original images?
Hi Laex, I'm using some test images like these:
I want to make a watermark. First, i'm tried this code, but transparency is not respected:
watermark := cvLoadImage('D:\logo2.png',CV_LOAD_IMAGE_UNCHANGED);
alpha := 0.7;
beta := 1.0 - alpha;
image := cvLoadImage('D:\guacamayo.png',CV_LOAD_IMAGE_UNCHANGED);
cvSetImageROI(image,CvRect(x,y,watermark.Width,watermark.Height));
cvAddWeighted(watermark,alpha,image,beta,0,image);
cvResetImageROI(watermark));
cvReleaseImage(watermark);
Then i'm tried this code, but then transparency is not like png owns and images not blended:
watermark := cvLoadImage('D:\logo2.png',CV_LOAD_IMAGE_UNCHANGED);
image := cvLoadImage('D:\guacamayo.png',CV_LOAD_IMAGE_UNCHANGED);
cvSetImageROI(image,CvRect(x,y,watermark.Width,watermark.Height));
mask := cvCreateImage(CvSize(watermark.width,watermark.height),IPL_DEPTH_8U,1);
cvCvtColor(watermark,mask,CV_BGR2GRAY);
cvCopyImage(watermark,image,mask);
cvResetImageROI(image);
cvReleaseImage(watermark);
program Transparency1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils,
System.Math,
ocv.highgui_c,
ocv.core_c,
ocv.core.types_c,
ocv.imgproc_c,
ocv.imgproc.types_c,
uResourcePaths;
const
batmanimg = cResourceMedia + 'batman.png';
parrotimg = cResourceMedia + 'parrot.png';
const
px = 200;
py = 100;
var
overlay: pIplImage = nil;
underlay: pIplImage = nil;
rgba: array [0 .. 3] of pIplImage;
i, j, k: Integer;
opacity: Double;
overlayPx, srcPx: Byte;
begin
try
overlay := cvLoadImage(batmanimg, CV_LOAD_IMAGE_UNCHANGED);
underlay := cvLoadImage(parrotimg, CV_LOAD_IMAGE_UNCHANGED);
cvNamedWindow('overlay_source', CV_WINDOW_AUTOSIZE);
cvShowImage('overlay_source', overlay);
cvNamedWindow('underlay_source', CV_WINDOW_AUTOSIZE);
cvShowImage('underlay_source', underlay);
for i := 0 to 3 do
rgba[i] := cvCreateImage(cvGetSize(overlay), IPL_DEPTH_8U, 1);
cvSplit(overlay, rgba[2], rgba[1], rgba[0], rgba[3]);
cvNamedWindow('alpha_overlay', CV_WINDOW_AUTOSIZE);
cvShowImage('alpha_overlay', rgba[3]);
for i := 0 to overlay^.width - 1 do
for j := 0 to overlay^.height - 1 do
for k := 0 to overlay^.nChannels - 1 do
begin
opacity := (overlay^.imageData[j * overlay^.widthStep + i * overlay^.nChannels + 3]) / 255;
overlayPx := overlay^.imageData[j * overlay^.widthStep + i * overlay^.nChannels + k];
srcPx := underlay^.imageData[(py + j) * underlay^.widthStep + (i + px) * overlay^.nChannels + k];
underlay^.imageData[(py + j) * underlay^.widthStep + (i + px) * overlay^.nChannels + k] :=
Trunc(srcPx * (1 - opacity) + overlayPx * opacity);
end;
cvNamedWindow('underlay', CV_WINDOW_AUTOSIZE);
cvShowImage('underlay', underlay);
cvWaitKey(0);
cvReleaseImage(overlay);
cvReleaseImage(underlay);
for i := 0 to 3 do
cvReleaseImage(rgba[i]);
cvDestroyAllWindows;
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.
Thank you Laex! You're great! Only two more qüestions... If underlay has only 3 channels and overlay has 4, result are not correct (shows as stripped bars). Must i convert to 4 channels first? how can i do?
If i want to blend these two images with transparency. I want same effect like AddWeighted, but respecting transparency. I changed this part of your code. Is correct?
alpha := 0.5
opacity := (overlay^.imageData[j * overlay^.widthStep + i * overlay^.nChannels + 3]) / 255;
opacity := opacity * alpha;
I've solved the alpha problem, and tried to solve blending overlay image (4 channels) over underlay image (3 channels) with this code:
if srcHas4channels then underlay^.imageData[(j + y) * fOCVImage^.widthStep + (i + x) * overlay^.nChannels + k] := Trunc(srcPx * (1 - opacity) + overlayPx * opacity)
else if opacity > 0 then underlay^.imagedata[(j + y) * underlay^.widthStep + underlay^.nchannels * (i + x) + k] := Trunc(srcPx * (1 - opacity) + overlayPx * opacity);
but result produces some kind of small vertical lines as you can see on batman logo.
Finally i've solved the problem with these changes in code:
//overlay images two images
if underlay^.nChannels > 3 then srcHasAlpha := True
else srcHasAlpha := False;
for i := 0 to overlay^.width - 1 do
begin
for j := 0 to overlay^.height - 1 do
begin
for k := 0 to underlay^.nChannels - 1 do
begin
opacity := (overlay^.imageData[j * overlay^.widthStep + i * overlay^.nChannels + 3]) / 255;
opacity := opacity * alpha;
overlayPx := overlay^.imageData[j * overlay^.widthStep + i * overlay^.nChannels + k];
if srcHasAlpha then
begin
srcPx := underlay^.imageData[(y + j) * underlay^.widthStep + (i + x) * overlay^.nChannels + k];
underlay^.imageData[(j + y) * underlay^.widthStep + (i + x) * overlay^.nChannels + k] := Trunc(srcPx * (1 - opacity) + overlayPx * opacity);
end
else if opacity > 0 then
begin
srcPx := underlay^.imageData[(y + j) * underlay^.widthStep + (i + x) * underlay^.nChannels + k];
underlay^.imagedata[(j + y) * underlay^.widthStep + (i + x) * underlay^.nchannels + k] := Trunc(srcPx * (1 - opacity) + overlayPx * opacity);
end;
end;
end;
end;
I'm trying to copy an small image with alpha over an big image but final image not respects small image transparency. I've tried with cvAddWeigthed, cvCopyImage, etc