使用Elixir/Vix/libvips去除色度键



这只是从Vix示例复制的一些处理程序代码

defmodule VixExt do
alias Vix.Vips.Image
alias Vix.Vips.Operation
@max_height 500
def show(%Image{} = image) do
height = Image.height(image)
# scale down if image height is larger than 500px
image =
if height > @max_height do
Operation.resize!(image, @max_height / height)
else
image
end
# write vips-image as png image to memory
{:ok, image_bin} = Image.write_to_buffer(image, ".png")
Kino.render(Kino.Image.new(image_bin, "image/png"))
:ok
end
end

做事情的代码:

import VixExt
{:ok, fore} = Image.open("/home/user/Downloads/greenscreen.jpg")
{:ok, back} = Image.open("/home/user/Downloads/background.jpg")
# Lower bound green
{:ok, l_green} = Image.Math.greater_than(fore, [0.0, 100.0, 0.0])
# Upper bound green
{:ok, u_green} = Image.Math.less_than(fore, [100.0, 255.0, 95.0])
{:ok, color_fore_mask} = Image.Math.boolean_and(l_green, u_green)
{:ok, fore_mask} = Vix.Vips.Operation.bandbool(color_fore_mask, :VIPS_OPERATION_BOOLEAN_AND)
{:ok, masked} = Image.Math.subtract(fore, fore_mask)
{:ok, inverted_fore_mask} = Vix.Vips.Operation.invert(fore_mask)
{:ok, masked_back} = Image.Math.subtract(back, inverted_fore_mask)
{:ok, masked_bin} = Vix.Vips.Image.write_to_buffer(masked, ".jpg")
{:ok, masked_clone} = Vix.Vips.Image.new_from_buffer(masked_bin)

{:ok, masked_back_bin} = Vix.Vips.Image.write_to_buffer(masked_back, ".jpg")
{:ok, masked_back_clone} = Image.from_binary(masked_back_bin)
{:ok, composite} = Vix.Vips.Operation.add(masked_back, masked_clone)
show(composite)

我一开始遇到的问题是剪辑后的图像没有正确地添加在一起。长生不老药是永恒的,所以我有点期待这种行为。然而,它们都指向同一个图像,所以当我试图将它们添加在一起时,这有点像是原始图像的混搭。

我可以通过加载预剪切的图像来强制它达到正确的行为,然后它会像我预期的那样运行,但我不想因为明显的原因而不得不保存到磁盘。所以现在我试图强制复制,这样我得到的是剪辑后的版本,而不是原始版本。

显示的图像是我想要的结果。人物从绿色背景开始,绿色背景被移除并合成到场景中。

我目前得到的错误是

** (MatchError) no match of right hand side value: {:error, "Failed to write VipsImage to memory"}

每当我尝试向缓冲区写入两次时,就会发生这种情况。

我本以为移除绿屏是一个比较常规的用例,这样做会更容易。我很乐意采取更好的方法。

Image Elixir库现在提供Image.chroma_key/2以响应@GeneticJam的这一挑战。像这样使用,基本上是:
Image.chroma_key!(foreground) 
|> then(&Image.compose!(background, &1))

默认色度覆盖色度绿色的可能色域。

我设法用两种不同的方法(在帮助下(解决了这个问题。

import VixExt
# Opening with this option makes it possible to have more than one pipeline so it avoids the above error.
{:ok, fore} = Image.open("/home/kevinedey/Downloads/greenscreen.jpg", access: :random)
{:ok, back} = Image.open("/home/kevinedey/Downloads/background.jpg", access: :random)
# Lower bound green
{:ok, l_green} = Image.Math.greater_than(fore, [0.0, 100.0, 0.0])
# Upper bound green
{:ok, u_green} = Image.Math.less_than(fore, [100.0, 255.0, 95.0])
{:ok, color_fore_mask} = Image.Math.boolean_and(l_green, u_green)
{:ok, fore_mask} = Vix.Vips.Operation.bandbool(color_fore_mask, :VIPS_OPERATION_BOOLEAN_AND)
{:ok, masked} = Image.Math.subtract(fore, fore_mask)
{:ok, inverted_fore_mask} = Vix.Vips.Operation.invert(fore_mask)
{:ok, masked_back} = Image.Math.subtract(back, inverted_fore_mask)
{:ok, masked_bin} = Vix.Vips.Image.write_to_buffer(masked, ".jpg")
{:ok, masked_clone} = Vix.Vips.Image.new_from_buffer(masked_bin)
{:ok, masked_back_bin} = Vix.Vips.Image.write_to_buffer(masked_back, ".jpg")
{:ok, masked_back_clone} = Image.from_binary(masked_back_bin)
{:ok, comp} = Vix.Vips.Operation.add(masked_back_clone, masked_clone)
show(comp)

可能更接近vip的使用方式,因为不需要额外的管道。

import VixExt
{:ok, fore} = Image.open("/home/kevinedey/Downloads/greenscreen.jpg")
{:ok, back} = Image.open("/home/kevinedey/Downloads/background.jpg")
# Lower bound green
{:ok, l_green} = Image.Math.greater_than(fore, [0.0, 100.0, 0.0])
# Upper bound green
{:ok, u_green} = Image.Math.less_than(fore, [100.0, 255.0, 95.0])
{:ok, color_fore_mask} = Image.Math.boolean_and(l_green, u_green)
{:ok, fore_mask} = Vix.Vips.Operation.bandbool(color_fore_mask, :VIPS_OPERATION_BOOLEAN_AND)
{:ok, inverted_fore_mask} = Vix.Vips.Operation.invert(fore_mask)
{:ok, masked_person} = Vix.Vips.Operation.bandjoin([fore, inverted_fore_mask])
{:ok, comp} = Image.compose(back, masked_person)
show(comp)

最新更新