如何批量处理色度键照片(遮蔽绿屏)
How to Batch Chroma Key Photos (Masking Green Screen)
目标
我有数百张图片都与这里的这一张相似:
我只是想使用绿屏为每个看起来像这里的图像创建一个蒙版(最好将边界平滑一点):
如果你想做测试,这里是原始图像:https://mega.nz/#!0YJnzAJR!GRYI4oNWcsKztHGoK7e4uIv_GvXBjMvyry7cPmyRpRA
我试过的
我发现 this post 用户使用 Imagemagick 实现色度键控。
for i in *; do convert $i -colorspace HSV -separate +channel \
\( -clone 0 -background none -fuzz 3% +transparent grey43 \) \
\( -clone 1 -background none -fuzz 10% -transparent grey100 \) \
-delete 0,1 -alpha extract -compose Multiply -composite \
-negate mask_$i; done;
但无论我如何调整数字,结果都不完美:
我真的很傻,这么简单的问题我自己都找不到解决办法。另请注意,我使用的是 Linux。所以没有 Photoshop 或 After Effects! :)
但我确信必须有解决这个问题的方法。
更新 1
我刚刚尝试使用 运行 ./greenscreen infile.jpg outfile.png
使用 this greenscreen script by fmw42,我对结果相当满意。
但是处理一张图像大约需要 40 秒,这导致我所有的图像总共需要 8 个小时(尽管我有一个相当强大的工作站,请参阅下面的规格)
也许这与 那些在处理过程中出现的错误有关?:
convert-im6.q16: width or height exceeds limit `black' @ error/cache.c/OpenPixelCache/3911.
convert-im6.q16: ImageSequenceRequired `-composite' @ error/mogrify.c/MogrifyImageList/7995.
convert-im6.q16: no images defined `./GREENSCREEN.6799/lut.png' @ error/convert.c/ConvertImageCommand/3258.
convert-im6.q16: unable to open image `./GREENSCREEN.6799/lut.png': No such file or directory @ error/blob.c/OpenBlob/2874.
convert-im6.q16: ImageSequenceRequired `-clut' @ error/mogrify.c/MogrifyImageList/7870.
convert-im6.q16: profile 'icc': 'RGB ': RGB color space not permitted on grayscale PNG `mask.png' @ warning/png.c/MagickPNGWarningHandler/1667.
工作站规格
- 内存:125,8 GiB
- 处理器:AMD®锐龙9 3900x 12核处理器×24
- 显卡:GeForce GTX 970/PCIe/SSE2 (两个)
如果在类 Unix 系统上,您可以尝试我的绿屏脚本,该脚本调用 ImageMagick 并用 Bash Unix 编写。例如:
输入:
greenscreen img.jpg result.png
结果(绿色变透明):
结果缩小了 50%,这样 Whosebug 就不会反对原来的结果太大了。但是,Whosebug 已将图像从透明 PNG 更改为白色背景 JPG。
请注意,其他图像可能需要默认值以外的参数值。您可以在 http://www.fmwconcepts.com/imagemagick/ 获取我的脚本。请注意,如果要用于商业用途,您需要就许可事宜与我联系。
我们知道背景是绿色的,可以通过颜色与物体区分开来,所以我建议使用颜色阈值。为此,我编写了一个简单的 OpenCV Python 代码来演示结果。
首先,我们需要安装OpenCV。
sudo apt update
pip3 install opencv-python
# verify installation
python3 -c "import cv2; print(cv2.__version__)"
然后,我们在与图像相同的目录中创建一个名为 skull.py
的脚本。
import cv2
import numpy as np
def show_result(winname, img, wait_time):
scale = 0.2
disp_img = cv2.resize(img, None, fx=scale, fy=scale)
cv2.imshow(winname, disp_img)
cv2.waitKey(wait_time)
img = cv2.imread('skull.jpg')
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# define range of green color in HSV
lower_green = np.array([70, 200, 100])
upper_green = np.array([90, 255, 255])
# Threshold the HSV image to extract green color
mask = cv2.inRange(hsv, lower_green, upper_green)
mask = cv2.bitwise_not(mask)
#cv2.imwrite('mask.png', mask)
show_result('mask', mask, 0)
cv2.destroyAllWindows()
您可以轻松找到有关使用 OpenCV 进行 HSV 颜色操作的教程。我不会复述这里使用的函数,但有一部分很重要。图像操作通常以 RGB 颜色 space 完成,其中包含红色、绿色和蓝色分量。然而,HSV 更像是人类的视觉系统,包含色调、饱和度和值分量。你可以找到conversion here。由于我们根据我们的感知来分离颜色,因此 HSV 更适合此任务。
重要的部分是选择适当的阈值。我通过检查选择了大约 80 的色调(最大 180),以及 200 和 100 以上的饱和度和值(最大 255)。您可以通过以下行打印特定像素的值:
rows,cols,channels = hsv.shape
print(hsv[row, column])
注意原点在左上角
结果如下:
可能需要做两件事。一个是对一组图像进行操作,使用 for 循环很简单。另一个是如果您不喜欢结果的某些部分,您可能想知道像素位置并相应地更改阈值。这可以使用鼠标事件。
for i in range(1, 100):
img = imread(str(i) + '.jpg')
def mouse_callback(event, x, y, flags, params):
if event == cv2.EVENT_LBUTTONDOWN:
row = y
column = x
print(row, column)
winname = 'img'
cv2.namedWindow(winname)
cv2.setMouseCallback(winname, mouse_callback)
请记住,show_result
函数会按比例因子调整图像大小。
如果你不想处理像素位置,而是想要平滑的结果,你可以应用morphological transformations。尤其是打开和关闭将完成工作。
kernel = np.ones((11,11), np.uint8)
opened = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel)
closed = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel)
打开结果(内核=11x11):
我真的不能把它放在评论中,所以我把它作为一个答案。如果你想使用 Fred 的 greenscreen
脚本,你可以使用 GNU Parallel 来加速它。
假设您使用以下命令:
mkdir out
greenscreen image.png out/image.png
要处理一张图像,而您有数千张图像,您可以执行以下操作以使所有 CPU 核心并行忙碌,直到它们全部处理完毕:
mkdir out
parallel greenscreen {} out/{} ::: *.png
目标
我有数百张图片都与这里的这一张相似:
如果你想做测试,这里是原始图像:https://mega.nz/#!0YJnzAJR!GRYI4oNWcsKztHGoK7e4uIv_GvXBjMvyry7cPmyRpRA
我试过的
我发现 this post 用户使用 Imagemagick 实现色度键控。
for i in *; do convert $i -colorspace HSV -separate +channel \
\( -clone 0 -background none -fuzz 3% +transparent grey43 \) \
\( -clone 1 -background none -fuzz 10% -transparent grey100 \) \
-delete 0,1 -alpha extract -compose Multiply -composite \
-negate mask_$i; done;
但无论我如何调整数字,结果都不完美:
我真的很傻,这么简单的问题我自己都找不到解决办法。另请注意,我使用的是 Linux。所以没有 Photoshop 或 After Effects! :)
但我确信必须有解决这个问题的方法。
更新 1
我刚刚尝试使用 运行 ./greenscreen infile.jpg outfile.png
使用 this greenscreen script by fmw42,我对结果相当满意。
但是处理一张图像大约需要 40 秒,这导致我所有的图像总共需要 8 个小时(尽管我有一个相当强大的工作站,请参阅下面的规格)
也许这与 那些在处理过程中出现的错误有关?:
convert-im6.q16: width or height exceeds limit `black' @ error/cache.c/OpenPixelCache/3911.
convert-im6.q16: ImageSequenceRequired `-composite' @ error/mogrify.c/MogrifyImageList/7995.
convert-im6.q16: no images defined `./GREENSCREEN.6799/lut.png' @ error/convert.c/ConvertImageCommand/3258.
convert-im6.q16: unable to open image `./GREENSCREEN.6799/lut.png': No such file or directory @ error/blob.c/OpenBlob/2874.
convert-im6.q16: ImageSequenceRequired `-clut' @ error/mogrify.c/MogrifyImageList/7870.
convert-im6.q16: profile 'icc': 'RGB ': RGB color space not permitted on grayscale PNG `mask.png' @ warning/png.c/MagickPNGWarningHandler/1667.
工作站规格
- 内存:125,8 GiB
- 处理器:AMD®锐龙9 3900x 12核处理器×24
- 显卡:GeForce GTX 970/PCIe/SSE2 (两个)
如果在类 Unix 系统上,您可以尝试我的绿屏脚本,该脚本调用 ImageMagick 并用 Bash Unix 编写。例如:
输入:
greenscreen img.jpg result.png
结果(绿色变透明):
结果缩小了 50%,这样 Whosebug 就不会反对原来的结果太大了。但是,Whosebug 已将图像从透明 PNG 更改为白色背景 JPG。
请注意,其他图像可能需要默认值以外的参数值。您可以在 http://www.fmwconcepts.com/imagemagick/ 获取我的脚本。请注意,如果要用于商业用途,您需要就许可事宜与我联系。
我们知道背景是绿色的,可以通过颜色与物体区分开来,所以我建议使用颜色阈值。为此,我编写了一个简单的 OpenCV Python 代码来演示结果。
首先,我们需要安装OpenCV。
sudo apt update
pip3 install opencv-python
# verify installation
python3 -c "import cv2; print(cv2.__version__)"
然后,我们在与图像相同的目录中创建一个名为 skull.py
的脚本。
import cv2
import numpy as np
def show_result(winname, img, wait_time):
scale = 0.2
disp_img = cv2.resize(img, None, fx=scale, fy=scale)
cv2.imshow(winname, disp_img)
cv2.waitKey(wait_time)
img = cv2.imread('skull.jpg')
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# define range of green color in HSV
lower_green = np.array([70, 200, 100])
upper_green = np.array([90, 255, 255])
# Threshold the HSV image to extract green color
mask = cv2.inRange(hsv, lower_green, upper_green)
mask = cv2.bitwise_not(mask)
#cv2.imwrite('mask.png', mask)
show_result('mask', mask, 0)
cv2.destroyAllWindows()
您可以轻松找到有关使用 OpenCV 进行 HSV 颜色操作的教程。我不会复述这里使用的函数,但有一部分很重要。图像操作通常以 RGB 颜色 space 完成,其中包含红色、绿色和蓝色分量。然而,HSV 更像是人类的视觉系统,包含色调、饱和度和值分量。你可以找到conversion here。由于我们根据我们的感知来分离颜色,因此 HSV 更适合此任务。
重要的部分是选择适当的阈值。我通过检查选择了大约 80 的色调(最大 180),以及 200 和 100 以上的饱和度和值(最大 255)。您可以通过以下行打印特定像素的值:
rows,cols,channels = hsv.shape
print(hsv[row, column])
注意原点在左上角
结果如下:
可能需要做两件事。一个是对一组图像进行操作,使用 for 循环很简单。另一个是如果您不喜欢结果的某些部分,您可能想知道像素位置并相应地更改阈值。这可以使用鼠标事件。
for i in range(1, 100):
img = imread(str(i) + '.jpg')
def mouse_callback(event, x, y, flags, params):
if event == cv2.EVENT_LBUTTONDOWN:
row = y
column = x
print(row, column)
winname = 'img'
cv2.namedWindow(winname)
cv2.setMouseCallback(winname, mouse_callback)
请记住,show_result
函数会按比例因子调整图像大小。
如果你不想处理像素位置,而是想要平滑的结果,你可以应用morphological transformations。尤其是打开和关闭将完成工作。
kernel = np.ones((11,11), np.uint8)
opened = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel)
closed = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel)
打开结果(内核=11x11):
我真的不能把它放在评论中,所以我把它作为一个答案。如果你想使用 Fred 的 greenscreen
脚本,你可以使用 GNU Parallel 来加速它。
假设您使用以下命令:
mkdir out
greenscreen image.png out/image.png
要处理一张图像,而您有数千张图像,您可以执行以下操作以使所有 CPU 核心并行忙碌,直到它们全部处理完毕:
mkdir out
parallel greenscreen {} out/{} ::: *.png