views:

36

answers:

1

There are many different colour conversions to YUV but they all have different results! Which one is officially correct?

This is the output from my test program. I have input R=128 G=50 B=50 (max value is 255). The table shows the converted YUV values, and the re-converted RGB values (which don't match the original).

./ColourConversion.exe 128 50 50 
         Y         U         V         R         G         B      Name
===============================================================================
         0         0         0       128        50        50      a) Original RGB Values
        79       116       162       128        50        49      b) Microsoft MSDN integer maths
        78       116       162       126        49        47      c) ITU-R BT.601
        73       120       162       127        49        49      d) HDTV ITU-R BT.709
        73       114       202       176        25        48      e) RGB to full-range YCbCr
        78       116       162       126        49        47      f) Book 'Video Demystified'

Here's my code (in C#):

using System;

namespace ColourConversion
{
    class MainClass
    {
        //Turn on debug to enter RGB values in 'red, geen & blue'
        public static bool debug = true;
        public static int red = 128;
        public static int green = 50;
        public static int blue = 50;


        //for printTidy()
        public static string alphabet = "abcdefghijklmnopqrstuvwxyz";
        public static int testCount = 0;

        public static void Main (string[] args)
        {
            //init variables
            int r, g, b, R, G, B, Y, U, V, C, D, E;
            r = g = b = R = G = B = Y = U = V = C = D = E = 0;

            //read user input if not in debug mode
            if (!debug) {
                if (args.Length < 3) {
                    //Print CLI usage
                    Console.WriteLine ("Enter RGB values in the format:");
                    Console.WriteLine ("ColourConversion.exe 255 255 255");
                    return;
                } else {
                    r = clip(int.Parse (args[0]));
                    g = clip(int.Parse (args[1]));
                    b = clip(int.Parse (args[2]));
                }
            }else{
                r = clip(red);
                g = clip(green);
                b = clip(blue);
            }


            //write table header
            Console.Write("Y".PadLeft(10));
            Console.Write("U".PadLeft(10));
            Console.Write("V".PadLeft(10));
            Console.Write("R".PadLeft(10));
            Console.Write("G".PadLeft(10));
            Console.Write("B".PadLeft(10));
            Console.WriteLine("      Name");
            Console.WriteLine("===============================================================================");
            printTidy(Y,U,V,r,g,b, "Original RGB Values");




            //---------------------------------------------------------------
            //Microsoft MSDN integer maths
            //http://msdn.microsoft.com/en-us/library/ms893078
            R = r;
            G = g;
            B = b;

            Y = ((66 * R + 129 * G + 25 * B + 128) >> 8) + 16;
            U = ((-38 * R - 74 * G + 112 * B + 128) >> 8) + 128;
            V = ((112 * R - 94 * G - 18 * B + 128) >> 8) + 128;

            C = Y - 16;
            D = U - 128;
            E = V - 128;

            R = clip ((298 * C + 409 * E + 128) >> 8);
            G = clip ((298 * C - 100 * D - 208 * E + 128) >> 8);
            B = clip ((298 * C + 516 * D + 128) >> 8);

            printTidy(Y,U,V,R,G,B, "Microsoft MSDN integer maths");

            //---------------------------------------------------------------       
            //ITU-R BT.601
            //http://www.equasys.de/colorconversion.html
            R = r;
            G = g;
            B = b;

            //http://www.equasys.de/equasysRGB_YCbCrColorConversionSDTV.png
            Y = clip(16 + (0.257 * R + 0.504 * G + 0.098 * B));
            U = clip(128 + (-0.148 * R + -0.291 * G + 0.439 * B));
            V = clip(128 + (0.439 * R + -0.368 * G + -0.071 * B));

            //http://www.equasys.de/equasysYCbCr_RGBColorConversionSDTV.png
            R = clip(1.164 * (Y - 16) + 0.0 * (U - 128) + 1.596 * (V - 128));
            G = clip(1.164 * (Y - 16) + -0.392 * (U - 128) + -0.813 * (V - 128));
            B = clip(1.164 * (Y - 16) + 2.017 * (U - 128) + 0.0 * (V - 128));

            printTidy(Y,U,V,R,G,B, "ITU-R BT.601");


            //---------------------------------------------------------------
            //HTDV ITU-R BT.709
            //http://www.equasys.de/colorconversion.html
            R = r;
            G = g;
            B = b;

            //http://www.equasys.de/equasysRGB_YCbCrColorConversionHDTV.png
            Y = clip(16 + ((0.183 * R) + (0.614 * G) + (0.062 * B)));
            U = clip(128 + ((-0.101 * R) +  (-0.339 * G) + (0.439 * B)));
            V = clip(128 + ((0.439 * R) + (-0.399 * G) + (-0.040 * B)));

            //http://www.equasys.de/equasysYCbCr_RGBColorConversionHDTV.png
            R = clip((1.164 * (Y-16)) + (0.0 * (U-128)) + (1.793 * (V-128)));
            G = clip((1.164 * (Y-16)) + (-0.213 * (U-128)) + (-0.533 * (V-128)));
            B = clip((1.164 * (Y-16)) + (2.112 * (U-128)) + (0.0 * (V-128)));

            printTidy(Y,U,V,R,G,B, "HDTV ITU-R BT.709");


            //---------------------------------------------------------------
            //RGB to full-range YCbCr
            //http://www.equasys.de/colorconversion.html
            R = r;
            G = g;
            B = b;

            //http://www.equasys.de/equasysRGB_FullRangeYCbCrColorConversion.png
            Y = clip(0.0 + ((0.299 * R) + (0.587 * G) + (0.114 * B)));
            U = clip(128.0 + ((-0.169 * R) + (-0.331 * G) + (0.500 * B)));
            V = clip(128.0 + ((0.500 * R) + (0.419 * G) + (-0.081 * R)));

            //http://www.equasys.de/equasysFullRangeYCbCr_RGBColorConversion.png
            R = clip((1.0 * Y) + (0.0 * (U - 128)) + (1.4 * (V - 128)));
            G = clip((1.0 * Y) + (-0.343 * (U - 128)) + (-0.711 * (V - 128)));
            B = clip((1.0 * Y) + (1.765 * (U - 128)) + (0.0 * (V - 128)));

            printTidy(Y,U,V,R,G,B, "RGB to full-range YCbCr");


            //---------------------------------------------------------------
            //Book 'Video Demystified' ISBN 1-878707-09-4
            //http://www.fourcc.org/fccyvrgb.php
            R = r;
            G = g;
            B = b;

            Y = clip((0.257 * R) + (0.504 * G) + (0.098 * B) + 16);
            V = clip((0.439 * R) - (0.368 * G) - (0.071 * B) + 128);
            U = clip(-(0.148 * R) - (0.291 * G) + (0.439 * B) + 128);

            B = clip(1.164*(Y - 16) + 2.018*(U - 128));
            G = clip(1.164*(Y - 16) - 0.813*(V - 128) - 0.391*(U - 128));
            R = clip(1.164*(Y - 16) + 1.596*(V - 128));

            printTidy(Y,U,V,R,G,B, "Book 'Video Demystified'");

        }

        //Print output in a nice form
        public static void printTidy(int Y,int U,int V,int R,int G,int B, string methodName)
        {
            Console.Write(Y.ToString().PadLeft(10));
            Console.Write(U.ToString().PadLeft(10));
            Console.Write(V.ToString().PadLeft(10));
            Console.Write(R.ToString().PadLeft(10));
            Console.Write(G.ToString().PadLeft(10));
            Console.Write(B.ToString().PadLeft(10));
            Console.WriteLine("      " + alphabet[testCount++] + ") " + methodName);
            return;
        }

        //overload for clip() - converts double to int
        public static int clip (double d)
        {
            return clip((int)d);
        }

        //clips int to between 0 and 255
        public static int clip (int i)
        {
            if (i < 0)
                return 0;
            if (i > 255)
                return 255;

            return i;
        }
    }
}
+1  A: 

None are 'officially correct' for example, BT.601 applies to .DV video, while other's apply to other standards...

What is the source of the YUV/YCbCr colors? That will tell you how to convert it.

Dave
The source I'm hoping to use is a PNG image which is 24 bit colour 8 bits per pixel. I have to convert it to YUV in order to run quality comparison tests such as PSNR and SSIM etc. Ideally I suppose I would like to use the same conversion as ffmpeg...
ross
You would need to look up the standard used for conversion to/from png then. Finding a standards document for the filetype will be a good starting point.
Dave