0

I have a mask and a background image. I want to add this mask on the background image and blurring (or perhaps something like cv2.inpaint()) the intersection to make it more natural, but am blocked for the bluring effect, any help would be highly appreciated.


More details: I have two RGB images. The first image (foreground) is associated with a binary mask, which I would like to add on the second image (background).

The issue is that when we look at the final image we clearly see which part was added on the background image. Hence, I would like to add a blurring effect at the intersection of the mask and the background image. For now my code looks like:

#foreground image: we'll use only the mask part
#background image:  where we will add the mask
foreground = cv2.imread(path1) 
background = cv2.imread(path2)

#Convert to float
foreground = foreground.astype(float)
background = background.astype(float)
mask = mask.astype(float)

#Multiply the foreground with the mask 
foreground = cv2.multiply(mask, foreground)

#Multiply the background with everywhere except with mask
background = cv2.multiply(1.0 - mask, background)

#Add the masked foreground to background image
outImage = cv2.add(foreground, background)

I could not find a straightforward way to do it, but I guess their should have one. A lot of related answer on internet works by thresholding to some pixel value, but this can not be used here. For now the easiest way I found is:

  1. create a mask of the part I want to blurr
  2. blurr the final images (background +foreground mask)
  3. take from the blurr images only the part of the mask of 1) and add it the initial final image (background +foreground mask)

Before doing this, I was wondering if someone would have some advices.

miki
  • 639
  • 2
  • 6
  • 16
  • Two input images and some indication of what the result should look like might help. – Mark Setchell May 20 '19 at 14:46
  • Your current code probably would work fine if you just blurred your mask. What's the issue with that? – alkasm May 21 '19 at 07:29
  • Thank you for your answer alkasm. Unfortunately this is not what I need (refering to the alpha blending you were talking about), as this will reduce the mask intensity, but I need to keep it maximal. Also, concerning your second suggestion, blurring the mask will make me loos a lot of information of the mask. I guess I would need to be alble to blurr only part of the images: the intersection part. – miki May 21 '19 at 07:31
  • I am looking with cv2.dilate and cv2.inpaint for now... will edit when I have something interesting. Thank you for your help its greatly appreciated! – miki May 21 '19 at 07:33

1 Answers1

0

The way I am doing it so far works well, but I am staying open to any other better solution! Here's mine:

def foreground_background_into1(background, foreground, with_smooth=True, thickness=3, mask=[]):

    '''will add the foreground image to the background image to create a new image, with smooth intersection
    -foreground image: this image must be either black where there is no mask, or the mask parameter must be specified in 
    the mask parameter
    -background image:  image on which we will add the mask
    -mask: binary mask if foreground image does not already contain this information

    Note: not tested with mask'''

    #make a copy for the smooth part
    img = foreground.copy()

    #create binary mask (as needed to multiply with the backgound) from foreground image if not existing (replacing all value 
    #bigger than 0 to 1)
    if len(mask)==0:
        _,mask = cv2.threshold(foreground,1,1,cv2.THRESH_BINARY)

    #verification
    if foreground.shape!=background.shape:
        raise Warning("the foreground is not of same shape as background, we will convert it")
        foreground = imresize(foreground, size=background.shape)

    #if mask has one channel add two others
    if len(mask.shape)==2:
        mask = skimage.color.gray2rgb(mask)

    #add foreground to background
    foreground = foreground.astype(float)
    background = background.astype(float)
    mask = mask.astype(float)
    foreground = cv2.multiply(mask, foreground) 
    background = cv2.multiply(1 - mask, background) #is the initial background with black where the mask of forground
    outImage = cv2.add(foreground, background)
    result = outImage.astype(np.uint8)

    if with_smooth:

        #find contour
        foreground_gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
        ret,thresh = cv2.threshold(foreground_gray,1,255,0)
        _, contours, __ = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)

        #create intersection_mask
        intersection_mask = cv2.drawContours(np.zeros(foreground.shape, np.uint8),
                                             contours,-1,(0,255,0),thickness)

        #inpaint the contour in the first final image
        intersection_mask = cv2.cvtColor(intersection_mask, cv2.COLOR_BGR2GRAY)
        kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (1,1))
        intersection_mask = cv2.dilate(intersection_mask, kernel, iterations=1)
        result = cv2.inpaint(result,intersection_mask,1,cv2.INPAINT_TELEA)

    return(result)

I am basically adding the mask on the background image, and then smooth the intersection part by inpaint with openCV the contour of the mask.

miki
  • 639
  • 2
  • 6
  • 16