opencv 从图像中去除光反射

snvhrwxg  于 2023-04-21  发布在  其他
关注(0)|答案(1)|浏览(657)

我有一个RGB图像,上面有一些条形码。在我的算法中,我应用梯度来识别条形码,但当条形码上有光反射时,问题就来了。所以我一直在尝试去除反射,但也试图保留该区域的条形码。下面是一个示例图像:

我在高于(225,225,225):(R,G,B)的像素中使用了inpaint函数,但结果不是我想要的,甚至更糟。代码:

target = cv2.bitwise_and(image,image, mask=mascara)    #Original image
target_gray = cv2.cvtColor(target, cv2.COLOR_RGB2GRAY)  

#Filtro para quitar reflejos de los códigos de barras
red = numpy.array(image[:,:,0]) 
green = numpy.array(image[:,:,1])            
blue = numpy.array(image[:,:,2])

mascara_red = red > 225
mascara_green = green > 225 
mascara_blue = blue > 225
mascara_reflejo = mascara_red & mascara_green & mascara_blue    #   ENGLISH: WE USE INPAINT FUNCTION IN PIXELS HIGHER THAN (225, 225, 225)
kernel_reflejo = numpy.zeros((height, width),numpy.uint8)

kernel_reflejo[mascara_reflejo == True] = 255

# print(kernel_reflejo)
sin_reflejo = cv2.inpaint(target, kernel_reflejo, 30, cv2.INPAINT_TELEA)

我不知道是不是这个方法不对。我得到的结果是下面的图片:

x33g5p2x

x33g5p2x1#

我们可以从应用imflatfield(2-D图像平场校正)开始,然后应用降噪和锐化。
请注意,建议的解决方案不能保证改善条形码检测,也不能保证适用于所有图像。
建议阶段:

  • 应用2-D图像平场校正。

我们可以使用我的following answer中的Python实现。

flat_img = imflatfield(img, 15)  # Apply imflatfield with relatively small sigma - smaller sigma means that the brightness of each filter is determined by smaller area around it.
  • 使用非局部均值滤波器去除噪声,以减少“划痕”伪影。

注:使用非局部均值的想法来自following post

denoised_flat_img = cv2.fastNlMeansDenoisingColored(flat_img, None, 3, 3, 7)
  • 锐化非局部均值的结果-需要,因为非局部均值会使图像平滑得太多。
# https://stackoverflow.com/questions/4993082/how-can-i-sharpen-an-image-in-opencv
 blur = cv2.GaussianBlur(denoised_flat_img, (0, 0), 3)
 sharpened_flat_img = cv2.addWeighted(denoised_flat_img, 1.5, blur, -0.5, 0);

代码示例:

import cv2
import numpy as np

# https://stackoverflow.com/questions/61087996/imflatfield-matlab-for-python-use
def imflatfield(I, sigma):
    """Python equivalent imflatfield implementation
       I format must be BGR uint8"""
    A = I.astype(np.float32) / 255  # A = im2single(I);
    Ihsv = cv2.cvtColor(A, cv2.COLOR_BGR2HSV)  # Ihsv = rgb2hsv(A);
    A = Ihsv[:, :, 2]  # A = Ihsv(:,:,3);
    
    filterSize = int(2*np.ceil(2*sigma) + 1);  # filterSize = 2*ceil(2*sigma)+1;
    
    # shading = imgaussfilt(A, sigma, 'Padding', 'symmetric', 'FilterSize', filterSize); % Calculate shading
    shading = cv2.GaussianBlur(A, (filterSize, filterSize), sigma, borderType=cv2.BORDER_REFLECT)
    
    meanVal = np.mean(A)  # meanVal = mean(A(:),'omitnan')
    
    #% Limit minimum to 1e-6 instead of testing using isnan and isinf after division.
    shading = np.maximum(shading, 1e-6)  # shading = max(shading, 1e-6);
    
    B = A*meanVal / shading  # B = A*meanVal./shading;
    
    #% Put processed V channel back into HSV image, convert to RGB
    Ihsv[:, :, 2] = B  # Ihsv(:,:,3) = B;
    
    B = cv2.cvtColor(Ihsv, cv2.COLOR_HSV2BGR)  # B = hsv2rgb(Ihsv);
    
    B = np.round(np.clip(B*255, 0, 255)).astype(np.uint8)  # B = im2uint8(B);

    return B

img = cv2.imread('barcode.png')

# Apply imflatfield with relatively small sigma - smaller sigma means that the brightness of each filter is determined by smaller area around it. 
flat_img = imflatfield(img, 15)

# Remove noise using Non-local means filter
denoised_flat_img = cv2.fastNlMeansDenoisingColored(flat_img, None, 3, 3, 7)

# https://stackoverflow.com/questions/4993082/how-can-i-sharpen-an-image-in-opencv
# Sharpen the result of Non-local means
blur = cv2.GaussianBlur(denoised_flat_img, (0, 0), 3)
sharpened_flat_img = cv2.addWeighted(denoised_flat_img, 1.5, blur, -0.5, 0);

# Show results for testing
cv2.imshow('img', img)
cv2.imshow('flat_img', flat_img)
cv2.imshow('denoised_flat_img', denoised_flat_img)
cv2.imshow('sharpened_flat_img', sharpened_flat_img)
cv2.waitKey()
cv2.destroyAllWindows()

原始图像:

flat_img

denoised_flat_img

sharpened_flat_img

注意事项:
最好的解决方案是在捕获图像时去除反射(如果可能的话)。
图像处理解决方案(在当前的上下文中)应该更像学术主题(对于解决“真实的问题”可能不是很实用)。

相关问题