Home | History | Annotate | Download | only in vl
      1 /**************************************************************************
      2  *
      3  * Copyright 2009 Younes Manton.
      4  * All Rights Reserved.
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a
      7  * copy of this software and associated documentation files (the
      8  * "Software"), to deal in the Software without restriction, including
      9  * without limitation the rights to use, copy, modify, merge, publish,
     10  * distribute, sub license, and/or sell copies of the Software, and to
     11  * permit persons to whom the Software is furnished to do so, subject to
     12  * the following conditions:
     13  *
     14  * The above copyright notice and this permission notice (including the
     15  * next paragraph) shall be included in all copies or substantial portions
     16  * of the Software.
     17  *
     18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     19  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
     21  * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
     22  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
     23  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
     24  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     25  *
     26  **************************************************************************/
     27 
     28 #include "util/u_math.h"
     29 #include "util/u_debug.h"
     30 
     31 #include "vl_csc.h"
     32 
     33 /*
     34  * Color space conversion formulas
     35  *
     36  * To convert YCbCr to RGB,
     37  *    vec4  ycbcr, rgb
     38  *    mat44 csc
     39  *    rgb = csc * ycbcr
     40  *
     41  * To calculate the color space conversion matrix csc with ProcAmp adjustments,
     42  *    mat44 csc, cstd, procamp, bias
     43  *    csc = cstd * (procamp * bias)
     44  *
     45  * Where cstd is a matrix corresponding to one of the color standards (BT.601, BT.709, etc)
     46  * adjusted for the kind of YCbCr -> RGB mapping wanted (1:1, full),
     47  * bias is a matrix corresponding to the kind of YCbCr -> RGB mapping wanted (1:1, full)
     48  *
     49  * To calculate procamp,
     50  *    mat44 procamp, hue, saturation, brightness, contrast
     51  *    procamp = brightness * (saturation * (contrast * hue))
     52  * Alternatively,
     53  *    procamp = saturation * (brightness * (contrast * hue))
     54  *
     55  * contrast
     56  * [ c, 0, 0, 0]
     57  * [ 0, c, 0, 0]
     58  * [ 0, 0, c, 0]
     59  * [ 0, 0, 0, 1]
     60  *
     61  * brightness
     62  * [ 1, 0, 0, b/c]
     63  * [ 0, 1, 0,   0]
     64  * [ 0, 0, 1,   0]
     65  * [ 0, 0, 0,   1]
     66  *
     67  * saturation
     68  * [ 1, 0, 0, 0]
     69  * [ 0, s, 0, 0]
     70  * [ 0, 0, s, 0]
     71  * [ 0, 0, 0, 1]
     72  *
     73  * hue
     74  * [ 1,       0,      0, 0]
     75  * [ 0,  cos(h), sin(h), 0]
     76  * [ 0, -sin(h), cos(h), 0]
     77  * [ 0,       0,      0, 1]
     78  *
     79  * procamp
     80  * [ c,           0,          0, b]
     81  * [ 0,  c*s*cos(h), c*s*sin(h), 0]
     82  * [ 0, -c*s*sin(h), c*s*cos(h), 0]
     83  * [ 0,           0,          0, 1]
     84  *
     85  * bias
     86  * [ 1, 0, 0,  ybias]
     87  * [ 0, 1, 0, cbbias]
     88  * [ 0, 0, 1, crbias]
     89  * [ 0, 0, 0,      1]
     90  *
     91  * csc
     92  * [ c*cstd[ 0], c*cstd[ 1]*s*cos(h) - c*cstd[ 2]*s*sin(h), c*cstd[ 2]*s*cos(h) + c*cstd[ 1]*s*sin(h), cstd[ 3] + cstd[ 0]*(b + c*ybias) + cstd[ 1]*(c*cbbias*s*cos(h) + c*crbias*s*sin(h)) + cstd[ 2]*(c*crbias*s*cos(h) - c*cbbias*s*sin(h))]
     93  * [ c*cstd[ 4], c*cstd[ 5]*s*cos(h) - c*cstd[ 6]*s*sin(h), c*cstd[ 6]*s*cos(h) + c*cstd[ 5]*s*sin(h), cstd[ 7] + cstd[ 4]*(b + c*ybias) + cstd[ 5]*(c*cbbias*s*cos(h) + c*crbias*s*sin(h)) + cstd[ 6]*(c*crbias*s*cos(h) - c*cbbias*s*sin(h))]
     94  * [ c*cstd[ 8], c*cstd[ 9]*s*cos(h) - c*cstd[10]*s*sin(h), c*cstd[10]*s*cos(h) + c*cstd[ 9]*s*sin(h), cstd[11] + cstd[ 8]*(b + c*ybias) + cstd[ 9]*(c*cbbias*s*cos(h) + c*crbias*s*sin(h)) + cstd[10]*(c*crbias*s*cos(h) - c*cbbias*s*sin(h))]
     95  * [ c*cstd[12], c*cstd[13]*s*cos(h) - c*cstd[14]*s*sin(h), c*cstd[14]*s*cos(h) + c*cstd[13]*s*sin(h), cstd[15] + cstd[12]*(b + c*ybias) + cstd[13]*(c*cbbias*s*cos(h) + c*crbias*s*sin(h)) + cstd[14]*(c*crbias*s*cos(h) - c*cbbias*s*sin(h))]
     96  */
     97 
     98 /*
     99  * Converts ITU-R BT.601 YCbCr pixels to RGB pixels where:
    100  * Y is in [16,235], Cb and Cr are in [16,240]
    101  * R, G, and B are in [16,235]
    102  */
    103 static const vl_csc_matrix bt_601 =
    104 {
    105    { 1.0f,  0.0f,    1.371f, 0.0f, },
    106    { 1.0f, -0.336f, -0.698f, 0.0f, },
    107    { 1.0f,  1.732f,  0.0f,   0.0f, }
    108 };
    109 
    110 /*
    111  * Converts ITU-R BT.709 YCbCr pixels to RGB pixels where:
    112  * Y is in [16,235], Cb and Cr are in [16,240]
    113  * R, G, and B are in [16,235]
    114  */
    115 static const vl_csc_matrix bt_709 =
    116 {
    117    { 1.0f,  0.0f,    1.540f, 0.0f, },
    118    { 1.0f, -0.183f, -0.459f, 0.0f, },
    119    { 1.0f,  1.816f,  0.0f,   0.0f, }
    120 };
    121 
    122 /*
    123  * Converts SMPTE 240M YCbCr pixels to RGB pixels where:
    124  * Y is in [16,235], Cb and Cr are in [16,240]
    125  * R, G, and B are in [16,235]
    126  */
    127 static const vl_csc_matrix smpte240m =
    128 {
    129    { 1.0f,  0.0f,    1.541f, 0.0f, },
    130    { 1.0f, -0.221f, -0.466f, 0.0f, },
    131    { 1.0f,  1.785f,  0.0f,   0.0f, }
    132 };
    133 
    134 static const vl_csc_matrix bt_709_rev  = {
    135    { 0.183f,  0.614f,  0.062f, 0.0625f},
    136    {-0.101f, -0.338f,  0.439f, 0.5f   },
    137    { 0.439f, -0.399f, -0.040f, 0.5f   }
    138 };
    139 
    140 static const vl_csc_matrix identity =
    141 {
    142    { 1.0f, 0.0f, 0.0f, 0.0f, },
    143    { 0.0f, 1.0f, 0.0f, 0.0f, },
    144    { 0.0f, 0.0f, 1.0f, 0.0f, }
    145 };
    146 
    147 const struct vl_procamp vl_default_procamp = {
    148    0.0f,  /* brightness */
    149    1.0f,  /* contrast   */
    150    1.0f,  /* saturation */
    151    0.0f   /* hue        */
    152 };
    153 
    154 void vl_csc_get_matrix(enum VL_CSC_COLOR_STANDARD cs,
    155                        struct vl_procamp *procamp,
    156                        bool full_range,
    157                        vl_csc_matrix *matrix)
    158 {
    159    float cbbias = -128.0f/255.0f;
    160    float crbias = -128.0f/255.0f;
    161 
    162    const struct vl_procamp *p = procamp ? procamp : &vl_default_procamp;
    163    float c = p->contrast;
    164    float s = p->saturation;
    165    float b = p->brightness;
    166    float h = p->hue;
    167    float x, y;
    168 
    169    const vl_csc_matrix *cstd;
    170 
    171    if (full_range) {
    172       c *= 1.164f;              /* Adjust for the y range */
    173       b *= 1.164f;              /* Adjust for the y range */
    174       b -= c * 16.0f  / 255.0f; /* Adjust for the y bias */
    175    }
    176 
    177    /* Parameter substitutions */
    178    x = c * s * cosf(h);
    179    y = c * s * sinf(h);
    180 
    181    assert(matrix);
    182 
    183    switch (cs) {
    184       case VL_CSC_COLOR_STANDARD_BT_601:
    185          cstd = &bt_601;
    186          break;
    187       case VL_CSC_COLOR_STANDARD_BT_709:
    188          cstd = &bt_709;
    189          break;
    190       case VL_CSC_COLOR_STANDARD_SMPTE_240M:
    191          cstd = &smpte240m;
    192          break;
    193       case VL_CSC_COLOR_STANDARD_BT_709_REV:
    194          memcpy(matrix, bt_709_rev, sizeof(vl_csc_matrix));
    195          return;
    196       case VL_CSC_COLOR_STANDARD_IDENTITY:
    197       default:
    198          assert(cs == VL_CSC_COLOR_STANDARD_IDENTITY);
    199          memcpy(matrix, identity, sizeof(vl_csc_matrix));
    200          return;
    201    }
    202 
    203    (*matrix)[0][0] = c * (*cstd)[0][0];
    204    (*matrix)[0][1] = (*cstd)[0][1] * x - (*cstd)[0][2] * y;
    205    (*matrix)[0][2] = (*cstd)[0][2] * x + (*cstd)[0][1] * y;
    206    (*matrix)[0][3] = (*cstd)[0][3] + (*cstd)[0][0] * b +
    207                      (*cstd)[0][1] * (x * cbbias + y * crbias) +
    208                      (*cstd)[0][2] * (x * crbias - y * cbbias);
    209 
    210    (*matrix)[1][0] = c * (*cstd)[1][0];
    211    (*matrix)[1][1] = (*cstd)[1][1] * x - (*cstd)[1][2] * y;
    212    (*matrix)[1][2] = (*cstd)[1][2] * x + (*cstd)[1][1] * y;
    213    (*matrix)[1][3] = (*cstd)[1][3] + (*cstd)[1][0] * b +
    214                      (*cstd)[1][1] * (x * cbbias + y * crbias) +
    215                      (*cstd)[1][2] * (x * crbias - y * cbbias);
    216 
    217    (*matrix)[2][0] = c * (*cstd)[2][0];
    218    (*matrix)[2][1] = (*cstd)[2][1] * x - (*cstd)[2][2] * y;
    219    (*matrix)[2][2] = (*cstd)[2][2] * x + (*cstd)[2][1] * y;
    220    (*matrix)[2][3] = (*cstd)[2][3] + (*cstd)[2][0] * b +
    221                      (*cstd)[2][1] * (x * cbbias + y * crbias) +
    222                      (*cstd)[2][2] * (x * crbias - y * cbbias);
    223 }
    224