Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Smooth the edges of binary images (Face) using Python and Open CV

Tags:

python

opencv

I am looking for a perfect way to smooth edges of binary images. The problem is the binary image appears to be a staircase like borders which is very unpleasing for my further masking process.

I am attaching a raw binary image that is to be converted into smooth edges and I am also providing the expected outcome. I am also looking for a solution that would work even if we increase the dimensions of the image.

Problem Image Expected Outcome

like image 555
Pranav Avatar asked Dec 23 '22 17:12

Pranav


2 Answers

To preserve the sharpness of a binary image, I would recommend applying something like a median filter. Here is an example of this:

from PIL import Image, ImageFilter


image = Image.open('input_image.png')
image = image.filter(ImageFilter.ModeFilter(size=13))
image.save('output_image.png')

which gives us the following results:

Input image Output image

Figure 1. Left: The original input image. Right: The output image with a median filter of size 13.

Increasing the size of the filter would increase the degree of smoothing, but of course this comes as a trade-off because you also lose high-frequency information such as the sharp corner on the bottom-left of this sample image. Unfortunately, high-frequency features are similar in nature to the staircase-like borders.

like image 166
Desmond Cheong Avatar answered May 18 '23 00:05

Desmond Cheong


You can do that in Python/OpenCV with the help of Skimage by blurring the binary image. Then apply a one-sided clip.

Input:

enter image description here

import cv2
import numpy as np
import skimage.exposure

# load image
img = cv2.imread('bw_image.png')

# blur threshold image
blur = cv2.GaussianBlur(img, (0,0), sigmaX=3, sigmaY=3, borderType = cv2.BORDER_DEFAULT)

# stretch so that 255 -> 255 and 127.5 -> 0
# C = A*X+B
# 255 = A*255+B
# 0 = A*127.5+B
# Thus A=2 and B=-127.5
#aa = a*2.0-255.0 does not work correctly, so use skimage
result = skimage.exposure.rescale_intensity(blur, in_range=(127.5,255), out_range=(0,255))

# save output
cv2.imwrite('bw_image_antialiased.png', result)

# Display various images to see the steps
cv2.imshow('result', result)

cv2.waitKey(0)
cv2.destroyAllWindows()


enter image description here

You will have to adjust the amount of blur for the degree of aliasing in the image.

like image 44
fmw42 Avatar answered May 18 '23 00:05

fmw42