开发者

How do I create a color bar (TV test pattern)

I need to create a colorbar like THIS I use a scaled array of floats between 0 and 1.

Now I want to compute the RGB color from this float. How to do it? Want to write it in C/c++ so I think I need 2 functions.

The first function to build the colorbar with one开发者_开发技巧 parameter like STEPSIZE and the second function need the value and must just return the array index of the colorbar.

I couldn't find it on google, so please help me.


What you are referring to here is the 100% EBU Color Bars (named after the standards body, the European Broadcasting Union). This is not the same as the full SMPTE RP 219-2002 color bars, which have other features including gradients and the PLUGE (Picture Line-Up Generation Equipment), described in the Wikipedia article on Color Bars.

The EBU Color Bars consist of 8 vertical bars of equal width. They are defined in the same way for both SD and HD formats. In the RGB color space, they alternate each of the red, green and blue channels at different rates (much like counting in binary) from 0 to 100% intensity. Counting down from white, in normalised RGB form (appearing left to right):

  • 1, 1, 1: White
  • 1, 1, 0: Yellow
  • 0, 1, 1: Cyan
  • 0, 1, 0: Green
  • 1, 0, 1: Magenta
  • 1, 0, 0: Red
  • 0, 0, 1: Blue
  • 0, 0, 0: Black

So the blue channel alternates every column, the red channel after two columns, and the green after four columns. This arrangement has the useful property that the luminance (Y in YCb'Cr' colour space) results in a downward stepping plot.

To render using 8-bit RGB (most commonly found in desktop systems), simply multiply the above values by 255. The EBU bars come in 75% and 100% variants, based on the intensity of the white column. The SMPTE color bars typically use 75% levels as a reference.

Here is some simple C code to generate 100% EBU color bars and save the result as a PGM file:

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>

// PAL dimensions
static const unsigned kWidth = 720;
static const unsigned kHeight = 576;

typedef struct
{
    uint8_t     r;
    uint8_t     g;
    uint8_t     b;
} RGB;

int main(int argc, char* argv[])
{
    const RGB BAR_COLOUR[8] =
    {
        { 255, 255, 255 },  // 100% White
        { 255, 255,   0 },  // Yellow
        {   0, 255, 255 },  // Cyan
        {   0, 255,   0 },  // Green
        { 255,   0, 255 },  // Magenta
        { 255,   0,   0 },  // Red
        {   0,   0, 255 },  // Blue
        {   0,   0,   0 },  // Black
    };

    // Allocate frame buffer
    size_t      frameBytes = kWidth*kHeight*sizeof(RGB);
    RGB*        frame = malloc(frameBytes);
    unsigned    columnWidth = kWidth / 8;

    // Generate complete frame
    for (unsigned y = 0; y < kHeight; y++)
    {
        for (unsigned x = 0; x < kWidth; x++)
        {
            unsigned col_idx = x / columnWidth;
            frame[y*kWidth+x] = BAR_COLOUR[col_idx];
        }
    }

    // Save as PPM
    FILE* fout = fopen("ebu_bars.ppm", "wb");
    fprintf(fout, "P6\n%u %u\n255\n", kWidth, kHeight);
    fwrite(frame, frameBytes, 1, fout);
    fclose(fout);

    free(frame);

    return 0;
}

This should be readily adaptable to any other language. There's probably no need for using float unless you're implementing this on a GPU (in which case the algorithm would be quite different). There is much scope for optimization here; the code is written for clarity, not speed.

Note that while it is possible to generate a perfect digital representation of the color bars in a computer, this will not be safe for broadcast. The transitions between "perfect" color bars would require infinitely high bandwidth to accurately represent. So if the test image is to be transmitted via analog broadcast equipment, it must be bandwidth-limited by a low-pass filter (eg. ~4.3MHz for PAL). This is why you notice the "fuzzy" boundaries in between each column; these contain intermediate values between the pure colors.

Also note that it is not possible to accurately represent the SMPTE color bars in the RGB color space. This is because certain critical values are specified in the YCb'Cr' color space (notably in the PLUGE region) which are outside the gamut of RGB (either SD or HD). You can create something that approximates the values (eg. a very dark blue) but they are not correct. So unless you are representing the test frame in YCb'Cr', stick to EBU bars only (the upper 2/3).


RGB uses bytes, so assuming your array of floats is something like

float scaledColor[3]; // 0 = R, etc., all 0.0 < scaledColor[x] < 1.0

then you can do:

unsigned char r = (unsigned char)(255 * scaledColor[0]);
unsigned char g = (unsigned char)(255 * scaledColor[1]);
unsigned char b = (unsigned char)(255 * scaledColor[2]);

This will of course only work if the values in the floats are really in the range from 0.0 to 1.0.


The simplest solution:

const unsigned char* getColour(float x) /* 0 <= x < 1 */
{
    static const unsigned char bar[][3] = {
        {255,255,255},
        {255,255,0},
        // ... fill in all the colours ...
        {0,0,0}
    };
    return bar[(int)(x*sizeof(bar))];
}

Then you can use it to generate bars of any width.


My google-fu turned up that you want the upper third of a SMPTE color bar pattern. Wikipedia says:

In order from left to right, the colors are gray, yellow, cyan, green, magenta, red, and blue.

So the easiest way is to simply hard code the respective RGB color codes if you only need those. The article also mentions how those colors can be generated but this seems a lot more difficult and isn't really worth the effort for seven colors.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜