需求:图像阴影去除,有时候用手机或者相机拍照,往往会出现背景。打印出来就是灰色或者有黑色的背景,就需要实现背景去除,还原清晰图像。
最大最小值滤波:首先排序周围像素和中心像素值,将中心像素值与最大和最小值比较,如果比最小值小,则替换中心像素为最小值,如果比最大值大,则替换中心像素为最大值。一个Kernel矩阵为3x3的最大最小值滤波如下:
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]):
if wall[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
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]):
if wall_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
删除阴影时需要注意,如果图西奥ing背景较浅且对象较暗,则必须限制性最大滤波,然后再执行最小滤波,如果图像背景较暗且物体较亮,则先执行最小滤波再执行最大滤波!
执行完最大-最小滤波后,获得的值不在0-255范围内,因此必须归一化使用背景减法获得最终阵列,该方法将原始图像减去最小-最大滤波图像,以获得去除阴影的最终图像。
#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
完整代码:
# conding=utf-8
'''
Author: Zhang Kanghui
Email: [email protected]
Wechat: a695201965
data: 2020/12/10 20:53
'''
import cv2
import numpy as np
import matplotlib.pyplot as plt
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]):
if wall[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
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]):
if wall_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
#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
def min_max_filtering(M, N, I):
if M == 0:
#max_filtering
A = max_filtering(N, I)
#min_filtering
B = min_filtering(N, A)
#subtraction
normalised_img = background_subtraction(I, B)
elif M == 1:
#min_filtering
A = min_filtering(N, I)
#max_filtering
B = max_filtering(N, A)
#subtraction
normalised_img = background_subtraction(I, B)
return normalised_img
if __name__ == '__main__':
image_path = r'0.jpg'
P = cv2.imread(image_path, 1)
b, g, r = cv2.split(P)
b_O_P = min_max_filtering(M=1, N=20, I=b)
g_O_P = min_max_filtering(M=1, N=20, I=g)
r_O_P = min_max_filtering(M=1, N=20, I=r)
O_P = cv2.merge([b_O_P, g_O_P, r_O_P])
# O_P = min_max_filtering(M=0, N=3, I=P)
plt.imshow(P)
plt.title("original image")
plt.show()
# Display final output
plt.imshow(O_P)
plt.title("Final output")
plt.show()
几点感悟:
(1)调参比较麻烦?
(2)想在rgb三个空间中,最终输出也是rgb的图。对于每个通道之间的相关性需要解决?
图像中光照大多数条件都是比较好的,所以阴影部分的亮度会比其他区域的亮度明显低不少,另外,由于亮度较低,导致色调较浅,所以RGB三个通道数值的方差较小。
# conding=utf-8
'''
Author: Zhang Kanghui
Email: [email protected]
Wechat: a695201965
data: 2020/12/11 11:35
'''
import cv2
import numpy as np
import matplotlib.pyplot as plt
img = cv2.imread('2.jpg')
img_sum = np.sum(img, axis=2)
std_img = np.std(img)
std_img = np.where(img_sum<310, std_img, 255)
cv2.imwrite("std_img.png", std_img.astype(np.uint8))
plt.imshow(std_img)
plt.show()
就这样吧~!
发布于 2020-12-11