创建以YUVtoJPEG为名称的M文件,读取CIF格式的YUV文件mobile_cif_300f.yuv的前60帧,并逐一以jpg格式保存各视频帧至当前目录下,视频帧帧号命名相对应的jpg图片。保存的jpg图片满足以下条件:
第1-10帧,视频帧缩小1倍后,利用双线性内插法放大回原尺寸;
第11-20帧,对视频帧混入椒盐噪声,再作中值滤波;
第21-30帧,对视频帧混入高斯噪声,再作图像维纳滤波复原;
第31-40帧,对视频帧作直方图均衡化;
第41-50帧,对视频帧作Sobel边缘检测,将边缘点像素值增大为原值的1.2倍;
第51-60帧,将视频帧的DCT变换系数取值前30%置为0,并重建视频帧;
计算第1-60帧处理后视频帧与原始视频帧在Y通道上的PSNR值,并显示出PSNR值随帧号的变化曲线。
注:上述所有处理均在Y通道,UV通道不作处理。
%YUVtoJPEG.m
clc;clear;
%
[Y,U,V] = ReadMultiFrames('mobile_cif_300f.yuv','cif',[0,60]);
len = size(Y,3);
psnr = [];
for ii = 1:len
Yc = Y(:,:,ii);
Uc = U(:,:,ii);
Vc = V(:,:,ii);
if ii<=10
Yd = fun1(Yc);
elseif ii<=20
Yd = fun2(Yc);
elseif ii<=30
Yd = fun3(Yc);
elseif ii<=40
Yd = fun4(Yc);
elseif ii<=50
Yd = fun5(Yc);
else
Yd = fun6(Yc);
end
tmp = PSNR(Yc,Yd);
psnr = [psnr,tmp];
im_rgb = yuv2rgb(Yd,Uc,Vc);
imwrite(uint8(im_rgb),[num2str(ii),'.jpg']);
end
plot(psnr);
function Yd = fun1(Yc)
w = fspecial('average',[5,5]);
Yc = imfilter(Yc,w);
Yc = Yc(1:2:end,1:2:end);
Yd = imresize(Yc,2,'bilinear');
end
function Yd = fun2(Yc)
Yc = uint8(Yc);
J = imnoise(Yc,'salt & pepper',0.05);
B = ordfilt2(J,13,ones(5,5));
Yd = double(B);
end
function Yd = fun3(Yc)
Yc = mat2gray(Yc);
J = imnoise(Yc,'gaussian',0,0.05);
B = wiener2(J,[5 5]);
Yd = double(255*B);
end
function Yd = fun4(Yc)
Yc = uint8(Yc);
Yd = histeq(Yc);
Yd = double(Yd);
end
function Yd = fun5(Yc)
BW = edge(Yc,'sobel');
Yc(BW(:)) = Yc(BW(:))*1.2;
Yd = Yc;
end
function Yd = fun6(Yc)
d = dct2(Yc);
[tmp,idx] = sort(d(:),'descend');
idx1 = idx(1:round(length(idx)*0.3));
d(idx1) = 0;
Yd = idct2(d);
end
function r = PSNR(x1,x2)
x1 = double(x1);
x2 = double(x2);
mes = x1-x2;
r = 10 * log10(255^2 / mean(mes(:).^2));
end
function im_rgb = yuv2rgb(Yd,Uc,Vc)
Uc = imresize(Uc,2);
Vc = imresize(Vc,2);
R = Yd + 1.4075*(Vc-128);
G = Yd - 0.3455*(Uc-128) - 0.7169*(Vc-128);
B = Yd + 1.7790*(Uc-128);
im_rgb = cat(3,R,G,B);
im_rgb(im_rgb>255) = 255;
im_rgb(im_rgb<0) = 0;
end
function [Y,U,V] = ReadMultiFrames(yuvfilename,format,init2last)
%该函数用于将yuv格式的视频连续多帧分别读入到三维数组Y,U,V之中
%yuv视频的采样格式为4:2:0
%输入参数:
% yuvfilename ---- 视频yuv文件路径名
% format ---- 视频格式(格式名or分辨率[rows,cols])
% init2last ---- 读取的视频帧的范围[初始帧序号,终止帧序号]
%输出参数:
% Y ---- 亮度,三维数组,第三维为帧序号,前两维是单帧的行和列
% U,V ---- 色差,三维数组,第三维为帧序号,前两维是单帧的行和列
%调用示范:
% [Y,U,V] = ReadMultiFrames('.\videoname.yuv','cif',[100,101]);
% [Y,U,V] = ReadMultiFrames('.\videoname.yuv',[288,352],[100,101]);
close all;
if ischar(format)
format = lower(format);
switch format
case 'sub_qcif'
cols = 128; rows = 96;
case 'qcif'
cols = 176; rows = 144;
case 'cif'
cols = 352; rows = 288;
case 'sif'
cols = 352; rows = 240;
case '4cif'
cols = 704; rows = 576;
otherwise
error('no format!');
end
elseif isequal(size(format),[1,2])||isequal(size(format),[2,1])
cols = format(2);rows = format(1);
else
error('第二参数输入有误!');
end
point = fopen(yuvfilename,'r');
if point == -1
error('打开文件失败!');
end
order_num = init2last(1);
frames_num = init2last(2) - order_num + 1;
k = 0;
Y = zeros(rows,cols,frames_num);
U = zeros(rows/2,cols/2,frames_num);
V = U;
offset = order_num*(rows*cols + rows*cols/2);
status = fseek(point,offset,'bof');
pro = fread(point,1,'uchar');
if (isempty(pro)&&feof(point)) || status ~=0
error('读取位置定位失败!');
end
fseek(point,-1,'cof');
for ii = 1:frames_num
k = k + 1;
pro = fread(point,1,'uchar');
if feof(point)&&isempty(pro)
disp('读取帧数范围已超过yuv视频总帧数!');
Y = Y(:,:,1:k-1);
U = U(:,:,1:k-1);
V = V(:,:,1:k-1);
break;
end
fseek(point,-1,'cof');
temp = fread(point,[cols,rows],'uchar');
Y(:,:,ii) = temp';
temp = fread(point,[cols/2,rows/2],'uchar');
U(:,:,ii) = temp';
temp = fread(point,[cols/2,rows/2],'uchar');
V(:,:,ii) = temp';
end
fclose(point);
end