Gradient mask blending in opencv python

前端 未结 3 563
[愿得一人]
[愿得一人] 2020-12-17 06:17

I have an image and circle zone. I need to blur all, except for circle zone. Also i need to make border of circle smooth.
The input:

The output(made it in image

相关标签:
3条回答
  • 2020-12-17 06:30

    So the main problem with (mask/255) * blur + (1-mask/255)*another img was operators. They were working only with one channel. Next problem is working with float numbers for "smoothing".
    I've changed code of blending with alpha channel to this:
    1) i'm taking every channel for source images and mask
    2) Performing formula
    3) Merging channels

    def blend_with_mask_matrix(src1, src2, mask):
        res_channels = []
        for c in range(0, src1.shape[2]):
            a = src1[:, :, c]
            b = src2[:, :, c]
            m = mask[:, :, c]
            res = cv.add(
                cv.multiply(b, cv.divide(np.full_like(m, 255) - m, 255.0, dtype=cv.CV_32F), dtype=cv.CV_32F),
                cv.multiply(a, cv.divide(m, 255.0, dtype=cv.CV_32F), dtype=cv.CV_32F),
               dtype=cv.CV_8U)
            res_channels += [res]
        res = cv.merge(res_channels)
        return res
    

    And as a gradient mask i'm just using blurred circle.

    def blur_image(cv_image, radius, center, gaussian_core, sigma_x):
        blurred = cv.GaussianBlur(cv_image, gaussian_core, sigma_x)
    
        circle_not_mask = np.zeros_like(cv_image)
        cv.circle(circle_not_mask, center, radius, (255, 255, 255), -1)
    #Smoothing borders
        cv.GaussianBlur(circle_not_mask, (101, 101), 111, dst=circle_not_mask)
    # Computing
        res = blend_with_mask_matrix(cv_image, blurred, circle_not_mask)
        return res
    

    Result:

    It is working a bit slower than very first version without smoother borders, but it's ok.
    Closing question.

    0 讨论(0)
  • 2020-12-17 06:31

    You can easily mask upon an image using the following funciton:

    def transparentOverlay(src, overlay, pos=(0, 0), scale=1):
        overlay = cv2.resize(overlay, (0, 0), fx=scale, fy=scale)
        h, w, _ = overlay.shape  # Size of foreground
        rows, cols, _ = src.shape  # Size of background Image
        y, x = pos[0], pos[1]  # Position of foreground/overlay image
    
        # loop over all pixels and apply the blending equation
        for i in range(h):
            for j in range(w):
                if x + i >= rows or y + j >= cols:
                    continue
                alpha = float(overlay[i][j][3] / 255.0)  # read the alpha channel
                src[x + i][y + j] = alpha * overlay[i][j][:3] + (1 - alpha) * src[x + i][y + j]
        return src
    

    You need to pass the source image, then the overlay mask and position where you want to set the mask. You can even set the masking scale. by calling it like this way.

    transparentOverlay(face_cigar_roi_color,cigar,(int(w/2),int(sh_cigar/2)))
    

    For details you can look at this link: Face masking and Overlay using OpenCV python

    Output:

    0 讨论(0)
  • 2020-12-17 06:50

    I think maybe you want something like that.

    This is the source image:

    The source-blured-pair :

    The mask-alphablened-pair:


    The code with description in the code comment.

    #!/usr/bin/python3
    # 2018.01.16 13:07:05 CST
    # 2018.01.16 13:54:39 CST
    import cv2
    import numpy as np
    
    def alphaBlend(img1, img2, mask):
        """ alphaBlend img1 and img 2 (of CV_8UC3) with mask (CV_8UC1 or CV_8UC3)
        """
        if mask.ndim==3 and mask.shape[-1] == 3:
            alpha = mask/255.0
        else:
            alpha = cv2.cvtColor(mask, cv2.COLOR_GRAY2BGR)/255.0
        blended = cv2.convertScaleAbs(img1*(1-alpha) + img2*alpha)
        return blended
    
    img = cv2.imread("test.png")
    
    H,W = img.shape[:2]
    mask = np.zeros((H,W), np.uint8)
    cv2.circle(mask, (325, 350), 40, (255,255,255), -1, cv2.LINE_AA)
    mask = cv2.GaussianBlur(mask, (21,21),11 )
    
    blured = cv2.GaussianBlur(img, (21,21), 11)
    
    blended1 = alphaBlend(img, blured, mask)
    blended2 = alphaBlend(img, blured, 255- mask)
    
    cv2.imshow("blened1", blended1);
    cv2.imshow("blened2", blended2);
    cv2.waitKey();cv2.destroyAllWindows()
    

    Some useful links:

    1. Alpha Blending in OpenCV C++ : Combining 2 images with transparent mask in opencv

    2. Alpha Blending in OpenCV Python: Gradient mask blending in opencv python

    0 讨论(0)
提交回复
热议问题