Alpha channel overlay back to RGB

asked 2019-10-08 06:39:31 -0500

updated 2019-10-08 06:58:18 -0500

berak gravatar image

I need to overlay a watermark on a video stream. I am using av for flicking through the frames, but opencv for the image processing. It's a the point where I want to hand a frame back to av that I get a problem.

Here is an annotated example of what I am trying to do, and where I am having problems

container = av.open('video.mp4')
for frame in container.decode(video=0):
    background = frame.to_ndarray(format="bgr24")
    (h, w) = background.shape[:2]
    background = np.dstack([background, np.ones((h, w), dtype="uint8") * 255])

    overlay = np.zeros((h, w, 4), dtype="uint8")
    y1 = watermark_top_margin
    y2 = watermark_top_margin + watermark_height
    x1 = w - watermark_width - watermark_right_margin
    x2 = w - watermark_right_margin

    overlay[y1:y2, x1: x2] = resized_watermark

    # blend the two images together using transparent overlays
    output = background.copy()
    cv2.addWeighted(overlay, watermark_alpha, output, 1.0, 0, output)

    # blend the two images together using transparent overlays
    output = background.copy()
    cv2.addWeighted(overlay, watermark_alpha, output, 1.0, 0, output)

    #This is the problem right here vvvvvvvvvvvvvvvvvvvvvv
    output = cv2.cvtColor(output,cv2.COLOR_RGBA2RGB)
    #Here is the problem ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The colour conversion loses any work I have done in the alpha channel. So the frame looks exactly as it did before I overlay the image.

    new_frame = av.video.VideoFrame.from_ndarray(output, format="bgr24")

So my question is this. How can I convert the image back to RGB format to create an av frame without losing the alpha channel information? This needs to be performat as it is happening in real time.

edit retag flag offensive close merge delete

Comments

you probably need a bgr (or rgb, who knows?) watermark, and an rgb image, and a single addWeighted() call between them. (also the weights must add up to 1).

berak gravatar imageberak ( 2019-10-08 07:09:12 -0500 )edit
1

you don't need opencv for that all . weighted blending can be done simply using numpy

berak gravatar imageberak ( 2019-10-08 07:13:53 -0500 )edit

The addWeighted call is in there and working just fine. The overlay works just fine. When I convert it using cvtColor the overlay is lost.

suityou01 gravatar imagesuityou01 ( 2019-10-08 07:14:59 -0500 )edit

Well that's cleared that up.

suityou01 gravatar imagesuityou01 ( 2019-10-08 07:15:49 -0500 )edit

Any chance of some code, or a url?

    container = av.open('video.mp4')
for frame in container.decode(video=0):
    background = frame.to_ndarray(format="bgr24")
    (h, w) = background.shape[:2]
    background = np.dstack([background, np.ones((h, w), dtype="uint8") * 255])
    overlay= background.copy()

    y1 = watermark_top_margin
    y2 = watermark_top_margin + watermark_height
    x1 = w - watermark_width - watermark_right_margin
    x2 = w - watermark_right_margin

    overlay[y1:y2, x1: x2] = resized_watermark

    output = 0.5 * background + 0.5 * overlay
    cv2.namedWindow("original")
    cv2.imshow('original', background) << This is now just a white image

    cv2.namedWindow("overlay")
    cv2.imshow('overlay', output) << This is also just a white image, albeit much smaller
suityou01 gravatar imagesuityou01 ( 2019-10-08 07:41:32 -0500 )edit

Do you have an image to see what is looked like?

supra56 gravatar imagesupra56 ( 2019-10-08 08:45:28 -0500 )edit

Why do you have 2 duplicated?

# blend the two images together using transparent overlays
output = background.copy()
cv2.addWeighted(overlay, watermark_alpha, output, 1.0, 0, output)

# blend the two images together using transparent overlays
output = background.copy()
cv2.addWeighted(overlay, watermark_alpha, output, 1.0, 0, output)
supra56 gravatar imagesupra56 ( 2019-10-08 21:00:35 -0500 )edit