【问题标题】:chromakey: opencv make green screen video transparentchromakey:opencv 使绿屏视频透明
【发布时间】:2021-09-13 20:05:16
【问题描述】:

我正在使用以下脚本将原始视频的绿屏替换为背景图像,但结果不是我所期望的,我更改了 u_green 数组参数和 l_green,但它只会变得最糟糕。 最后,我想让它透明我应该使用哪个面具?

如果能提供任何解决此问题的帮助,我将不胜感激。

Python 脚本:

import cv2
import numpy as np


video = cv2.VideoCapture("green.mp4")
image = cv2.imread("bg.jpg")

while True:

    ret, frame = video.read()

    frame = cv2.resize(frame, (640, 480))
    image = cv2.resize(image, (640, 480))

    u_green = np.array([104, 153, 70])
    l_green = np.array([30, 30, 0])

    mask = cv2.inRange(frame, l_green, u_green)
    res = cv2.bitwise_and(frame, frame, mask=mask)

    f = frame - res
    f = np.where(f == 0, f, image)

    cv2.imshow("video", frame)
    cv2.imshow("mask", f)

    if cv2.waitKey(25) == 27:
        break

video.release()
cv2.destroyAllWindows()

结果

更新 源视频: Link

【问题讨论】:

  • 单独分享图片,同时分享纯背景,对于想试试你的代码的人来说会更好
  • 请查看使用 HSV 颜色空间的颜色阈值。
  • @YunusTemurlenk 我应该上传我的测试视频吗?这是带有绿屏背景的简单视频,我需要使其透明。

标签: python opencv chromakey


【解决方案1】:

我已尽力使用 HSV 色彩空间屏蔽屏幕。还是有一些绿色的轮廓,但是我不能再增加颜色边距而不切掉一些衣服。

编辑:将代码封装在视频循环中。

编辑 2:我添加了一个 VideoWriter 来保存结果并切换到使用饱和度通道,因为它具有更好的分离度。

输出视频:

https://drive.google.com/file/d/1GrECFwFy7JQJT6kUGrfLtlXjcfBsr7fP/view?usp=sharing

import cv2
import numpy as np

# open up video
cap = cv2.VideoCapture("video.mp4");

# grab one frame
scale = 0.5;
_, frame = cap.read();
h,w = frame.shape[:2];
h = int(h*scale);
w = int(w*scale);

# videowriter 
res = (w, h);
fourcc = cv2.VideoWriter_fourcc(*'XVID');
out = cv2.VideoWriter('test_vid.avi',fourcc, 30.0, res);

# loop
done = False;
while not done:
    # get frame
    ret, img = cap.read();
    if not ret:
        done = True;
        continue;

    # resize
    img = cv2.resize(img, res);

    # change to hsv
    hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV);
    h,s,v = cv2.split(hsv);

    # get uniques
    unique_colors, counts = np.unique(s, return_counts=True);

    # sort through and grab the most abundant unique color
    big_color = None;
    biggest = -1;
    for a in range(len(unique_colors)):
        if counts[a] > biggest:
            biggest = counts[a];
            big_color = int(unique_colors[a]);

    # get the color mask
    margin = 50;
    mask = cv2.inRange(s, big_color - margin, big_color + margin);

    # smooth out the mask and invert
    kernel = np.ones((3,3), np.uint8);
    mask = cv2.dilate(mask, kernel, iterations = 1);
    mask = cv2.medianBlur(mask, 5);
    mask = cv2.bitwise_not(mask);

    # crop out the image
    crop = np.zeros_like(img);
    crop[mask == 255] = img[mask == 255];

    # show
    cv2.imshow("Mask", mask);
    cv2.imshow("Blank", crop);
    cv2.imshow("Image", img);
    done = cv2.waitKey(1) == ord('q');

    # save
    out.write(crop);

# close caps
cap.release();
out.release();

【讨论】:

  • 这太棒了,谢谢。但是我如何将它用于视频?如您所见,我的问题是关于如何在具有绿屏背景的视频上完成此操作
  • 关于findContours 的错误:@IanChu 显然使用了一些 OpenCV 3.x 版本,其中方法签名具有三个返回值。您可能会使用一些 OpenCV 4.x 版本,其中只有两个返回值。请改用contours, _ = cv2.findContours(...)
  • @IanChu 为了防止出现这些后续问题,请尝试在您的答案中使用cnts = cv2.findContours(...) 后跟cnts = cnts[0] if len(cnts) == 2 else cnts[1] 之类的内容。大多数问 OpenCV 问题的人都倾向于使用相当新的 OpenCV 版本,findContours 不兼容会让他们感到困惑。
  • 对不起!我忘了记下我的opencv版本,我的错。当你说它不影响视频时,你是什么意思? cv2.imshow() 应该向您显示裁剪后的图像。您的意思是要保存仅包含裁剪图像的新视频吗?
  • 这不是我以前尝试过的,所以我不知道有什么特别的方法。以下是快速谷歌搜索带来的结果:stackoverflow.com/questions/46864915/…
猜你喜欢
  • 1970-01-01
  • 2014-08-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多