noise:时域降噪,图像平均的效果

VIDEO DENOISING BASED ON ADAPTIVE TEMPORAL AVERAGING
1.这篇论文时域去噪的论文很简单,就是对图像序列的当前帧查找附近的相似帧,然后进行平均。对于位移比较大的物体或者相机位移比较大时,都会出现重影的效果。
在这里插入图片描述

def denoise_adaptive_temp_average(imgs, thrA, thrB):
    imgs2 = []
    # 首先计算帧间差异
    N = len(imgs)
    print(N)
    d = np.zeros([N, N], dtype=np.float32)
    for i in range(N):
        for j in np.arange(i, N, 1):
            d[i][j] = np.mean(np.abs(imgs[i] - imgs[j]))
            d[j][i] = d[i][j]
    print("cal d finish! ")
    for i in np.arange(0, N):
        l = i
        r = i
        dl = 0
        dr = 0
        suml = 0
        sumr = 0
        while(dl < thrA and suml < thrB):
            if l > 0:
                l -= 1
                dl = d[l][i]
                suml += dl
            else:
                break
            #print(dl, suml, thrA, thrB)
        while (dr < thrA and sumr < thrB ):
            if r < N-1:
                r += 1
                dr = d[i][r]
                sumr += dr
            else:
                break
            #print(dr, sumr, thrA, thrB)
        # 计算 left - right image 的均值
        im_t = np.zeros(imgs[0].shape, dtype=np.float32)
        #print(im_t.dtype, imgs[0].dtype)
        for k in np.arange(l+1, r, 1):
            im_t += imgs[k]

        cnt = (r - l - 1)
        if cnt == 0:
            cnt = 1
            im_t = imgs[i]
        im_t = im_t // cnt
        imgs2.append(im_t.astype(np.uint8))

        #print(i, l, r, suml, sumr)
    return imgs2

2.即使只利用左右两帧的效果,也会有重影。可见判断运动时非常重要的。当r=1时,只利用左右两帧进行平均的code

def denoise_temp_average(imgs, r):
    imgs2 = []
    # 首先计算帧间差异
    N = len(imgs)
    s = imgs[0].shape

    for ii in np.arange(0, r, 1):
        imgs2.append(imgs[ii])

    for ii in np.arange(r, N-r):
        # cur = imgs[i]
        sum = np.zeros(s, dtype=np.float32)
        for k in np.arange(-r, r+1):
            sum += imgs[ii+k]

        sum = sum // (2*r+1)
        sum = np.clip(sum, 0, 255).astype(np.uint8)
        imgs2.append(sum)
    for ii in np.arange(N - r, N, 1):
        imgs2.append(imgs[ii])
    return imgs2

3.如果对每个像素进行判断呢,和当前像素在一定阈值内的相邻帧同一位置像素,作为候选点,然后进行平均。理论上应该更好,实际确实是感观更好一些
在这里插入图片描述

def denoise_adaptive_temp_pixel_average(imgs, r=3, thr1=10, thr2=0.2):
    '''
    前后各r帧中, 相同位置的pixel, 如果值相差在一定范围内,则作为候选帧
    '''
    s = imgs[0].shape
    imgs2 = []
    # 首先计算帧间差异
    N = len(imgs)
    if 2*r+1 > N:
        print("error: frame number is not enough, ", 2*r+1, "  ", N)
        return [-1]
    print("num is enough !")
    for ii in np.arange(0, r, 1):
        imgs2.append(imgs[ii])

    for i in np.arange(r, N - r):

        masks = np.zeros(imgs[0].shape, dtype=np.int32)
        sum = np.zeros(imgs[0].shape, dtype=np.float32)

        for k in np.arange(-r, r+1):
            mask1 = np.abs((imgs[i] - imgs[i+k])) < thr1
            mask2 = np.abs((imgs[i] - imgs[i+k]) / (imgs[i] + imgs[i+k] + 0.0001)) < thr2

            mask = np.logical_and(mask1, mask2).astype(np.int32)


            sum += imgs[i+k]*mask
            masks += mask
            #print(i, k, mask)
            # plt.figure()
            # plt.subplot(121)
            # plt.imshow((mask*255).astype(np.uint8), cmap='gray')
            # plt.subplot(122)
            # plt.imshow(imgs[i+k]*mask)

            #print(np.sum(masks<1)) # should be 0
            #print(masks)
        sum = sum // masks
        imgs2.append(np.clip(sum, 0, 255).astype(np.uint8))

    for ii in np.arange(N-r, N, 1):
        imgs2.append(imgs[ii])

    #plt.show()
    return imgs2

4.关于yuv文件转换的一些函数

"""
import os

import cv2
from matplotlib import pyplot as plt

"""
Threshold A is designed to react to abrupt changes in the input signal and
Threshold B is designed to react to continuous changes in the input signal

Threshold A and Threshold B were determined and used in further experiments. They are as follows:
ThresholdA = 5·σ, ThresholdB = 10·σ.
"""
import numpy as np

def split420(single_frame_data, height, width):
    t = height * width
    Y = single_frame_data[:t].reshape(height, width)
    U = single_frame_data[t:t//4*5].reshape(height//2, width//2)
    V = single_frame_data[t // 4 * 5:].reshape(height // 2, width // 2)
    return Y, U, V

def pixel_yuv2rgb(y, u, v):
    '''
    https://zhuanlan.zhihu.com/p/111069275
    像素的转换和转换公式
    '''
    r = y + (1.370705 * (v - 128))
    g = y - (0.698001 * (v - 128)) - (0.337633 * (u - 128))
    b = y + (1.732446 * (u - 128))
    return r, g, b
def cvt_yuv2rgb(Y, U, V):
    Y = Y.astype(np.float32)
    U = U.astype(np.float32)
    V = V.astype(np.float32)
    rgb = []
    h, w = Y.shape

    # for i in range(h):
    #     ii = i // 2
    #     for j in range(w):
    #         jj = j // 2
    #         y = Y[i, j]
    #         u = U[ii, jj]
    #         v = V[ii, jj]
    #         r, g, b = pixel_yuv2rgb(y, u, v)
    #         rgb.append([r,g,b])

    U2 = np.zeros([h, w], dtype=np.float32)
    U2[0::2, 0::2] = U
    U2[0::2, 1::2] = U
    U2[1::2, 0::2] = U
    U2[1::2, 1::2] = U
    V2 = np.zeros([h, w], dtype=np.float32)
    V2[0::2, 0::2] = V
    V2[0::2, 1::2] = V
    V2[1::2, 0::2] = V
    V2[1::2, 1::2] = V
    r, g, b = pixel_yuv2rgb(Y, U2, V2)
    rgb = cv2.merge([r,g,b])
    rgb = np.array(rgb).reshape(h, w, 3)
    rgb = np.clip(rgb, 0, 255).astype(np.uint8)
    return rgb

def cvt_single(single_frame_data, height, width, show_im=0):
    '''
    将一个YUV420 的数据解析为 Y, U, V ,并转换为rgb
    '''
    Y, U, V = split420(single_frame_data, height, width)
    if show_im:
        plt.figure()
        plt.subplot(131)
        plt.imshow(Y, cmap='gray')

        plt.subplot(132)
        plt.imshow(U)

        plt.subplot(133)
        plt.imshow(V)
        plt.show()

    rgb = cvt_yuv2rgb(Y, U, V)
    if show_im:
        plt.figure()
        plt.imshow(rgb)
        plt.show()
    return Y,U,V,rgb

5.主函数
测试图像:https://download.csdn.net/download/tywwwww/86264119

def cal_psnr(im1, im2):
    t = 10 * np.log10(255 ** 2 / np.mean(((im1 - im2) ** 2)))
    return t
if __name__ == "__main__":
    file = r'D:\dataset\video_test\bus_cif\bus_cif.yuv' # 90frame
    dirY = r'D:\dataset\video_test\bus_cif\Y'
    dirRGB = r'D:\dataset\video_test\bus_cif\RGB'
    if not os.path.exists(dirY):
        os.makedirs(dirY)
    if not os.path.exists(dirRGB):
        os.makedirs(dirRGB)

    data = np.fromfile(file, dtype=np.uint8)
    # print(len(data)/90)
    height = 288
    width = 352
    single_frame_size = height * width * 3 // 2
    frame_num = len(data) // single_frame_size

    fps = 30
    videoWriteRGB = cv2.VideoWriter(file[:-4] + 'RGB.avi', cv2.VideoWriter_fourcc('I', '4', '2', '0'), fps, (width, height))
    sigma = 20 # noise level

    Ys = []
    rgbs = []
    Yns = []
    rgbns = []
    start = 0
    for i in range(frame_num):
        print(i)
        single_frame_data = data[start:start+single_frame_size]
        start += single_frame_size
        Y, U, V, rgb = cvt_single(single_frame_data, height, width, show_im=0)
        # write
        videoWriteRGB.write(rgb[...,::-1])
        # add gauss noise
        Yn = Y + np.random.normal(0, sigma, Y.shape)
        rgbn = rgb + np.random.normal(0, sigma, rgb.shape)
        #Yn = np.clip(Yn, 0, 255).astype(np.uint8)         # 如果进行clip,降噪效果会变差
        #rgbn = np.clip(rgbn, 0, 255).astype(np.uint8)
        # save
        # cv2.imwrite(dirY + '\\'+str(i)+'.png', Y)
        # cv2.imwrite(dirRGB + '\\' + str(i) + '.png', rgb[...,::-1])
        # cv2.imwrite(dirY + '\\' + str(i) + 'n.png', Yn)
        # cv2.imwrite(dirRGB + '\\' + str(i) + 'n.png', rgbn[..., ::-1])
        # list
        Ys.append(Y)
        rgbs.append(rgb)
        Yns.append(Yn)
        rgbns.append(rgbn)

    thrA = 10 * sigma
    thrB = 30 * sigma

    USE_Y = 0
    USE_RGB = 1
    if USE_Y:
        denoised = denoise_adaptive_temp_average(Yns, thrA, thrB)
        denoised2 = denoise_temp_average(Yns, 2)
        denoised3 = denoise_adaptive_temp_pixel_average(Yns, r=5, thr1=4*sigma, thr2=0.2)

        NT = 99

        snr1 = cal_psnr(Ys[NT], Yns[NT])
        snr2 = cal_psnr(Ys[NT], denoised[NT])
        print(snr1, snr2)
        snr1 = cal_psnr(Ys[NT], Yns[NT])
        snr2 = cal_psnr(Ys[NT], denoised2[NT])
        print(snr1, snr2)
        snr1 = cal_psnr(Ys[NT], Yns[NT])
        snr2 = cal_psnr(Ys[NT], denoised3[NT])
        print(snr1, snr2)

        plt.figure()
        plt.subplot(131)
        plt.imshow(Ys[NT])
        plt.subplot(132)
        plt.imshow(Yns[NT])
        plt.subplot(133)
        plt.imshow(denoised3[NT])
        plt.show()

        for i in np.arange(0, frame_num):
            cv2.imwrite(dirY + '\\' + str(i) + 'dn.png', denoised[i])
        for i in np.arange(0, frame_num):
            cv2.imwrite(dirY + '\\' + str(i) + 'dn2.png', denoised2[i])
        for i in np.arange(0, frame_num):
            cv2.imwrite(dirY + '\\' + str(i) + 'dn3.png', denoised3[i])


    elif USE_RGB:
        denoised = denoise_adaptive_temp_average(rgbns, thrA, thrB)
        denoised2 = denoise_temp_average(rgbns, 2)
        denoised3 = denoise_adaptive_temp_pixel_average(rgbns, r=5, thr1=4*sigma, thr2=0.2)

        for i in np.arange(0, frame_num):
            cv2.imwrite(dirRGB + '\\' + str(i) + 'dn.png', denoised[i][..., ::-1])
        for i in np.arange(0, frame_num):
            cv2.imwrite(dirRGB + '\\' + str(i) + 'dn2.png', denoised2[i][..., ::-1])
        for i in np.arange(0, frame_num):
            cv2.imwrite(dirRGB + '\\' + str(i) + 'dn3.png', denoised3[i][..., ::-1])

方便具体分析:

"""
采用比较少的帧,更具体的分析下时域滤波的效果

QCIF Format
(176x144) = 25344

CIF Format
(352x288) = 101376
"""
import os

import cv2
import numpy as np
from matplotlib import pyplot as plt

from denoise_video.denoise_adaptive_temporal_averaging import denoise_temp_average, cal_psnr, \
    denoise_adaptive_temp_pixel_average

if __name__ == "__main__":
    # salesman_qcif
    dirY = r'D:\dataset\video_test\bus_cif\Y'
    dirRGB = r'D:\dataset\video_test\bus_cif\RGB'

    dir = dirRGB
    k = 100
    n = 20
    sigma = 20

    imgs = []
    imgns = []
    for i in range(k-n,k+n+1):
        file = os.path.join(dir, str(i)+'.png')
        img = cv2.imread(file)
        img = img[:, :, ::-1]
        imgn = img + np.random.normal(0, sigma, img.shape)
        imgs.append(img)
        imgns.append(imgn)
    r = 4
    imgs2 = denoise_temp_average(imgns, r)
    imgs3 = denoise_adaptive_temp_pixel_average(imgns, 2*r, thr1=2*sigma, thr2=0.2)


    psnr = cal_psnr(imgs[n], imgns[n])
    psnr2 = cal_psnr(imgs[n], imgs2[n])
    psnr3 = cal_psnr(imgs[n], imgs3[n])
    print('psnr :', psnr, psnr2, psnr3)

    plt.figure()
    plt.subplot(231)
    plt.imshow(imgs[n], cmap='gray')

    plt.subplot(232)
    plt.imshow(np.clip(imgns[n], 0, 255).astype(np.uint8))

    plt.subplot(233)
    plt.imshow(imgs2[n])
    plt.subplot(234)
    plt.imshow(imgs3[n])
    plt.show()


  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值