基于opencv的图像阴影去除

 

需求:图像阴影去除,有时候用手机或者相机拍照,往往会出现背景。打印出来就是灰色或者有黑色的背景,就需要实现背景去除,还原清晰图像。

基于opencv的图像阴影去除_第1张图片

基于opencv的图像阴影去除_第2张图片\

基于opencv的图像阴影去除_第3张图片

 

一。最大、最小值滤波

最大最小值滤波:首先排序周围像素和中心像素值,将中心像素值与最大和最小值比较,如果比最小值小,则替换中心像素为最小值,如果比最大值大,则替换中心像素为最大值。一个Kernel矩阵为3x3的最大最小值滤波如下:

基于opencv的图像阴影去除_第4张图片

 

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()

基于opencv的图像阴影去除_第5张图片

基于opencv的图像阴影去除_第6张图片

基于opencv的图像阴影去除_第7张图片

 

几点感悟:

(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()

基于opencv的图像阴影去除_第8张图片

就这样吧~!

发布于 2020-12-11

你可能感兴趣的:(图象处理)