Search code examples
matlabsubsampling

In Matlab, how can I use chroma subsampling to downscale a 4:4:4 image to 4:1:1 when the image is in YCbCr?


Following this exact question

In Matlab, how can I use chroma subsampling to downscale a 4:4:4 image to 4:2:0 when the image is in YCbCr?

where he is performing chroma downscaling from 4:4:4 to 4:2:0, I wanna dowscale from 4:4:4 to 4:1:1. Im not sure how to do that?

YUV = rgb2ycbcr(RGB);
Y = YUV(:, :, 1);
U = YUV(:, :, 2);
V = YUV(:, :, 3);

Performing downscaling

U = double(YUV(:, :, 2))
V = double(YUV(:, :, 3))

newU = ??
newV =??

Can anyone please help me?

Thanks in advance.


Solution

  • In YUV 4:1:1, the chroma channels are down-sampled by a factor of 1/4 in the horizontal axis.

    Using imresize, the solution is simple:

    newU = imresize(U, [size(U, 1), size(U, 2)/4]);
    newV = imresize(V, [size(V, 1), size(V, 2)/4]);
    

    Notes:

    • The above solution is valid, only if the horizontal resolution of the input is a multiple of 4.
    • The default arguments of imresize applies cubic interpolation with antialiasing enabled.
      Most real-world implementations uses simpler interpolation methods, like linear interpolation without antialiasing.
    • YUV 4:1:1 (synonym for Y:Cb:Cr 4:1:1) refers chroma down-sampling, but there are multiple options of ordering the components in streaming video or in RAM or file.

    Chroma subsampling illustrations:
    enter image description here [https://robbeekmans.net/euc/vmware-horizon-7-4-blast-gets-necessary-update-support-chroma-subsampling-444-h-264/]

    Another illustration:
    enter image description here [https://academickids.com/encyclopedia/index.php/YUV_4:2:0]


    Implementing without using imresize:

    In case you want the same result as imresize (bilinear without Antialiasing):

    refU = imresize(U, [size(U, 1), size(U, 2)/4], 'bilinear', 'Antialiasing', false);
    % refV = ...
    

    The following code is equivalent:

    U = double(U);
    V = double(U);
    newU = uint8(round(U(:, 2:4:end) + U(:, 3:4:end))/2);
    newV = uint8(round(V(:, 2:4:end) + V(:, 3:4:end))/2);
    

    You may also use the average of every 4 elements (better if reducing noise is important):

    U = double(U);
    V = double(V);
    newU = uint8(round((U(:, 1:4:end) + U(:, 2:4:end) + U(:, 3:4:end) + U(:, 4:4:end))/4));
    newV = uint8(round((V(:, 1:4:end) + V(:, 2:4:end) + V(:, 3:4:end) + V(:, 4:4:end))/4));
    

    Note:
    I prefer the term "down-sampling" over "sub-sampling".
    Sub-sampling by 1/4 means skipping - sample every 4 element, and ignore the other 3.
    Historically, in analog (or mixed analog/digital) video systems, the conversion to 4:1:1 most likely performed by analog sub-sampling.
    In digital systems, when you already have the 4:4:4 information, it's better to average samples than skip samples.
    I think the term "down-sampling" is more adequate (but "sub-sampling" is the commonly used term).