Glare removal With Inpainting[OpenCV Python]

Sivaram Rasathurai
5 min readApr 6, 2020

--

This article is originally posted here

Glare is a visual sensation caused by excessive and uncontrolled brightness. It can be disabling or simply uncomfortable. It is subjective, and sensitivity to glare can vary widely. Older people are usually more sensitive to glare due to the ageing characteristics of the eye.

Glare Image

First, We need to detect the place where the glare exists. We can easily identify them using global binarization since when a glare exists commonly, that pixel value is higher than 180. Using that, we can detect the glare. So we need to get the pixels which are greater than 180, so then we do the removing part.

The below function is used to get the mask of an image in which pixels are white when the pixels are greater than 180 and below its black. We have actual glare places of the image as white and other places as black.

def create_mask(image):
gray = cv2.cvtColor( image, cv2.COLOR_BGR2GRAY )
blurred = cv2.GaussianBlur( gray, (9,9), 0 )
_,thresh_img = cv2.threshold( blurred, 180, 255, cv2.THRESH_BINARY)
thresh_img = cv2.erode( thresh_img, None, iterations=2 )
thresh_img = cv2.dilate( thresh_img, None, iterations=4 )
# perform a connected component analysis on the thresholded image,
# then initialize a mask to store only the "large" components
labels = measure.label( thresh_img, neighbors=8, background=0 )
mask = np.zeros( thresh_img.shape, dtype="uint8" )
# loop over the unique components
for label in np.unique( labels ):
# if this is the background label, ignore it
if label == 0:
continue
# otherwise, construct the label mask and count the
# number of pixels
labelMask = np.zeros( thresh_img.shape, dtype="uint8" )
labelMask[labels == label] = 255
numPixels = cv2.countNonZero( labelMask )
# if the number of pixels in the component is sufficiently
# large, then add it to our mask of "large blobs"
if numPixels > 300:
mask = cv2.add( mask, labelMask )
return mask

What we have done in this function is, We first convert the image to grayscale, using a Gaussian matrix (9x9) to blur the image to reduce the noise. Setting a threshold value to 180 in the global threshold method to convert our blurred image into a binary image where the pixel value is above 180 is the white other is black. We might have small blobs of noise; for that, we have done a series of erosion and dilations to our binary image.

After this dilation, erosion of our image, we might have small noises. For that, we performed a connected component analysis on the threshold image. measure.labels method of the scikit-image library is used for the connected component analysis. A new black image is created using the np.zeros method with the exact shape of the binary image. It is named as a mask.

We start looping over each of the unique labels. If the label is zero, then we know we are examining the background region and can safely ignore it. Otherwise, we construct a mask for just the current. Then counts the number of non-zero pixels in the labelMask. If numPixels exceeds a pre-defined threshold (in this case, a total of 300 pixels), then we consider the blob “large enough” and add it to our mask. This detection method was inspired from here. The author explained this method well there.

So our mask will be like below

We spotted our glare/bright places of the images. We can remove these spots using various methods.

  1. Inpainting method
  2. CLAHE method

Inpainting method of OpenCV

Filling some region of the image in different ways is called as inpainting in image preprocessing. Basically, inpainting is just filling gaps.

So which are the ways we can fill it in python OpenCV. You can fill it with Naiver-Stokes method or Fast — Marching method.

Naiver-Stokes method

Image intensities of the region can be updated using the partial differential equation, and the smoothness of the image can be calculated by the image Laplacian (The Laplacian is a 2-D isotropic measure of the 2nd spatial derivative of an image. The Laplacian of an image highlights regions of rapid intensity change and is therefore often used for edge detection (see zero-crossing edge detectors). The Laplacian is often applied to an image that has first been smoothed with something approximating a Gaussian smoothing filter in order to reduce its sensitivity to noise, and hence the two variants will be described together here. The operator normally takes a single gray-level image as input and produces another gray-level image as output)

Laplacian and partial differential equations can be used to preserve the edges and continue to propagate colour information in smooth regions. This is one of the methods to do image inpainting.

paper → https://www.math.ucla.edu/~bertozzi/papers/cvpr01.pdf

Fast Marching method

a weighted average over a known image neighbourhood of the pixel is used for image smoothness to inpaint. The known neighbourhood pixels and gradients are used to estimate the colour of the pixel to be inpainted.

paper → https://www.semanticscholar.org/paper/An-Image-Inpainting-Technique-Based-on-the-Fast-Telea/67d0cb47d14150daff08980efbea9f1267d3a4e5

We can use any of the above algorithms to inpaint.

How to use in OpenCV python

dst = cv2.inpaint( src, inpaintMask,inpaintRadius,flags)

Here

src → The input glared image
inpaintMask →A binary mask indicating pixels to be inpainted.
dst → Output image
inpaintRadius →Neighborhood around a pixel to inpaint.
flags → INPAINT_NS,(Navier-Stokes based method) or INPAINT_TELEA (Fast marching based method)

When we select the inpaintRadius, if the regions to be inpainted are thin, smaller values produce better results (less blurry).

Let’s apply this to our image

INPAINT_TELEA
INPAINT_NS

References

https://dsp.stackexchange.com/questions/1215/how-to-remove-a-glare-clipped-brightness-from-an-image

Spatial Filters — Laplacian/Laplacian of Gaussian. http://homepages.inf.ed.ac.uk/rbf/HIPR2/log.html

--

--