Search code examples
luavips

vips - How to achieve edge feather effect


I'm using the vips library for manipulating some images, specifically its Lua binding, lua-vips, and I'm trying to find a way to do a feather effect on the edge of an image.

It's the first time I try a library for this kind of task and I've been looking at this list of functions available, but still no idea on how to it. It's not complex shape, just a basic rectangular image whose top and bottom edges should blend smoothly with the background (another image that I'm currently using vips_composite() on).

Supposing that a "feather_edges" method existed, it would be something like:

local bg = vips.Image.new_from_file("foo.png")
local img = vips.Image.new_from_file("bar.png") --smaller than `bg`
img = img:feather_edges(6) --imagine a 6px feather
bg:composite(img, 'over')

But still it would be nice to specify what parts of the image should be feathered. Any ideas on how to do it?


Solution

  • You need to pull the alpha out of the top image, mask off the edges with a black border, blur the alpha to feather the edges, reattach, then compose.

    Something like:

    #!/usr/bin/luajit
    
    vips = require 'vips'
    
    function feather_edges(image, sigma)
        -- split to alpha + image data 
        local alpha = image:extract_band(image:bands() - 1)
        local image = image:extract_band(0, {n = image:bands() - 1})
    
        -- we need to place a black border on the alpha we can then feather into,
        -- and scale this border with sigma
        local margin = sigma * 2
        alpha = alpha
            :crop(margin, margin,
                image:width() - 2 * margin, image:height() - 2 * margin)
            :embed(margin, margin, image:width(), image:height())
            :gaussblur(sigma)
    
        -- and reattach
        return image:bandjoin(alpha)
    end
    
    bg = vips.Image.new_from_file(arg[1], {access = "sequential"})
    fg = vips.Image.new_from_file(arg[2], {access = "sequential"})
    fg = feather_edges(fg, 10)
    out = bg:composite(fg, "over", {x = 100, y = 100})
    out:write_to_file(arg[3])