Inpainting an image in Julia

For our final article of the month, we’ll be showing you how easy it is to inpaint images in Julia. This might be the shortest Julia article here on MLG, but I bet you that its the most interesting Julia article here.

We’ll be using the package ImageInpainting.jl, which is a part of the larger Images.jl package here. We’ll also use ImageDraw.jl from that package in order to draw the masks.

Here I’ve kept the image in a folder named Tempy in the root of my C-drive.

image=load("C:\\Tempy\\2077.jpg")

For a refresher, remember that the way inpainting works is by calculating color gradients, and then interpolating them in the masked region.

But before we’re able to use the inpaint, function, we must convert our image into an array

We’re going to take the following picture:

And remove that logo in the bottom left. So, first we define a masking by drawing a circle over the area we want to inpaint:

masking=draw(image,Ellipse(CirclePointRadius(140,666,90)))

We then compare this to the original image to get us a mask:

Now that you know the gameplan, let’s put it into action.

As this is a rudimentary library, we’re going to have separate the image into its constituent channels, inpaint, and then reconstitute the image. So, first lets split the image:

split=channelview(image);

Now we have separated the three channels(you can zoom in to see the code too):

Our previous mask is perfectly fine as we only want to retouch that area in each channel. So we carry out the inpainting on each channel:

r=inpaint(convert(Array{Float64},(Gray.(split[1,:,:]))),mask,Criminisi(100,10))
g=inpaint(convert(Array{Float64},(Gray.(split[2,:,:]))),mask,Criminisi(150,50))
b=inpaint(convert(Array{Float64},(Gray.(split[3,:,:]))),mask,Criminisi(99,90))

Note that you’ll want to tweak how much area is used by the diffusion equation by tweaking the parameters you pass to Criminisi for each channel. Finally we reconstitute the image from the three channels, and display it:

colorview(RGB,StackedView(r,g,b))

Getting the following result:

Its not the best job ever, but I’m happy enough with it. If you want to better this, I’d recommend you to choose as small a mask as possible, and iterate the painted image into the following function recursively.

Note that we talked at length about all the steps, else they can all be done within less than 5 lines:

function doIt(image)
	split=channelview(image);
	r=inpaint(convert(Array{Float64},(Gray.(split[1,:,:]))),mask,Criminisi(10,10))
	g=inpaint(convert(Array{Float64},(Gray.(split[2,:,:]))),mask,Criminisi(100,100))
	b=inpaint(convert(Array{Float64},(Gray.(split[3,:,:]))),mask,Criminisi(100,100))
	return colorview(RGB,StackedView(r,g,b))
	end

you can find the notebook here:

https://github.com/mathmetal/Misc/blob/master/MLG/Inpaint.jl

Leave a Reply

Your email address will not be published.