Recent

Author Topic: merge two images  (Read 11815 times)

klausbits

  • New Member
  • *
  • Posts: 29
merge two images
« on: July 07, 2016, 11:00:00 am »
Hi.

I want to interpolate between two images like this

Code: Pascal  [Select][+][-]
  1. var picture1,picture2,picture3: Tpicture;
  2. picture1:= Tpicture.create;
  3. picture2:= Tpicture.create;
  4. picture3:= Tpicture.create;
  5. picture1.LoadFromFile(d:\image1.jpg);
  6. picture2.LoadFromFile(d:\image2.jpg);
  7.  
  8. picture3 = 0.7*picture1 + 0.3*picture2;
  9.  

how can I do this?

Thaddy

  • Hero Member
  • *****
  • Posts: 14373
  • Sensorship about opinions does not belong here.
Re: merge two images
« Reply #1 on: July 07, 2016, 11:06:05 am »
You need to set transparency levels for those pictures so the one shines through the other.
Object Pascal programmers should get rid of their "component fetish" especially with the non-visuals.

klausbits

  • New Member
  • *
  • Posts: 29
Re: merge two images
« Reply #2 on: July 07, 2016, 11:26:56 am »
to Thaddy,
thanks for the tip. I have to think about this if it serves my purpose.

Rather I thought to have
red3:=0.7*red1+0.3*red2;
green3:=...
blue3:=...

Thaddy

  • Hero Member
  • *****
  • Posts: 14373
  • Sensorship about opinions does not belong here.
Re: merge two images
« Reply #3 on: July 07, 2016, 11:35:39 am »
@Klausbits:
;) Yup, that is basically what transparency does <very big smile> so why re-invent wheels? I never got further than an octagonal one.... ;)

You got the algorithm almost spot on but think about weights of the values. Now let your drivers do the real work ;)
« Last Edit: July 07, 2016, 11:41:23 am by Thaddy »
Object Pascal programmers should get rid of their "component fetish" especially with the non-visuals.

klausbits

  • New Member
  • *
  • Posts: 29
Re: merge two images
« Reply #4 on: July 07, 2016, 11:55:12 am »
to Thaddy,

I am not sure thsat this is the same (pardon me, I am a physicist;-)

How would you program your proposal?

circular

  • Hero Member
  • *****
  • Posts: 4220
    • Personal webpage
Re: merge two images
« Reply #5 on: July 07, 2016, 03:11:28 pm »
How to do that with BGRABitmap:

Code: Pascal  [Select][+][-]
  1. uses BGRABitmap, BGRABitmapTypes;
  2. var bmp1,bmp2,bmp3: TBGRABitmap;
  3. begin
  4.   bmp1 := TBGRABitmap.Create('d:\image1.jpg');
  5.   bmp2 := TBGRABitmap.Create('d:\image2.jpg');
  6.   bmp3 := TBGRABitmap.Create(bmp1.Width,bmp1.Height); //note that size may be different between bmp1 and bmp2
  7.   bmp3.CrossFade(Rect(0,0,bmp3.Width,bmp3.Height), bmp1, bmp2, round(0.3*255), dmSet);
  8.   bmp1.Free;
  9.   bmp2.Free;
  10.   ...
  11. end;

It works with images that have transparent parts as well.
Conscience is the debugger of the mind

klausbits

  • New Member
  • *
  • Posts: 29
Re: merge two images
« Reply #6 on: July 07, 2016, 04:27:50 pm »
to circular:

thank you, I'll try it.

Meanwile I worked around with
colorm:=picm.bitmap.Canvas.Pixels[nw,nh];      //color of picm, but has only 256 colors :-(
or
fpcolorm1:=picm1.bitmap.Canvas.getColor(nw,nh);  //FPcolor of picm1 does not work :-(

klausbits

  • New Member
  • *
  • Posts: 29
Re: merge two images
« Reply #7 on: July 07, 2016, 08:43:43 pm »
many thanks for your tips. Here my own solution, I hope it works:
Code: Pascal  [Select][+][-]
  1.   begin                //see diary 6.July 2016
  2.     picm:= TPicture.Create;
  3.     picm1:= TPicture.Create;
  4.     for n:=0 to nwidth-1 do
  5.     begin
  6. //        picture2[n]:= TPicture.Create;   //already defined
  7.       nr:=n;                 //real of n
  8.       mr:=nr*nmax/nwidth;    //real of m
  9.       m:=floor(mr);
  10.       dmr:=mr-m;            //fade position
  11.       Str(m:4,nstring);
  12.       fastring:=files+'\b'+nstring+'.jpg';
  13.       Str(m+1:4,nstring);
  14.       fbstring:=files+'\b'+nstring+'.jpg';
  15.       picm.LoadFromFile(fastring);      //image 1
  16.       picm1.LoadFromFile(fbstring);     //image 2
  17.       for nh:=0 to nheight-1 do
  18.       begin
  19.         for nw:=0 to nwidth-1 do        //for every pixel do
  20.         begin
  21.           colorm:=picm.bitmap.Canvas.Pixels[nw,nh];      //color of picm
  22.           RedGreenBlue(colorm, mRed, mGreen, mBlue);     //bytes! -> only 512 different colors?
  23.           colorm1:=picm1.bitmap.Canvas.Pixels[nw,nh];      //color of picm1
  24.           RedGreenBlue(colorm1, m1Red, m1Green, m1Blue);
  25. //          fpcolorm1:=picm1.bitmap.Canvas.getColor(nw,nh);  //FPcolor of picm1 does not work
  26.           nred:=round((1-dmr)*mRed+dmr*m1Red);             //to be scaled by 256?  or 8?
  27.           ngreen:=round((1-dmr)*mGreen+dmr*m1Green);
  28.           nblue:=round((1-dmr)*mBlue+dmr*m1Blue);
  29.  //         function RGBToColor(R, G, B: Byte): TColor;
  30.           colorn:=RGBToColor(nred, ngreen, nblue);
  31.           picture2[n].bitmap.Canvas.Pixels[nw,nh]:=colorn;   //image 3
  32.         end;
  33.       end;
  34.     end;
  35.     Str(n:4,nstring);
  36.     fastring:=files+'\bb'+nstring+'.jpg';  // bb... different name to not overwrite b... files of user
  37.     picture2[n].SaveToFile(fastring); //
  38.     picture2[n].free; //
  39.   end;
  40.  

circular

  • Hero Member
  • *****
  • Posts: 4220
    • Personal webpage
Re: merge two images
« Reply #8 on: July 07, 2016, 09:44:51 pm »
That's the idea.
Conscience is the debugger of the mind

russellman

  • Newbie
  • Posts: 3
Re: merge two images
« Reply #9 on: October 19, 2023, 08:18:55 pm »
I use BGRABitmap.
Hear is a PDF file that show how to do this.
https://drive.google.com/file/d/1-HWs7X5YNKkbDUdx9WpcBZ_RByodXFKb/view?usp=share_link

uses
   BGRABitmap, BGRABitmapTypes;

procedure TForm1.FormDropFiles(Sender: TObject; const FileNames: array of string
  );
begin
  ///If first image is drop on form.
  if tic = False then begin
    ///Create bmp1 TBGRABitmap.
    bmp1 := TBGRABitmap.Create;
    ///Load the first image into bmp1.
    bmp1.LoadFromFile(FileNames[0]);
    ///Create (bmp2) a TBGRABitmap canvas. The size of bmp1.
    bmp2 := TBGRABitmap.Create(bmp1.Width,bmp1.Height);
    ///Puts bmp1 (image data) into bmp2. Using Linear Blend.
    bmp2.PutImage(0, 0, bmp1, dmLinearBlend );
    ///bmp1 Free memory.
    bmp1.Free;
    ///Togels to All other images.
    tic := True
  ///All other images are drop on form.
  end else begin
    ///Create bmp1 TBGRABitmap.
    bmp1 := TBGRABitmap.Create;
    ///Load the first image into bmp1.
    bmp1.LoadFromFile(FileNames[0]);
    ///Puts bmp1 (image data) into bmp2. Using Linear Blend.
    ///bmp2 was not freed.
    bmp2.PutImage(0, 0, bmp1, dmLinearBlend);
    ///bmp1 Free memory.
    bmp1.Free;
  end; ///end if else().
  ///Draw bmp2 to Image1.
  Image1.Picture.Assign(bmp2);
  Image1.Picture.SaveToFile(Saved.png');
end;

r.lukasiak

  • Full Member
  • ***
  • Posts: 138
Re: merge two images
« Reply #10 on: October 25, 2023, 06:56:23 am »
Hi everyone,
I see the post is quite old but since #russellman recently revived it, I'll give it a try since it's about something I need :-)

I was playing with CrossFade and it's somehow working but there is something I can't figure out.
I have 2 BGRABitmaps, lets name them img1 and img2. Img1 is non-transparent picture but img2 is partly transparent. I need to merge them but without any calculating partly transparent pixels whatsoever. Img2 consists of either 100% transparent pixels or 100% opaque color pixels. I need the 100% opaque pixels to just replace the pixels from img1 and the 100% transparent pixels just keep the original pixels from img1.
so my first shot was:
Code: Pascal  [Select][+][-]
  1. img.CrossFade(Rect(0,0,img1.Width,img1.Height), img1, img2, 255, dmSet);
but it resulted in img be the same as img2, it took just 1ms though.
Then I started playing with mode value but all of them resulted in the same, img = img1, just taking 5-8ms.
Next I changed 255 to 254 and this did the trick, I got expected result but it took 26-28ms, depending on the mode.
I just don't understand why 255 doesn't give the result I expected. It looks like 254 causes the function to calculate the img1 and img2 pixels, that's why it's taking so much more time.  Even though it visually looks good, img2 seems to cover img1 in "just" 254/255, am I wrong?
Is AFadePosition and equivalent of opacity? Setting a value between 0 and 254 gives results as if it were but everything changes with 255.

Searching for any answer led me to this post and #russellman's using PutImage instead of CrossFade. By these functions names I'd say that CrossFade really calculates transparency according to AFadePosition whereas PutImage just drops one image onto another. PutImage indeed gives expected result in just 7ms. How PutImage different to CrossFade?

Could someone shed more light on it?

Thanks in advance!


circular

  • Hero Member
  • *****
  • Posts: 4220
    • Personal webpage
Re: merge two images
« Reply #11 on: October 25, 2023, 04:05:42 pm »
Hello @r.lukasiak

CrossFade is designed to create a transition between two images based on the fade position. When fade position is 0 to be equivalent of putting the first image (img1 in your case), and when fade position is 255 to be equivalent of putting the second image (img2). In between, it is supposed to be the intermediate value.

When using as the fade position different from 0 or 255, the function will perform some interpolation between the two images, which is why you noticed an increase in computation time. For example, if at one pixel, the first image is opaque and the second is transparent, with fade position 128 the resulting pixel should be half-transparent.

if your goal is to just overlay img2 on img1 without any transitional effect, using PutImage is the more appropriate and efficient choice. CrossFade is intended for scenarios where you want a smooth transition between two images.

Note that the mode supplied to CrossFade applies after the interpolation has been made between the two images. In most scenarios, you would use dmSet if you want to replace the content of the target or dmDrawWithTransparency if there is a background you want to preserve.

I hope this clarifies things! Let me know if you have any further questions or if the result you get does not seem consistent with the explanations.
Conscience is the debugger of the mind

r.lukasiak

  • Full Member
  • ***
  • Posts: 138
Re: merge two images
« Reply #12 on: October 26, 2023, 07:09:35 am »
Thank you very much for this explanation. Everthying makes perfect sense. However I'm still not sure why FadePosition=255 makes img1 disappear and the result=img2. 0-254 works exactly as you explanation indicates, giving a mix of both pics, depending on the FadePosition value.

And indeed, PutImage  does exactly what I needed and it's really fast.

thanks a lot!


circular

  • Hero Member
  • *****
  • Posts: 4220
    • Personal webpage
Re: merge two images
« Reply #13 on: October 26, 2023, 08:34:55 am »
I am happy the explanation made sense.

Your assumption that there isn't a big difference between FadePosition=254 and FadePosition=255 is spot on. This is surprising indeed that there would be a significant different.

A couple of scenarios might explain this:
- if the draw mode is dmSetExceptTransparent: if the pixel has alpha 254 it won't be displayed but if it has alpha 255 it will.
- if you draw the final image with parameter Opaque=True on a control but in fact the final image has transparent pixels: if a pixel has an alpha of 1, it will still be fully displayed on the control.

Both cases can be addressed for example by first filling the target image with a background color. Were any of these scenarios applicable to your tests?
Conscience is the debugger of the mind

Dzandaa

  • Sr. Member
  • ****
  • Posts: 251
  • From C# to Lazarus
Re: merge two images
« Reply #14 on: October 26, 2023, 11:50:00 am »
Hi,

Is this that you want?

PictOrig, PictDest, NewPict: TBGRABitmap; // Must be of the same size
PBDest: TImage; 
PictOrig: Picture with transparency
PictDest: Picture without transparency
NewPict: Result


Code: Pascal  [Select][+][-]
  1. // **************************
  2. // ***** Filter Picture *****
  3. // **************************
  4. procedure TMergeColorsForm.BFxPictureClick(Sender: TObject);
  5. var
  6.  Pxo, Pxd, Pxn: PBGRAPixel;
  7.  i: integer;
  8. begin
  9.  if((PictOrig = nil) or (PictDest = nil)) then exit;
  10.  if((PictOrig.Width <> PictDest.Width) or (PictOrig.Height <> PictDest.Height)) then exit;
  11.  if(NewPict <> nil) then FreeAndNil(NewPict);
  12.  NewPict := TBGRABitmap.Create(PictOrig.Width, PictOrig.Height);
  13.  
  14.  Pxo := PictOrig.Data;
  15.  Pxd := PictDest.Data;
  16.  Pxn := NewPict.Data;
  17.  for i := Pred(PictOrig.NbPixels) downto 0 do
  18.  begin
  19.    if(Pxo^.alpha <> 0) then Pxn^:= Pxo^ else Pxn^ := Pxd^;
  20.    inc(Pxo);
  21.    inc(Pxd);
  22.    inc(Pxn);
  23.  end;
  24.  PBDest.Picture.Assign(NewPict) ;
  25.  PBDest.Repaint;
  26. end;                          
  27.  

B->
Dzandaa

 

TinyPortal © 2005-2018