运动自适应降噪_Motion Adaptive Noise Reduction
转载于:运动自适应降噪_Motion Adaptive Noise Reduction
CMOS传感器在工作过程中会生成热噪声、散粒噪声等,其中散粒噪声是一种随机噪声,其变化符合泊松分布,它存在严重影响图像的信噪比(SNR)。通常而言,此类噪声会通过软件算法采用多帧平均的方法进行抑制,这种方法即我们常说的3D降噪。本文我们将以Xilinx的运动自适应降噪算法为例,了解其工作原理及算法效果。
本文参考了两篇Xilinx的说明文档,见下链接:
LogiCORE IP Motion AdaptiveNoise Reduction v1.1
Motion Adaptive Noise Reduction v6.1 Product Guide
1. MANR算法原理
该算法使用了一个递归滤波器(类似于IIR滤波器),核心是使用运动传递函数(Motion Transfer Function, MTF)控制降噪曲线的形状与力度。具体步骤为:
1. 计算运动量motion value:计算像素点的亮度值在当前帧与上一帧的绝对差值。
Taking the absolute value of the difference in luma for the current and previous pixels.
2. 对上一步计算的运动量进行FIR滤波,滤波器固定为[1,3,8,3,1]。这里使用FIR滤波器的目的是降低噪声的干扰,使用当前像素在水平方向的1x5窗口内的运动量值进行加权平均。
This value is then filtered through a fixed coefficient FIR filter to form a scalar value representing the motion value present in the pixel for the current video frame.
3. 将上一步计算的结果作为MTF查找表的索引值。MTF的实际作用是得到当前帧像素点值与上一帧像素点值对滤波结果的权重,即Yout = m*Yprev+(1-m)*Yin中的m值。m值由运动量决定,运动量越大,表明上一帧值与当前帧值差异大,可能像素点存在运动偏移,因此Yprev应该占较小比重,m值越小;运动量越小,表明像素点很可能出现在背景区域,此时Yprev的权重可以稍大,代表加入更多的前帧值影响,注意这里的前帧并不仅仅指上一帧的图像,而是前N-1帧的加权结果,从而滤波效果更明显。一个典型的MTF曲线为:
上图的横坐标代表运动量索引值,纵坐标代表递归量(实际指代m值)。MTF查找表包含64个索引值,每个索引值对应的数据范围是[0, 255]。
This motion value is used as an index to the MTF look-up table. MTF look-up talbe is a 1D array of 64 integers in the range of 0 to 255。
4. 基于MTF查找表的值计算出实际降噪后的值:Yout = m*(Yprev-Yin)+Yin=m*Yprev+(1-m)*Yin。并且将Yout写入内存作为下一帧运算的上一帧结果,从而形成了一个递归的滤波器。
整体的算法流程图为:
其中,m值由亮度通道上的像素计算而来,色度通道使用相同的m值进行滤波。
2. 算法实现与视觉效果对比
算法原理中的第一步有点含糊不清,计算绝对差值后进行FIR滤波,FIR滤波是固定的1x5窗口,因此算法实现时同样采用计算1x5窗口的绝对差值。
clc;
clear all;
close all;
%% 1. 读取Lena图像
image = imread('lena.png');
%% 2. 添加噪声,生成二十帧含有噪声的图像
frames = 20;
[rows, cols, chnls] = size(image);
var_noise = rand(1,frames)*0.1; %噪声方差
for i=1:frames
image_noise(:,:,:,i) = imnoise(image,'gaussian',0,var_noise(i)); %依次对原始图像加噪
end
figure(1);
montage(image_noise(:,:,:,11:end)); %显示后十帧含有噪声的图像
title('加噪后图像(后十帧)');
%% 3. 降噪
% 生成MTF曲线
x = 0:1:63;
y = 1 - exp(-10./x);
MTF_LUT = floor(255*y);
figure(2),
plot(MTF_LUT);
title('MTF curve');
% 降噪处理
img_prev = zeros(rows, cols, chnls);
image_denoise = zeros(rows, cols, chnls, frames);
for k=1:frames
img_curr = double(rgb2ycbcr(image_noise(:,:,:,k))); %rgb域转到ycbcr域
if(k == 1) %第一帧不作处理
img_prev = img_curr;
image_denoise(:,:,:,k) = image_noise(:,:,:,k);
continue;
end
img_curr_y = img_curr(:, :, 1);
img_curr_u = img_curr(:, :, 2);
img_curr_v = img_curr(:, :, 3);
img_prev_y = img_prev(:, :, 1);
img_prev_u = img_prev(:, :, 2);
img_prev_v = img_prev(:, :, 3);
img_curr_y_pad = img_curr_y(1:rows, [1 1 1:cols cols cols]); %padding
img_curr_u_pad = img_curr_u(1:rows, [1 1 1:cols cols cols]);
img_curr_v_pad = img_curr_v(1:rows, [1 1 1:cols cols cols]);
img_prev_y_pad = img_prev_y(1:rows, [1 1 1:cols cols cols]);
img_prev_u_pad = img_prev_u(1:rows, [1 1 1:cols cols cols]);
img_prev_v_pad = img_prev_v(1:rows, [1 1 1:cols cols cols]);
for i = 1:rows
for j = 1:cols
win_curr = img_curr_y_pad(i, j:j+4);
win_prev = img_prev_y_pad(i, j:j+4);
win_abs = abs(win_curr - win_prev); %计算运动量
win_motion = sum(win_abs .*[1 3 8 3 1])/64; %FIR滤波
m(i,j) = MTF_LUT(floor(win_motion)+1); %MTF查找
end
end
tmp_y = img_curr_y + m.*(img_prev_y - img_curr_y)/256; %加权滤波
tmp_u = img_curr_u + m.*(img_prev_u - img_curr_u)/256;
tmp_v = img_curr_v + m.*(img_prev_v - img_curr_v)/256;
img_prev = cat(3, tmp_y, tmp_u, tmp_v); %recursive filter,将当前结果作为下一帧的img_prev
img_output = ycbcr2rgb(uint8(cat(3, tmp_y, tmp_u, tmp_v))); %ycbcr域转rgb域保存结果
image_denoise(:,:,:,k) = img_output;
end
image_denoise = uint8(image_denoise);
%% 4. show image (10 pictures)
figure(3);
montage(image_denoise(:,:,:,11:end)); %显示后十帧结果图像
title('降噪后图像(后十帧)');
实验结果:
实验证明该算法能明显消除图像中的彩色噪点,但只使用该算法进行降噪图像中的噪声依旧明显。可以通过调整MTF曲线来加强或者减弱降噪的强度。例如:当使用如下MTF曲线时,图像降噪较弱。
x = 0:1:63;
y = 1 - exp(-1./x);
MTF_LUT = floor(255*y);
figure(2),
plot(MTF_LUT);
title('MTF curve');
实验就简单地做到这了,欢迎大家对该方法进行讨论~