在Matlab中,当图像在YCbCr中时,如何使用色度子采样将4:4:4图像缩小到4:2:0?

在Matlab中,当图像在YCbCr中时,如何使用色度子采样将4:4:4图像缩小到4:2:0?,matlab,multimedia,subsampling,Matlab,Multimedia,Subsampling,我已经将jpg图像从RGB转换为YCbCr,但现在必须使用色度子采样使其为4:2:0。我已经搜索过了,但没有找到任何关于如何执行此操作的信息(注意:我对Matlab非常陌生) 编辑:我现在有这个,但在我设置ycbcr(:,:,2)=newCb的底部,它说“无法执行赋值,因为左侧的大小是1273-by-1910,右侧的大小是 1273-by-955-by-0。“ 您只需在每个轴上将Cb和Cr的大小调整0.5倍即可: 假设: YUV = rgb2ycbcr(RGB); Y = YUV(:, :, 1

我已经将jpg图像从RGB转换为YCbCr,但现在必须使用色度子采样使其为4:2:0。我已经搜索过了,但没有找到任何关于如何执行此操作的信息(注意:我对Matlab非常陌生)

编辑:我现在有这个,但在我设置ycbcr(:,:,2)=newCb的底部,它说“无法执行赋值,因为左侧的大小是1273-by-1910,右侧的大小是 1273-by-955-by-0。“


您只需在每个轴上将
Cb
Cr
的大小调整0.5倍即可:

假设:

YUV = rgb2ycbcr(RGB);
Y = YUV(:, :, 1);
U = YUV(:, :, 2);
V = YUV(:, :, 3);
Y
频道未经修改(与4:4:4格式中的4:2:0的
Y
相同)

将样本
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(不使用内置功能)
  • 将结果保存到二进制文件
    im.yuv
  • 使用命令行工具将
    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)

结果(转换为YCbCr 420并使用FFmpeg转换回RGB后):

您只需在每个轴上将
Cb
Cr
的大小调整0.5倍即可:

假设:

YUV = rgb2ycbcr(RGB);
Y = YUV(:, :, 1);
U = YUV(:, :, 2);
V = YUV(:, :, 3);
Y
频道未经修改(与4:4:4格式中的4:2:0的
Y
相同)

将样本
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(不使用内置功能)
  • 将结果保存到二进制文件
    im.yuv
  • 使用命令行工具将
    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)

结果(转换为YCbCr 420并使用FFmpeg转换回RGB后):

虽然这很有意义,但我被直接指示不要使用imresize功能,这会使事情变得不必要的困难,因为我添加了一个不使用
imresize
的解决方案。非常感谢您的详细解释!实际上我在使用这个时遇到了麻烦。我也不允许使用基本的rgb2ycbcr函数,所以这可能会引起问题,但我转换的图像显示为2D阵列,而不是像我认为您显示给我的3D阵列access@Sanam使用
imresize
:仅将水平轴缩小1/4:
newU=imresize(U、[size(U,1)、size(U,2)/4])虽然这很有意义,但我直接被指示不要使用imresize函数,这会使事情变得不必要的困难,因为我添加了一个不使用
imresize
的解决方案。非常感谢您的详细解释!实际上我在使用这个时遇到了麻烦。我也不允许使用基本的rgb2ycbcr函数,所以这可能会引起问题,但我转换的图像显示为2D阵列,而不是像我认为您显示给我的3D阵列access@Sanam使用
imresize
:仅将水平轴缩小1/4:
newU=imresize(U、[size(U,1)、size(U,2)/4])您使用了错误的转换公式。您可以使用我的帖子中的公式:。请阅读问题和答案(忽略NV12订购部分)。您将收到错误消息,因为在MATLAB中,当每个平面具有不同的尺寸时,您无法创建3D矩阵。不能使用
imwrite
将输出保存到单个文件中。我可以推荐您使用
fope