matlab - 在 Matlab 中,当图像在 YCbCr 中时,如何使用色度二次采样将 4:4:4 图像缩小到 4:2:0?
问题描述
我已经将 jpg 图像从 RGB 转换为 YCbCr,但现在必须使用 Chroma Subsampling 使它们成为 4:2:0。我已经搜索但没有找到有关如何执行此操作的任何信息(注意:我对 Matlab 很陌生)
编辑:我现在有了这个,但是在我设置 ycbcr(:,:,2) = newCb 的底部它说“无法执行分配,因为左侧的大小是 1273-by-1910 和右侧的大小边是 1273×955×0。”
function f = conversion(source_image, source_name)
image = imread(source_image);
% conversion_matrix = [0.299 -0.168736 0.5;
% 0.587 -.0331264 -.0418688;
% 0.114 0.5 -.081312];
conversion_matrix = [0.299 0.587 0.114;
-0.168736 -.0331264 0.5;
0.5 -.0418688 -.081312];
ycbr = reshape(double(image),[],3)*conversion_matrix;
ycbr = reshape(uint8(ycbr),size(image));
Y = ycbr(:,:,1)+ 0;
Cb = ycbr(:,:,2)+ 0.5;
Cr = ycbr(:,:,3)+ 0.5;
Cb = double(Cb);
newCb = uint8(round((Cb(:,1:2:end, 1:2:end) + Cb(:,2:2:end, 1:2:end) + Cb(:,1:2:end, 2:2:end) + Cb(:,2:2:end, 2:2:end)) / 4));
Cr = double(Cr);
newCr = uint8(round((Cr(:,1:2:end, 1:2:end) + Cr(:,2:2:end, 1:2:end) + Cr(:,1:2:end, 2:2:end) + Cr(:,2:2:end, 2:2:end)) / 4));
ycbcr(:,:,1) = Y;
ycbcr(:,:,2) = newCb;
ycbcr(:,:,3) = newCr;
imshow(ycbcr);
imwrite(ycbcr, source_name);
f = ycbcr;
解决方案
您可以简单地将每个轴的大小调整为 0.5 倍 Cb
:Cr
认为:
YUV = rgb2ycbcr(RGB);
Y = YUV(:, :, 1);
U = YUV(:, :, 2);
V = YUV(:, :, 3);
Y
通道未修改(Y
4:2:0 与 4:4:4 格式相同)
下采样U
和V
0.5 倍以获得 4:2:0 格式:
newU = imresize(U, 0.5);
newV = imresize(V, 0.5);
在 MATLAB 中,您通常喜欢保留 420 个结果Y
、newU
和newV
3 个矩阵(平面格式),而不是将这些矩阵合并为一个矩阵。
4:2:0 格式不规定特定组件的顺序(如 I420 或 NV12...),因此这三个矩阵被认为是 4:2:0 格式。
不使用下采样imresize
:
您可以下采样U
并V
使用以下代码示例:
U = double(U);
newU = uint8(round((U(1:2:end, 1:2:end) + U(2:2:end, 1:2:end) + U(1:2:end, 2:2:end) + U(2:2:end, 2:2:end)) / 4));
结果等效于使用双线性插值调整大小,没有抗锯齿滤波器:
shrunkU = imresize(U, 0.5, 'bilinear', 'Antialiasing', false);
更新:
- 您发布的转换公式不正确(至少与 MATLAB 内置
rgb2ycbcr
转换公式不同)。
MATLAB 转换公式符合 BT.601“有限范围”标准。 - 看起来你在矩阵乘法向量中有一个错误。
- 正如我所评论的,我建议您将 420 结果保存到二进制文件中。
以下代码示例执行以下步骤:
- 在不使用内置函数的情况下将 RGB 转换为 YCbCr,并将结果与 MATLAB
rgb2ycbcr
结果进行比较。 - 从 YCbCr 444 转换为 YCbCr 420(不使用内置函数)。
- 将 420 结果保存到二进制文件
im.yuv
- 使用FFmpeg命令行工具 转换
im.yuv
为 PNG 格式,并显示结果。
这是代码:
RGB = imresize(imread('autumn.png'), [100, 170]); % Load RGB image for testing (and resize)
% Convert to YCbCr using MATLAB builtin function (used as reference)
refYUV = rgb2ycbcr(RGB);
% Conversion matrix applies BT.601 standard ("limited range").
T = [ 0.2568 0.5041 0.0979
-0.1482 -0.2910 0.4392
0.4392 -0.3678 -0.0714];
% Conversion offset (for "limted range" standard the offset for Y channel is 16)
offset = [16
128
128];
% Manual conversion from RGB to YCbCr (YUV is a shortcut name from YCbCr):
% Multiply T matrix (from the left side) by three "long rows" of RGB elements and add offsets vector.
YUV = T*(reshape(double(RGB), [], 3))' + offset;
% Reshape YUV to the shape of RGB, and convert back to uint8.
YUV = uint8(reshape(YUV', size(RGB)));
% Verify that YUV equals refYUV (maximum difference result is 1 out of 255)
disp(['Max Diff = ', num2str(max(imabsdiff(YUV(:), refYUV(:))))]);
% Convert to YUV 420 (without builtin function):
Y = YUV(:, :, 1)
U = double(YUV(:, :, 2))
V = double(YUV(:, :, 3))
newU = uint8(round((U(1:2:end, 1:2:end) + U(2:2:end, 1:2:end) + U(1:2:end, 2:2:end) + U(2:2:end, 2:2:end)) / 4));
newV = uint8(round((V(1:2:end, 1:2:end) + V(2:2:end, 1:2:end) + V(1:2:end, 2:2:end) + V(2:2:end, 2:2:end)) / 4));
% Save result to YUV file (file format is going to be raw I420 foramt):
% Make sure to transpose the matrix before saving (becuase MATLAB is "column major", and fomrat is "row major").
f = fopen('im.yuv', 'w');
fwrite(f, Y', 'uint8');
fwrite(f, newU', 'uint8');
fwrite(f, newV', 'uint8');
fclose(f);
% Convert im.yuv to PNG format using FFmpeg (free command line tool).
% For Windows system, download stable stsatic build from https://ffmpeg.zeranoe.com/builds/
% Place ffmpeg.exe in the same path of the script (just for testing withing MATLAB)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
[status, cmdout] = system('ffmpeg -y -s 170x100 -i im.yuv -pix_fmt yuv420p im.png');
% Read and show im.png for testing:
I = imread('im.png');
imshow(I)
推荐阅读
- javascript - Node JS 在一个页面上使用多个注册助手
- javascript - 使用 scale(0) 而不是 display: none 的下拉菜单
- react-native - 反应原生链接挂在“资产已成功链接到您的项目”
- kubernetes - Kubernetes DNS 不解析外部地址
- javascript - Javascript - 游戏侧碰撞(从下到上)
- javascript - AJAX 获取请求不起作用
- java - 放基于字体大小的高度?
- mysql - 如果mysql表不存在则创建,否则添加缺少的列?
- reactjs - 在 React 中自动配置 Firebase SDK
- python - 在 python 中使用 opencv 在图像中显示特定颜色周围的边界