【问题标题】:How to use OpenCV to overlay an image AND text/shapes?如何使用 OpenCV 覆盖图像和文本/形状?
【发布时间】:2020-06-07 08:02:27
【问题描述】:

我遇到了关于 OpenCV 的透明覆盖的问题。到目前为止,这是我的代码:

import cv2

cap = cv2.VideoCapture('Sample_Vid.mp4')
stat_overlay = cv2.imread('overlay.png')
fps = 21

if cap.isOpened():
    while cap.isOpened():
        ret, frame = cap.read()
        overlay = frame.copy()
        output = frame.copy()

        cv2.rectangle(overlay, (0, 0), (730, 50), (0, 0, 0), -1)
        cv2.putText(overlay, fps, (1230, 20), cv2.FONT_HERSHEY_DUPLEX, 0.5, (255, 255, 255), 1)
        cv2.addWeighted(overlay, 1.0, output, 0, 0, output)

        cv2.imshow('frame', output)

所以我的框架带有一个矩形,并且 FPS 显示在上面。现在我想先覆盖我的 stat_overlay 图像,然后再覆盖文本和形状,因为它们是动态的。在我读到的每一个解释中,都被告知使用cv2.addWeighted(stat_overlay, 1.0, output, 0, 0, output) 执行此操作,但我已经有一个与动态叠加层使用的命令类似的命令,如果我在其上方插入第二个命令,它就不起作用。任何想法如何解决这个问题?

提前感谢您的回答!

【问题讨论】:

    标签: python opencv overlay transparent cv2


    【解决方案1】:

    您使用的命令:cv2.addWeighted(overlay, 1.0, output, 0, 0, output),使用alpha = 1.0,和beta = 0,所以没有透明度。
    您基本上是将overlay 图像复制output 图像中。

    AddWeighted documentation:

    cv2.addWeighted(src1, alpha, src2, beta, gamma[, dst[, dtype]])
    src1 – 第一个输入数组。
    alpha – 第一个数组元素的权重。
    src2 – 与 src1 大小和通道号相同的第二个输入数组。
    beta – 第二个数组元素的权重。
    dst – 与输入数组具有相同大小和通道数的输出数组。

    您还可以使用以下代码来覆盖文本:

    output = frame.copy()
    cv2.rectangle(output, (0, 0), (730, 50), (0, 0, 0), -1)
    cv2.putText(output, fps, (1230, 20), cv2.FONT_HERSHEY_DUPLEX, 0.5, (255, 255, 255), 1)
    

    要覆盖stat_overlay,您可以使用Alpha blending 代码示例之类的解决方案。

    我不知道'overlay.png'是RGB还是RGBA格式。
    如果图像具有 Alpha 通道,您可以将其用作透明平面。
    如果图像是 RGB,您可以创建所需的 alpha 平面。

    如果'overlay.png' 是一个小图像(如徽标),您可能不需要任何这些,您可以将小图像“放置”在output 图像上。


    我创建了一个基于 alpha blending 示例的自包含代码示例。
    为了使代码自包含,代码使用:

    • ffmpeg-python 用于生成合成视频(用于测试)。
    • 代码,画了一个红色圆圈替换'overlay.png'

    代码如下:

    import ffmpeg
    import cv2
    import numpy as np
    
    in_filename = 'Sample_Vid.mp4' # Input file for testing (".264" or ".h264" is a convention for elementary h264 video stream file)
    
    ## Build synthetic video, for testing:
    ################################################
    # ffmpeg -y -r 10 -f lavfi -i testsrc=size=192x108:rate=1 -c:v libx264 -crf 23 -t 50 test_vid.264
    
    width, height = 640, 480
    
    (
        ffmpeg
        .input('testsrc=size={}x{}:rate=1'.format(width, height), f='lavfi')
        .output(in_filename, vcodec='libx264', crf=23, t=5)
        .overwrite_output()
        .run()
    )
    ################################################
    
    
    cap = cv2.VideoCapture('Sample_Vid.mp4')
    #stat_overlay = cv2.imread('overlay.png')
    
    # Create image with green circle, instead of reaing a file
    # The image is created as RGBA (the 4'th plane is the transparency).
    stat_overlay = np.zeros((height, width, 4), np.uint8)
    cv2.circle(stat_overlay, (320, 240), 80, (0, 0, 255, 255), thickness=20) # Draw red circle (with alpha = 255) 
    
    # https://www.learnopencv.com/alpha-blending-using-opencv-cpp-python/
    stat_alpha = stat_overlay[:, :, 3] # Take 4'th plane as alpha channel
    stat_alpha = cv2.cvtColor(stat_alpha, cv2.COLOR_GRAY2BGR) # Duplicate alpha channel 3 times (to match output dimensions)
    
    # https://www.learnopencv.com/alpha-blending-using-opencv-cpp-python/
    # Normalize the alpha mask to keep intensity between 0 and 1
    stat_alpha = stat_alpha.astype(float) / 255
    
    stat_overlay = stat_overlay[:, :, 0:3] # Get RGB channels
    
    fps = 21
    
    
    if cap.isOpened():
        while cap.isOpened():
            ret, frame = cap.read()
            if ret:            
                output = frame.copy()
    
                # https://www.learnopencv.com/alpha-blending-using-opencv-cpp-python/
                # Alpha blending:
                foreground = stat_overlay.astype(float)
                background = output.astype(float)
    
                # Multiply the foreground with the alpha matte
                foreground = cv2.multiply(stat_alpha, foreground)
    
                # Multiply the background with ( 1 - alpha )
                background = cv2.multiply(1.0 - stat_alpha, background)
    
                # Add the masked foreground and background.
                output = cv2.add(foreground, background).astype(np.uint8)
    
                cv2.rectangle(output, (0, 0), (230, 50), (0, 0, 0), -1)
                cv2.putText(output, str(fps), (123, 20), cv2.FONT_HERSHEY_DUPLEX, 0.5, (255, 255, 255), 1)
    
                cv2.imshow('frame', output)
                cv2.waitKey(1000)
    
            else:
                break
    
    cv2.destroyAllWindows()
    

    结果(最后一帧):

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-11-08
      • 2018-04-25
      • 2020-08-24
      • 1970-01-01
      • 2016-11-02
      • 2017-01-30
      • 1970-01-01
      • 2015-10-17
      相关资源
      最近更新 更多