Alpha blending with a mask

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

Alpha blending with a mask

luca.dantona
Hi!
I need to add two images with alpha blending using a mask, but I found
that cvAddWeighted doesn't support masks :(
Has anyone already faced this problem?
Thanks.

Reply | Threaded
Open this post in threaded view
|

Re: Alpha blending with a mask

jaybromley
--- In [hidden email], "luca.dantona" <luca.dantona@...> wrote:
> I need to add two images with alpha blending using a mask, but I found
> that cvAddWeighted doesn't support masks :(
> Has anyone already faced this problem?

Yes, I've faced this problem and I've got a solution that worked for me,
though your circumstances may be different. In my case I wanted to
overlay some decals (X's, check marks, etc.) over a second main image.
The images I wanted overlayed were simple graphics with a black
background. I wanted to alpha-blend the non-black part of the decals
with the main image. cvAddWeighted didn't work because it would add in
the black part of the decals, which I didn't want. If this is something
like your situation, continue reading.

To solve this I did the following. Let decal be the image I wanted to
overlay, decal_size its size,  and img be the main image.

     // Make a mask from all non-zero pixels in the decal.
     mask = cvCreateImage(decal_size, IPL_DEPTH_8U, 1);
     cvCvtColor(decal_size, mask, CV_RGB2GRAY);
     cvThreshold(mask, mask, 0.0, 255.0, CV_THRESH_BINARY_INV);

     // Here, the target image ROI needs to be set to the region you wish
to be blended. I
     // I assume you've calculated this and put it in target_rect.
     cvSetImageROI(img, target_rect);
     cvCopy(img, decal, mask);

     // Now alpha blend. Note that for img, alpha * img + 1 - alpha *
decal gives back 1.0 * img.
     cvAddWeighted(img, 1.0 - alpha, decal, alpha, 0.0, img);

The main weakness is the thresholding that is used to generate the mask.
If your decal has anti-aliased pixels, these can cause some odd effects.
I haven't found a completely general way of getting satisfactory
blending. If someone has a better way, I'd be eager to hear it.

Regards.




[Non-text portions of this message have been removed]

Reply | Threaded
Open this post in threaded view
|

Re: Alpha blending with a mask

luca.dantona
--- In [hidden email], "jaybromley" <jbromley@...> wrote:

> Yes, I've faced this problem and I've got a solution that worked for
> me... [CUT]

Thanks very much for your reply.
If I've understood your solution, it works only with rectangular
masks; however I don't get why cvAddWighted doesn't support masks. How
does it differ from cvAdd? I mean, the main structure of the two
functions is the same, the only difference is:
cvAdd -> dest = img1 + img2
cvAddWeighted -> dest = alpha*img1 + eta*img2
In this sense, what about the following code?

void AlphaBlending(IplImage *pImg1, float alpha, IplImage *pImg2,
float beta, IplImage *pDest, IplImage *pMask)
{
   // pMask must have 1 channel

   for(int y=0; y<pImg1->height; y++ )
   {
      uchar* ptrImg1 = (uchar*) (pImg1->imageData + y * pImg1-
>widthStep);
      uchar* ptrImg2 = (uchar*) (pImg2->imageData + y * pImg2-
>widthStep);
      uchar* ptrDest = (uchar*) (pDest->imageData + y * pDest-
>widthStep);
      uchar* ptrMask = (uchar*) (pMask->imageData + y * pMask-
>widthStep);
       
      for(int x=0; x<pImg1->width; x++)
      {
         if(ptrMask[x] > 0)
         {
            ptrDest[3*x] = alpha*ptrImg1[3*x] + beta*ptrImg2[3*x];
            ptrDest[3*x+1] = alpha*ptrImg1[3*x+1] +
beta*ptrImg2[3*x+1];
            ptrDest[3*x+2] = alpha*ptrImg1[3*x+2] +
beta*ptrImg2[3*x+2];
         }
      }
   }
}