Edit (18/01/2013)

I have edited this post on the above date. However, the only change that I have made is that I am now hosting the source code (found at the end of this post) on GitHub. This means, that if I need to make a change to the code, I do not have to edit this post again – as it will pull the latest version of it from the relevant page on GitHub whenever it is accessed by a reader.

Jargon

In case you don’t know what they mean, I’ve included the following list of jargon terms and rough descriptions of them.

RGB = Red, Green, Blue

YUV = similar to RGB, except that luma (Y) and chroma (U and V) are stored

Sources?

Most of the information for this post came from the Wikipedia article on YUV. You can visit it here: [LINK]

RGB? YUV?

Last week, a friend of mine wanted to meet in the city centre and go for a nosey around the TV stores. He’d recently bought his own place, and is decorating it and looking for a new TV.

While we were walking around “Electronics-Company-That-Isn’t-Named-After-A-Spicy-Food-At-All”, we spotted the Sony and LG LED TVs. I got to wondering whether TV transmissions are still sent in YUV, and whether those same signals were converted to RGB before being displayed on screen.

When I got home, I decided that I should look into YUV and see just how it works. I didn’t actually get around to reading about YUV until this afternoon, but when I did it made sense.

The human eye is more sensitive to changes in brightness, rather than certain colours. So, why  not send the luma (brightness) information and the chroma (colour difference) information?

Back in the days of blank and white TV, all that the TV broadcasters had to send was the luma (brightness) information. As colour TV was invented, top boffins thought that the best (read: “way that requires less bandwidth over the air”) way to send the colour information was the extend the model of just sending luma information, this time including chroma information.

The best way to understand this is to see it. Luckily, Wikipedia have an amazing example. In the following picture (click to enlarge):

  • The top image is how it is displayed on screen in any picture browser
  • The second (blank and white) image is the luma data for the image
  • The third (mostly blue and green) image is the U chroma data for the image
  • The forth (mostly yellow and orange) images is the V chroma data for the image
An image along with its Y', U, and V components.

Images via Wikipedia

They could have ditched the older system of just sending luma, and gone with a purely RGB system. However, this would have required the transmitters to send redundant, extra data over the airwaves. Plus, the older blank and white TV sets would no longer have worked. If a blank and white TV is used, then it simply ignores the UV portion of a received signal.

Also, the data being sent can be compressed before sending over the airwaves. In fact, the video portion of digital broadcasts are compressed in (almost) the same way. Because the human eye is more sensitive to changes in brightness, the chroma differences can be compressed (sampled fewer times), thus reducing the bandwidth.

Why Are You Telling Me All Of This, Jamie?

Basically, one of the ways that I can tell if I understand something that I’ve just learnt is to test myself in some way.

Ever wondered why you have exams in most of your classes?

Also, this links into my (very basic) teacher training:

  • Teach something to the student(s)
  • Get the student(s) to tell you what you’ve just taught them in their own words

Anyway, I’ve tested myself by taking what I’ve learnt about the RGB to YUV conversion and created a small C program that converts RGB to YUV.

At the minute it only converts a set of user inputted strings that represent the RGB values and returns their YUV equivalents.

My browsers built in spell check system is telling me that “inputted” isn’t a word. I’m sure that it is. In fact, a whole slew of Internet resources tells me that it is.

Anyway, onto the code. I wont write any more information about the code than this (as everything else should be included in the comments for my code, hopefully):

I compiled this on MS Windows 7 x64, with MiNGW’s gcc with the following options/command:

gcc <path to source file> -o RGB.exe -O2

/*
 * Project Name:        	RGB to Y'UV
 * Solution Name:		RGB to Y'UV
 * Original creation date:	19/11/2011
 * Edit date:			18/01/2013
 * Programmer name:		Jamie Taylor (aka "GaProgMan")
 * File name:			YUV.c
 * 
 * Purpose of the project:
 *	I was reading through a wikipedia article on
 * 	the differences between YUV and RGB and found it
 * 	very interesting.
 * 		For those who don't know, YUV is a colour
 * 	space - a way of storing colour for digital images,
 * 	film and TV. It focuses on storing Luma
 * 	(brightness - as Y') and two chrominance (colour
 * 	- as U and V) values.
 * 		Most video and still images are stored  in
 * 	this format, as it takes into account the Human
 * 	eye's ability to perceive differences in brightness
 *	at higher definition than differences in colour. This
 * 	greatly reduces the data bandwidth required to send
 * 	and receive images and film in this format.
 * 		This short program explores the mathematical
 * 	formulae used to convert colour data from the RGB
 * 	colour space to the Y'UV colour space.
 * 		For an in-depth description Y'UV, RGB and
 * 	the formulae used, please see the following
 * 	website:
 * 			http://en.wikipedia.org/wiki/YUV
 * 
 * Formulae used:
 *	To convert from RGB to Y'UV, the following
 * 	will be used:
 * 			Y' = W[r]R + W[g]G + W[b]B
 * 			U = U[max] * (B - Y') / (1 - W[b])
 * 			V = V[max] * (R - Y') / (1 - W[r])
 * 		Where:
 * 			W[r] = 0.299
 * 			W[b] = 0.114
 * 			W[g] = 1 - W[r] - W[b] = 0.587
 * 			U[max] = 0.436
 * 			V[max] = 0.615
 * 		Note:- I have placed square brackes around
 * 	the letters in the formulae that are written in
 * 	subscript. This is to make it easier for the
 * 	reader.
 *
 *	GNU Copyright information
 *	Copyright 2011 Jamie Taylor <jamie@taylorj.org.uk>
 *
 *	This program is free software; you can redistribute
 *	it and/or modify it under the terms of the GNU General
 *	Public License as published by the Free Software
 *	Foundation; either version 2 of the License, or (at
 *	your option) any later version.
 *
 *	This program is distributed in the hope that it will
 *	be useful, but WITHOUT ANY WARRANTY; without even the
 *	implied warranty of MERCHANTABILITY or FITNESS FOR A
 *	PARTICULAR PURPOSE.  See the GNU General Public
 *	License for more details.
 *
 *	You should have received a copy of the GNU General
 *	Public License along with this program; if not, write
 *	to the Free Software Foundation, Inc., 51 Franklin
 *	Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

/* included libraries */
#include <stdio.h>

/* Constants that will be used for RGB to Y'UV */
#define WEIGHTEDRED	0.299
#define WEIGHTEDGREEN	0.587
#define WEIGHTEDBLUE	0.114
#define UMAX		0.436
#define VMAX		0.615

/* function declarations */
void convertFromRGB ();

/* global variables */
float redValue;
float greenValue;
float blueValue;
float yPrime;
float uValue;
float vValue;

int main () {

  /* read values for RGB into memory */
  printf("Please input a value for RED:");
  scanf("%f", &redValue);
  printf("Please input a value for GREEN:");
  scanf("%f", &greenValue);
  printf("Please input a value for BLUE:");
  scanf("%f", &blueValue);

  /* convert RGB to Y'UV */
  convertFromRGB();

  /*display results */
  printf("\nFor the RGB input (%.2f, %.2f, %.2f),\n",
    redValue, greenValue, blueValue);
  printf("The following Y'UV is outputted (%.2f, %.2f, %.2f)",
    yPrime, uValue, vValue);
  return 0;
}

void convertFromRGB (){
  /* 
   * implement formula:
   * Y' = W[r]R + W[g]G + W[b]B
   */
  yPrime = (WEIGHTEDRED * redValue) +
    (WEIGHTEDGREEN * greenValue) +
    (WEIGHTEDBLUE * blueValue);

  /*
   * implement formula:
   * U = U[max] * (B - Y') / (1 - W[b])
   */
  uValue = UMAX * ((blueValue - yPrime)
    / (1 - WEIGHTEDBLUE));

  /*
   * implement formula:
   * V = V[max] * (R - Y') / (1 - W[r])
   */
  vValue = VMAX * ((redValue - yPrime)
    / (1 - WEIGHTEDRED));
}

One last thing: If you’re going to compile and run this yourself, remember to put a blank line at the end of the source code. It’s ANSI C, after all.

When I added my source code to this page, it had the blank line at the end. But when I previewed the page, the blank line was pruned from the code viewer provided by WordPress.  But if you click on either “View source” or “Copy to clipboard” (when hovering over the source code black), you’ll get the code with the blank line at the end.

Until next time,

J – “Soul, peace and chicken grease” (as my brother says)

Related Post

Jamie is a .NET developer specialising in ASP.NET MVC websites and services, with a background in WinForms and Games Development. When not programming using .NET, he is either learning about .NET Core (and usually building something cross platform with it), speaking Japanese to anyone who'll listen, learning about languages, writing for this blog, or writing for a blog about Retro Gaming (which he runs with his brother)