Author | Kavya Musty compile | Flin source | medium
We often scan pieces of paper and turn them into images. We have a variety of tools that can enhance these images online, make them brighter, and eliminate shadows in these images. What if we could remove the shadows manually? We can load any image into our code as a grayscale image and get the output in seconds without any application help.
This can be done by using basic Numpy operations and some open CV functions. To explain the process, we used the image below, which was taken with a mobile phone.
Obviously, there is a shadow that needs to be removed. Let’s get started.
- Import the necessary packages into your environment. To make it easy to display the image, we use Jupyter Notebook.
import cv2
import numpy as np
import matplotlib.pyplot as plt
Copy the code
- There are two things to be aware of when removing shadows. Since the image is a grayscale image, if the image background is lighter and the object is darker, the maximum filtering must be performed first, and then the minimum filtering must be performed. If the image background is dark and the object is bright, we can perform minimum filtering first and then maximum filtering.
So, what are maximum and minimum filtering?
- Maximum filtering: Let’s assume that we have an image I of a particular size. The algorithm we write should traverse the pixels of I one by one, and for each pixel (x, y), it must find the maximum gray value in the neighborhood (window of size N x N) surrounding that pixel and write that maximum gray value to the corresponding pixel position (x, y) in A. The resulting image A is called the maximum filtered image of the input image I.
Let’s implement this concept in code.
-
The max_filtering() function accepts input images and window sizes N.
-
It initially creates a “wall” (filled with -1) around the input array, which helps as we traverse the edge pixels.
-
We then create a “temp” variable into which we copy the calculated maximum value.
-
We then iterate through the array and create a window around the current pixel size N x N.
-
We then use the “amax()” function to calculate the maximum value in that window and write it to the Temp array.
-
We copy this temporary array into the main array A and return it as output.
-
A is the maximum filtered image of input I.
def max_filtering(N, I_temp) :
wall = np.full((I_temp.shape[0]+(N//2) *2, I_temp.shape[1]+(N//2) *2), -1)
wall[(N//2):wall.shape[0]-(N//2), (N//2):wall.shape[1]-(N//2)] = I_temp.copy()
temp = np.full((I_temp.shape[0]+(N//2) *2, I_temp.shape[1]+(N//2) *2), -1)
for y in range(0,wall.shape[0) :for x in range(0,wall.shape[1) :ifwall[y,x]! = -1:
window = wall[y-(N//2):y+(N//2) +1,x-(N//2):x+(N//2) +1]
num = np.amax(window)
temp[y,x] = num
A = temp[(N//2):wall.shape[0]-(N//2), (N//2):wall.shape[1]-(N//2)].copy()
return A
Copy the code
- Minimum filtering: This algorithm is exactly the same as maximum filtering, but instead of looking for the adjacent maximum gray value, we find the minimum value of N x N adjacent to the pixel, and write this minimum gray value into (x, y) in B. The resulting image B is called the minimum-filtered image of image I.
Let’s code this function.
def min_filtering(N, A) :
wall_min = np.full((A.shape[0]+(N//2) *2, A.shape[1]+(N//2) *2), 300)
wall_min[(N//2):wall_min.shape[0]-(N//2), (N//2):wall_min.shape[1]-(N//2)] = A.copy()
temp_min = np.full((A.shape[0]+(N//2) *2, A.shape[1]+(N//2) *2), 300)
for y in range(0,wall_min.shape[0) :for x in range(0,wall_min.shape[1) :ifwall_min[y,x]! =300:
window_min = wall_min[y-(N//2):y+(N//2) +1,x-(N//2):x+(N//2) +1]
num_min = np.amin(window_min)
temp_min[y,x] = num_min
B = temp_min[(N//2):wall_min.shape[0]-(N//2), (N//2):wall_min.shape[1]-(N//2)].copy()
return B
Copy the code
-
Therefore, if the image has a light background, we perform a maximum filtering first, which will give us the enhanced background and pass the maximum filtered image to the minimum filtering function, which will be responsible for the actual content enhancement.
-
Therefore, after performing the minimum-maximum filtering, the values we obtain are not in the range 0-255. Therefore, we must normalize the final array obtained using background subtraction, which subtracts the min-max filtered image from the original image to obtain the final image with the shadow removed.
#B is the filtered image and I is the original image
def background_subtraction(I, B) :
O = I - B
norm_img = cv2.normalize(O, None.0.255, norm_type=cv2.NORM_MINMAX)
return norm_img
Copy the code
- The variable N (window size for filtering) changes based on the size of particles or content in the image. For the test image, select size N = 20. The final output image after enhancement is shown below:
The output image is the enhanced result of the original image. The code implemented is a poor attempt to manually implement some library functions in Open CV to enhance the image. The entire Notebook with the image can be found at the Github link below.
- Github.com/kavyamusty/…
Original link: medium.com/swlh/enhanc…
Welcome to panchuangai blog: panchuang.net/
Sklearn123.com/
Welcome to docs.panchuang.net/