diff options
Diffstat (limited to 'leptonica/prog/yuvtest.c')
-rw-r--r-- | leptonica/prog/yuvtest.c | 221 |
1 files changed, 221 insertions, 0 deletions
diff --git a/leptonica/prog/yuvtest.c b/leptonica/prog/yuvtest.c new file mode 100644 index 00000000..da6ecaa1 --- /dev/null +++ b/leptonica/prog/yuvtest.c @@ -0,0 +1,221 @@ +/*====================================================================* + - Copyright (C) 2001 Leptonica. All rights reserved. + - + - Redistribution and use in source and binary forms, with or without + - modification, are permitted provided that the following conditions + - are met: + - 1. Redistributions of source code must retain the above copyright + - notice, this list of conditions and the following disclaimer. + - 2. Redistributions in binary form must reproduce the above + - copyright notice, this list of conditions and the following + - disclaimer in the documentation and/or other materials + - provided with the distribution. + - + - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + - ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + - LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + - A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ANY + - CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + - OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *====================================================================*/ + +/* + * yuvtest.c + * + * Test the yuv to rgb conversion. + * + * Note that the yuv gamut is greater than rgb, so although any + * rgb image can be converted to yuv (and back), any possible + * yuv value does not necessarily represent a valid rgb value. + */ + +#ifdef HAVE_CONFIG_H +#include <config_auto.h> +#endif /* HAVE_CONFIG_H */ + +#include "allheaders.h" + +void AddTransformsRGB(PIXA *pixa, L_BMF *bmf, l_int32 gval); +void AddTransformsYUV(PIXA *pixa, L_BMF *bmf, l_int32 yval); + + +l_int32 main(int argc, + char **argv) +{ +l_int32 i, rval, gval, bval, yval, uval, vval; +l_float32 *a[3], b[3]; +L_BMF *bmf; +PIX *pixd; +PIXA *pixa; + + setLeptDebugOK(1); + lept_mkdir("lept/yuv"); + + /* Explore the range of rgb --> yuv transforms. All rgb + * values transform to a valid value of yuv, so when transforming + * back we get the same rgb values that we started with. */ + pixa = pixaCreate(0); + bmf = bmfCreate("fonts", 6); + for (gval = 0; gval <= 255; gval += 20) + AddTransformsRGB(pixa, bmf, gval); + + pixd = pixaDisplayTiledAndScaled(pixa, 32, 755, 1, 0, 20, 2); + pixDisplay(pixd, 100, 0); + pixWrite("/tmp/lept/yuv/yuv1.png", pixd, IFF_PNG); + pixDestroy(&pixd); + pixaDestroy(&pixa); + + /* Now start with all "valid" yuv values, not all of which are + * related to a valid rgb value. Our yuv --> rgb transform + * clips the rgb components to [0 ... 255], so when transforming + * back we get different values whenever the initial yuv + * value is out of the rgb gamut. */ + pixa = pixaCreate(0); + for (yval = 16; yval <= 235; yval += 16) + AddTransformsYUV(pixa, bmf, yval); + + pixd = pixaDisplayTiledAndScaled(pixa, 32, 755, 1, 0, 20, 2); + pixDisplay(pixd, 600, 0); + pixWrite("/tmp/lept/yuv/yuv2.png", pixd, IFF_PNG); + pixDestroy(&pixd); + pixaDestroy(&pixa); + bmfDestroy(&bmf); + + + /* --------- Try out a special case by hand, and show that --------- * + * ------- the transform matrices we are using are inverses ---------*/ + + /* First, use our functions for the transform */ + lept_stderr("Start with: yval = 143, uval = 79, vval = 103\n"); + convertYUVToRGB(143, 79, 103, &rval, &gval, &bval); + lept_stderr(" ==> rval = %d, gval = %d, bval = %d\n", rval, gval, bval); + convertRGBToYUV(rval, gval, bval, &yval, &uval, &vval); + lept_stderr(" ==> yval = %d, uval = %d, vval = %d\n", yval, uval, vval); + + /* Next, convert yuv --> rbg by solving for rgb --> yuv transform. + * [ a00 a01 a02 ] r = b0 (y - 16) + * [ a10 a11 a12 ] * g = b1 (u - 128) + * [ a20 a21 a22 ] b = b2 (v - 128) + */ + b[0] = 143.0 - 16.0; /* y - 16 */ + b[1] = 79.0 - 128.0; /* u - 128 */ + b[2] = 103.0 - 128.0; /* v - 128 */ + for (i = 0; i < 3; i++) + a[i] = (l_float32 *)lept_calloc(3, sizeof(l_float32)); + a[0][0] = 65.738 / 256.0; + a[0][1] = 129.057 / 256.0; + a[0][2] = 25.064 / 256.0; + a[1][0] = -37.945 / 256.0; + a[1][1] = -74.494 / 256.0; + a[1][2] = 112.439 / 256.0; + a[2][0] = 112.439 / 256.0; + a[2][1] = -94.154 / 256.0; + a[2][2] = -18.285 / 256.0; + lept_stderr("Here's the original matrix: yuv --> rgb:\n"); + for (i = 0; i < 3; i++) + lept_stderr(" %7.3f %7.3f %7.3f\n", 256.0 * a[i][0], + 256.0 * a[i][1], 256.0 * a[i][2]); + gaussjordan(a, b, 3); + lept_stderr("\nInput (yuv) = (143,79,103); solve for rgb:\n" + "rval = %7.3f, gval = %7.3f, bval = %7.3f\n", b[0], b[1], b[2]); + lept_stderr("Here's the inverse matrix: rgb --> yuv:\n"); + for (i = 0; i < 3; i++) + lept_stderr(" %7.3f %7.3f %7.3f\n", 256.0 * a[i][0], + 256.0 * a[i][1], 256.0 * a[i][2]); + + /* Now, convert back: rgb --> yuv; + * Do this by solving for yuv --> rgb transform. + * Use the b[] found previously (the rgb values), and + * the a[][] which now holds the rgb --> yuv transform. */ + gaussjordan(a, b, 3); + lept_stderr("\nInput rgb; solve for yuv:\n" + "yval = %7.3f, uval = %7.3f, vval = %7.3f\n", + b[0] + 16.0, b[1] + 128.0, b[2] + 128.0); + lept_stderr("Inverting the matrix again: yuv --> rgb:\n"); + for (i = 0; i < 3; i++) + lept_stderr(" %7.3f %7.3f %7.3f\n", 256.0 * a[i][0], + 256.0 * a[i][1], 256.0 * a[i][2]); + + for (i = 0; i < 3; i++) lept_free(a[i]); + return 0; +} + + +void +AddTransformsRGB(PIXA *pixa, + L_BMF *bmf, + l_int32 gval) +{ +char textbuf[256]; +l_int32 i, j, wpls; +l_uint32 *datas, *lines; +PIX *pixs, *pixt1, *pixt2, *pixt3, *pixt4; +PIXA *pixat; + + pixs = pixCreate(255, 255, 32); + wpls = pixGetWpl(pixs); + datas = pixGetData(pixs); + for (i = 0; i < 255; i++) { /* r */ + lines = datas + i * wpls; + for (j = 0; j < 255; j++) /* b */ + composeRGBPixel(i, gval, j, lines + j); + } + + pixat = pixaCreate(3); + pixaAddPix(pixat, pixs, L_INSERT); + pixt1 = pixConvertRGBToYUV(NULL, pixs); + pixaAddPix(pixat, pixt1, L_INSERT); + pixt2 = pixConvertYUVToRGB(NULL, pixt1); + pixaAddPix(pixat, pixt2, L_INSERT); + pixt3 = pixaDisplayTiledAndScaled(pixat, 32, 255, 3, 0, 20, 2); + snprintf(textbuf, sizeof(textbuf), "gval = %d", gval); + pixt4 = pixAddSingleTextblock(pixt3, bmf, textbuf, 0xff000000, + L_ADD_BELOW, NULL); + pixaAddPix(pixa, pixt4, L_INSERT); + pixDestroy(&pixt3); + pixaDestroy(&pixat); + return; +} + + +void +AddTransformsYUV(PIXA *pixa, + L_BMF *bmf, + l_int32 yval) +{ +char textbuf[256]; +l_int32 i, j, wpls; +l_uint32 *datas, *lines; +PIX *pixs, *pixt1, *pixt2, *pixt3, *pixt4; +PIXA *pixat; + + pixs = pixCreate(225, 225, 32); + wpls = pixGetWpl(pixs); + datas = pixGetData(pixs); + for (i = 0; i < 225; i++) { /* v */ + lines = datas + i * wpls; + for (j = 0; j < 225; j++) /* u */ + composeRGBPixel(yval + 16, j + 16, i + 16, lines + j); + } + + pixat = pixaCreate(3); + pixaAddPix(pixat, pixs, L_INSERT); + pixt1 = pixConvertYUVToRGB(NULL, pixs); + pixaAddPix(pixat, pixt1, L_INSERT); + pixt2 = pixConvertRGBToYUV(NULL, pixt1); + pixaAddPix(pixat, pixt2, L_INSERT); + pixt3 = pixaDisplayTiledAndScaled(pixat, 32, 225, 3, 0, 20, 2); + snprintf(textbuf, sizeof(textbuf), "yval = %d", yval); + pixt4 = pixAddSingleTextblock(pixt3, bmf, textbuf, 0xff000000, + L_ADD_BELOW, NULL); + pixaAddPix(pixa, pixt4, L_INSERT); + pixDestroy(&pixt3); + pixaDestroy(&pixat); + return; +} + |