opencv 降噪后,输出图像颜色不同

bakd9h0s  于 2023-06-24  发布在  其他
关注(0)|答案(1)|浏览(137)
import numpy as np
import cv2
import time



def my_get_Gaussian2D_mask(msize, sigma=1):
    y, x = np.mgrid[-(msize // 2):(msize // 2) + 1,
           -(msize // 2):(msize // 2) + 1]

    gaus2D = 1 / (2 * np.pi * sigma**2) * \
             np.exp(-(( x**2 + y**2 )/(2 * sigma**2)))

    gaus2D /= np.sum(gaus2D)
    return gaus2D

def my_normalize(src):
    dst = src.copy()
    dst *= 255
    dst = np.clip(dst, 0, 255)
    return dst.astype(np.uint8)

def my_padding(src, pad_shape):
    (h, w) = src.shape
    (p_h, p_w) = pad_shape
    pad_img = np.zeros((h+2*p_h, w+2*p_w))
    pad_img[p_h:p_h+h, p_w:p_w+w] = src
    return pad_img

def my_filtering(src, mask):
    (h, w) = src.shape
    (m_h, m_w) = mask.shape
    pad_img = my_padding(src, (m_h//2, m_w//2))
    dst = np.zeros((h, w))
    for row in range(h):
        for col in range(w):
            val = np.sum(pad_img[row:row + m_h, col:col + m_w] * mask)
            dst[row, col] = val
    return dst

def add_gaus_noise(src, mean=0, sigma=0.1):
    #src : 0 ~ 255, dst : 0 ~ 1
    dst = src/255
    h, w, c = dst.shape
    noise = np.random.normal(mean, sigma, size=(h, w, c))
    dst += noise
    return my_normalize(dst)

def my_bilateral(src, msize, sigma, sigma_r):

    (h, w) = src.shape
    m_s = msize // 2
    img_pad = my_padding(src, pad_shape=(m_s, m_s))
    dst = np.zeros((h, w))

    y, x = np.mgrid[-m_s:m_s + 1, -m_s:m_s + 1]

    for i in range(h):
        print('\r%d / %d ...' %(i,h), end="")
        for j in range(w):
            k = y + i
            l = x + j
            mask = np.exp( -(((i - k)**2) / (2 * sigma**2)) -(((j-l)**2) / (2 * sigma**2)) ) * np.exp( -(((img_pad[i+m_s, j+m_s] - img_pad[k+m_s, l+m_s])**2)/(2*sigma_r**2)) )
            mask = mask/mask.sum()
            dst[i, j] = np.sum(img_pad[i:i + msize, j:j + msize] * mask)
    return dst

def my_median_filtering(src, msize):
    h, w = src.shape

    dst = np.zeros((h, w))
    for row in range(h):
        for col in range(w):
            r_start = np.clip(row - msize // 2, 0, h)
            r_end = np.clip(row + msize // 2, 0, h)

            c_start = np.clip(col - msize // 2, 0, w)
            c_end = np.clip(col + msize // 2, 0, w)
            mask = src[r_start:r_end, c_start:c_end]
            dst[row, col] = np.median(mask)

    return dst.astype(np.uint8)

if __name__ == '__main__':
    src = cv2.imread('canoe.png')
    np.random.seed(seed=100)

    noise_image = add_gaus_noise(src, mean=0, sigma=0.1)

    src_noise = noise_image.astype(np.float32)

    ##apple

    rgb_bilateral_dst = np.zeros_like(src)
    rgb_gaussian_dst = np.zeros_like(src)
    rgb_median_dst = np.zeros_like(src)

    for i in range(3):
        rgb_bilateral_dst[:, :, i] = my_bilateral(src_noise[:, :, i], msize=5, sigma=10, sigma_r=0.1)
        rgb_gaussian_dst[:, :, i] = my_filtering(src_noise[:, :, i], my_get_Gaussian2D_mask(5, sigma=1))
        rgb_median_dst[:, :, i] = my_median_filtering(src_noise[:, :, i], msize=5)

    
    yuv_img = cv2.cvtColor(src_noise, cv2.COLOR_BGR2YUV)
    yuv_bilateral_dst = np.zeros_like(yuv_img)
    yuv_gaussian_dst = np.zeros_like(yuv_img)
    yuv_median_dst = np.zeros_like(yuv_img)

    for i in range(3):
        yuv_bilateral_dst[:, :, i] = my_bilateral(yuv_img[:, :, i], msize=5, sigma=10, sigma_r=0.1)
        yuv_gaussian_dst[:, :, i] = my_filtering(yuv_img[:, :, i], my_get_Gaussian2D_mask(5, sigma=1))
        yuv_median_dst[:, :, i] = my_median_filtering(yuv_img[:, :, i], msize=5)

    rgb_bilateral_dst = my_normalize(rgb_bilateral_dst)
    rgb_gaussian_dst = my_normalize(rgb_gaussian_dst)
    rgb_median_dst = my_normalize(rgb_median_dst)

    yuv_bilateral_dst = cv2.cvtColor(my_normalize(yuv_bilateral_dst), cv2.COLOR_YUV2BGR)
    yuv_gaussian_dst = cv2.cvtColor(my_normalize(yuv_gaussian_dst), cv2.COLOR_YUV2BGR)
    yuv_median_dst = cv2.cvtColor(my_normalize(yuv_median_dst), cv2.COLOR_YUV2BGR)

    #banana

    cv2.imshow('original.png', src)
    cv2.imshow('RGB bilateral', rgb_bilateral_dst)
    cv2.imshow('RGB gaussian', rgb_gaussian_dst)
    cv2.imshow('RGB median', rgb_median_dst)


    cv2.imshow('YUV bilateral', cv2.cvtColor(yuv_bilateral_dst, cv2.COLOR_YUV2BGR))
    cv2.imshow('YUV gaussian', cv2.cvtColor(yuv_gaussian_dst, cv2.COLOR_YUV2BGR))
    cv2.imshow('YUV median', cv2.cvtColor(yuv_median_dst, cv2.COLOR_YUV2BGR))

    cv2.waitKey()
    cv2.destroyAllWindows()

正在打印的图像应该不会与原始图像有太大差异,但它出来的时候很奇怪。从评论应用到香蕉,我写了代码。我认为这是错误的,因为输入图像的颜色和输出图像的颜色不匹配。if函数上面的其他函数都是完整的代码,没有任何问题。我很感激你对我写的代码的帮助。
output image
original image

f87krz0w

f87krz0w1#

颜色变化的主要原因与算术溢出有关。
uint8 dtype的OpenCV有效像素范围为[0,255]。
float32 dtype的OpenCV有效像素范围为[0,1]。
我们最好在开始时将输入转换为float32和范围[0,1],应用过滤器,并在最后转换回范围[0,255]中的uint8
方法my_normalize缩放255并转换为uint8-我们必须确保my_normalize的输入图像在范围[0,1]内是float32(或float64)。
也存在YUV到BGR转换被执行两次的情况。
更新代码:

import numpy as np
import cv2
import time

def my_get_Gaussian2D_mask(msize, sigma=1):
    y, x = np.mgrid[-(msize // 2):(msize // 2) + 1,
           -(msize // 2):(msize // 2) + 1]

    gaus2D = 1 / (2 * np.pi * sigma**2) * \
             np.exp(-(( x**2 + y**2 )/(2 * sigma**2)))

    gaus2D /= np.sum(gaus2D)
    return gaus2D

def my_normalize(src):
    dst = src.copy()
    dst *= 255
    dst = np.clip(dst, 0, 255)
    return dst.astype(np.uint8)

def my_padding(src, pad_shape):
    (h, w) = src.shape
    (p_h, p_w) = pad_shape
    pad_img = np.zeros((h+2*p_h, w+2*p_w))
    pad_img[p_h:p_h+h, p_w:p_w+w] = src
    return pad_img

def my_filtering(src, mask):
    (h, w) = src.shape
    (m_h, m_w) = mask.shape
    pad_img = my_padding(src, (m_h//2, m_w//2))
    dst = np.zeros((h, w))
    for row in range(h):
        for col in range(w):
            val = np.sum(pad_img[row:row + m_h, col:col + m_w] * mask)
            dst[row, col] = val
    return dst

def add_gaus_noise(src, mean=0, sigma=0.1):
    #src : 0 ~ 255, dst : 0 ~ 1
    dst = src/255
    h, w, c = dst.shape
    noise = np.random.normal(mean, sigma, size=(h, w, c))
    dst += noise
    return my_normalize(dst)


def my_bilateral(src, msize, sigma, sigma_r):
    (h, w) = src.shape
    m_s = msize // 2
    img_pad = my_padding(src, pad_shape=(m_s, m_s))
    dst = np.zeros((h, w))

    y, x = np.mgrid[-m_s:m_s + 1, -m_s:m_s + 1]

    for i in range(h):
        print('\r%d / %d ...' %(i,h), end="")
        for j in range(w):
            k = y + i
            l = x + j
            mask = np.exp( -(((i - k)**2) / (2 * sigma**2)) -(((j-l)**2) / (2 * sigma**2)) ) * np.exp( -(((img_pad[i+m_s, j+m_s] - img_pad[k+m_s, l+m_s])**2)/(2*sigma_r**2)) )
            mask = mask/mask.sum()
            dst[i, j] = np.sum(img_pad[i:i + msize, j:j + msize] * mask)
    return dst

def my_median_filtering(src, msize):
    h, w = src.shape

    dst = np.zeros((h, w))
    for row in range(h):
        for col in range(w):
            r_start = np.clip(row - msize // 2, 0, h)
            r_end = np.clip(row + msize // 2, 0, h)

            c_start = np.clip(col - msize // 2, 0, w)
            c_end = np.clip(col + msize // 2, 0, w)
            mask = src[r_start:r_end, c_start:c_end]
            dst[row, col] = np.median(mask)

    #return dst.astype(np.uint8)
    return dst.astype(np.float32)  # Convert to type float32 (assume range is still range of float32 [0, 1]).

if __name__ == '__main__':
    src = cv2.imread('canoe.png')

    np.random.seed(seed=100)

    noise_image = add_gaus_noise(src, mean=0, sigma=0.1)  # Pass src as uint8 because add_gaus_noise assumes range [0, 255].

    src_noise = noise_image.astype(np.float32) / 255  # Convert src_noise from uint8 range [0, 255] to float32 valid range [0, 1]
    
    src = src.astype(np.float32) / 255  # Convert src from uint8 range [0, 255] to float32 valid range [0, 1]

    ##apple

    rgb_bilateral_dst = np.zeros_like(src)
    rgb_gaussian_dst = np.zeros_like(src)
    rgb_median_dst = np.zeros_like(src)

    for i in range(3):
        rgb_bilateral_dst[:, :, i] = my_bilateral(src_noise[:, :, i], msize=5, sigma=10, sigma_r=0.1)
        rgb_gaussian_dst[:, :, i] = my_filtering(src_noise[:, :, i], my_get_Gaussian2D_mask(5, sigma=1))
        rgb_median_dst[:, :, i] = my_median_filtering(src_noise[:, :, i], msize=5)
   
    yuv_img = cv2.cvtColor(src_noise, cv2.COLOR_BGR2YUV)
    yuv_bilateral_dst = np.zeros_like(yuv_img)
    yuv_gaussian_dst = np.zeros_like(yuv_img)
    yuv_median_dst = np.zeros_like(yuv_img)

    for i in range(3):
        yuv_bilateral_dst[:, :, i] = my_bilateral(yuv_img[:, :, i], msize=5, sigma=10, sigma_r=0.1)
        yuv_gaussian_dst[:, :, i] = my_filtering(yuv_img[:, :, i], my_get_Gaussian2D_mask(5, sigma=1))
        yuv_median_dst[:, :, i] = my_median_filtering(yuv_img[:, :, i], msize=5)

    rgb_bilateral_dst = my_normalize(rgb_bilateral_dst)
    rgb_gaussian_dst = my_normalize(rgb_gaussian_dst)
    rgb_median_dst = my_normalize(rgb_median_dst)

    cv2.imshow('rgb_bilateral_dst', rgb_bilateral_dst)
    cv2.imshow('rgb_gaussian_dst', rgb_gaussian_dst)
    cv2.imshow('rgb_median_dst', rgb_median_dst)

    yuv_bilateral_dst = cv2.cvtColor(my_normalize(yuv_bilateral_dst), cv2.COLOR_YUV2BGR)
    yuv_gaussian_dst = cv2.cvtColor(my_normalize(yuv_gaussian_dst), cv2.COLOR_YUV2BGR)
    yuv_median_dst = cv2.cvtColor(my_normalize(yuv_median_dst), cv2.COLOR_YUV2BGR)

    #banana

    cv2.imshow('original.png', src)
    cv2.imshow('RGB bilateral', rgb_bilateral_dst)
    cv2.imshow('RGB gaussian', rgb_gaussian_dst)
    cv2.imshow('RGB median', rgb_median_dst)

    # Avoid converting twice from YUV to BRG
    #cv2.imshow('YUV bilateral', cv2.cvtColor(yuv_bilateral_dst, cv2.COLOR_YUV2BGR))
    #cv2.imshow('YUV gaussian', cv2.cvtColor(yuv_gaussian_dst, cv2.COLOR_YUV2BGR))
    #cv2.imshow('YUV median', cv2.cvtColor(yuv_median_dst, cv2.COLOR_YUV2BGR))
    cv2.imshow('YUV bilateral', yuv_bilateral_dst)
    cv2.imshow('YUV gaussian', yuv_gaussian_dst)
    cv2.imshow('YUV median', yuv_median_dst)

    cv2.waitKey()
    cv2.destroyAllWindows()

输出图像(截图):

相关问题