Home | History | Annotate | Download | only in IlmImf
      1 //////////////////////////////////////////////////////////////////////////////
      2 //
      3 // Copyright (c) 2004, Industrial Light & Magic, a division of Lucasfilm
      4 // Entertainment Company Ltd.  Portions contributed and copyright held by
      5 // others as indicated.  All rights reserved.
      6 //
      7 // Redistribution and use in source and binary forms, with or without
      8 // modification, are permitted provided that the following conditions are
      9 // met:
     10 //
     11 //     * Redistributions of source code must retain the above
     12 //       copyright notice, this list of conditions and the following
     13 //       disclaimer.
     14 //
     15 //     * Redistributions in binary form must reproduce the above
     16 //       copyright notice, this list of conditions and the following
     17 //       disclaimer in the documentation and/or other materials provided with
     18 //       the distribution.
     19 //
     20 //     * Neither the name of Industrial Light & Magic nor the names of
     21 //       any other contributors to this software may be used to endorse or
     22 //       promote products derived from this software without specific prior
     23 //       written permission.
     24 //
     25 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
     26 // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
     27 // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     28 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     29 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     30 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     31 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     32 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
     33 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
     34 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     35 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     36 //
     37 //////////////////////////////////////////////////////////////////////////////
     38 
     39 //-----------------------------------------------------------------------------
     40 //
     41 //	Conversion between RGBA and YCA data.
     42 //
     43 //-----------------------------------------------------------------------------
     44 
     45 #include <ImfRgbaYca.h>
     46 #include <assert.h>
     47 #include <algorithm>
     48 
     49 using namespace Imath;
     50 using namespace std;
     51 
     52 namespace Imf {
     53 namespace RgbaYca {
     54 
     55 
     56 V3f
     57 computeYw (const Chromaticities &cr)
     58 {
     59     M44f m = RGBtoXYZ (cr, 1);
     60     return V3f (m[0][1], m[1][1], m[2][1]) / (m[0][1] + m[1][1] + m[2][1]);
     61 }
     62 
     63 
     64 void
     65 RGBAtoYCA (const V3f &yw,
     66        int n,
     67        bool aIsValid,
     68        const Rgba rgbaIn[/*n*/],
     69        Rgba ycaOut[/*n*/])
     70 {
     71     for (int i = 0; i < n; ++i)
     72     {
     73     Rgba in = rgbaIn[i];
     74     Rgba &out = ycaOut[i];
     75 
     76     //
     77     // Conversion to YCA and subsequent chroma subsampling
     78     // work only if R, G and B are finite and non-negative.
     79     //
     80 
     81     if (!in.r.isFinite() || in.r < 0)
     82         in.r = 0;
     83 
     84     if (!in.g.isFinite() || in.g < 0)
     85         in.g = 0;
     86 
     87     if (!in.b.isFinite() || in.b < 0)
     88         in.b = 0;
     89 
     90     if (in.r == in.g && in.g == in.b)
     91     {
     92         //
     93         // Special case -- R, G and B are equal. To avoid rounding
     94         // errors, we explicitly set the output luminance channel
     95         // to G, and the chroma channels to 0.
     96         //
     97         // The special cases here and in YCAtoRGBA() ensure that
     98         // converting black-and white images from RGBA to YCA and
     99         // back is lossless.
    100         //
    101 
    102         out.r = 0;
    103         out.g = in.g;
    104         out.b = 0;
    105     }
    106     else
    107     {
    108         out.g = in.r * yw.x + in.g * yw.y + in.b * yw.z;
    109 
    110         float Y = out.g;
    111 
    112         if (abs (in.r - Y) < HALF_MAX * Y)
    113         out.r = (in.r - Y) / Y;
    114         else
    115         out.r = 0;
    116 
    117         if (abs (in.b - Y) < HALF_MAX * Y)
    118         out.b = (in.b - Y) / Y;
    119         else
    120         out.b = 0;
    121     }
    122 
    123     if (aIsValid)
    124         out.a = in.a;
    125     else
    126         out.a = 1;
    127     }
    128 }
    129 
    130 
    131 void
    132 decimateChromaHoriz (int n,
    133              const Rgba ycaIn[/*n+N-1*/],
    134              Rgba ycaOut[/*n*/])
    135 {
    136     #ifdef DEBUG
    137     assert (ycaIn != ycaOut);
    138     #endif
    139 
    140     int begin = N2;
    141     int end = begin + n;
    142 
    143     for (int i = begin, j = 0; i < end; ++i, ++j)
    144     {
    145     if ((j & 1) == 0)
    146     {
    147         ycaOut[j].r = ycaIn[i - 13].r *  0.001064f +
    148               ycaIn[i - 11].r * -0.003771f +
    149               ycaIn[i -  9].r *  0.009801f +
    150               ycaIn[i -  7].r * -0.021586f +
    151               ycaIn[i -  5].r *  0.043978f +
    152               ycaIn[i -  3].r * -0.093067f +
    153               ycaIn[i -  1].r *  0.313659f +
    154               ycaIn[i     ].r *  0.499846f +
    155               ycaIn[i +  1].r *  0.313659f +
    156               ycaIn[i +  3].r * -0.093067f +
    157               ycaIn[i +  5].r *  0.043978f +
    158               ycaIn[i +  7].r * -0.021586f +
    159               ycaIn[i +  9].r *  0.009801f +
    160               ycaIn[i + 11].r * -0.003771f +
    161               ycaIn[i + 13].r *  0.001064f;
    162 
    163         ycaOut[j].b = ycaIn[i - 13].b *  0.001064f +
    164               ycaIn[i - 11].b * -0.003771f +
    165               ycaIn[i -  9].b *  0.009801f +
    166               ycaIn[i -  7].b * -0.021586f +
    167               ycaIn[i -  5].b *  0.043978f +
    168               ycaIn[i -  3].b * -0.093067f +
    169               ycaIn[i -  1].b *  0.313659f +
    170               ycaIn[i     ].b *  0.499846f +
    171               ycaIn[i +  1].b *  0.313659f +
    172               ycaIn[i +  3].b * -0.093067f +
    173               ycaIn[i +  5].b *  0.043978f +
    174               ycaIn[i +  7].b * -0.021586f +
    175               ycaIn[i +  9].b *  0.009801f +
    176               ycaIn[i + 11].b * -0.003771f +
    177               ycaIn[i + 13].b *  0.001064f;
    178     }
    179 
    180     ycaOut[j].g = ycaIn[i].g;
    181     ycaOut[j].a = ycaIn[i].a;
    182     }
    183 }
    184 
    185 
    186 void
    187 decimateChromaVert (int n,
    188             const Rgba * const ycaIn[N],
    189             Rgba ycaOut[/*n*/])
    190 {
    191     for (int i = 0; i < n; ++i)
    192     {
    193     if ((i & 1) == 0)
    194     {
    195         ycaOut[i].r = ycaIn[ 0][i].r *  0.001064f +
    196               ycaIn[ 2][i].r * -0.003771f +
    197               ycaIn[ 4][i].r *  0.009801f +
    198               ycaIn[ 6][i].r * -0.021586f +
    199               ycaIn[ 8][i].r *  0.043978f +
    200               ycaIn[10][i].r * -0.093067f +
    201               ycaIn[12][i].r *  0.313659f +
    202               ycaIn[13][i].r *  0.499846f +
    203               ycaIn[14][i].r *  0.313659f +
    204               ycaIn[16][i].r * -0.093067f +
    205               ycaIn[18][i].r *  0.043978f +
    206               ycaIn[20][i].r * -0.021586f +
    207               ycaIn[22][i].r *  0.009801f +
    208               ycaIn[24][i].r * -0.003771f +
    209               ycaIn[26][i].r *  0.001064f;
    210 
    211         ycaOut[i].b = ycaIn[ 0][i].b *  0.001064f +
    212               ycaIn[ 2][i].b * -0.003771f +
    213               ycaIn[ 4][i].b *  0.009801f +
    214               ycaIn[ 6][i].b * -0.021586f +
    215               ycaIn[ 8][i].b *  0.043978f +
    216               ycaIn[10][i].b * -0.093067f +
    217               ycaIn[12][i].b *  0.313659f +
    218               ycaIn[13][i].b *  0.499846f +
    219               ycaIn[14][i].b *  0.313659f +
    220               ycaIn[16][i].b * -0.093067f +
    221               ycaIn[18][i].b *  0.043978f +
    222               ycaIn[20][i].b * -0.021586f +
    223               ycaIn[22][i].b *  0.009801f +
    224               ycaIn[24][i].b * -0.003771f +
    225               ycaIn[26][i].b *  0.001064f;
    226     }
    227 
    228     ycaOut[i].g = ycaIn[13][i].g;
    229     ycaOut[i].a = ycaIn[13][i].a;
    230     }
    231 }
    232 
    233 
    234 void
    235 roundYCA (int n,
    236       unsigned int roundY,
    237       unsigned int roundC,
    238       const Rgba ycaIn[/*n*/],
    239       Rgba ycaOut[/*n*/])
    240 {
    241     for (int i = 0; i < n; ++i)
    242     {
    243     ycaOut[i].g = ycaIn[i].g.round (roundY);
    244     ycaOut[i].a = ycaIn[i].a;
    245 
    246     if ((i & 1) == 0)
    247     {
    248         ycaOut[i].r = ycaIn[i].r.round (roundC);
    249         ycaOut[i].b = ycaIn[i].b.round (roundC);
    250     }
    251     }
    252 }
    253 
    254 
    255 void
    256 reconstructChromaHoriz (int n,
    257             const Rgba ycaIn[/*n+N-1*/],
    258             Rgba ycaOut[/*n*/])
    259 {
    260     #ifdef DEBUG
    261     assert (ycaIn != ycaOut);
    262     #endif
    263 
    264     int begin = N2;
    265     int end = begin + n;
    266 
    267     for (int i = begin, j = 0; i < end; ++i, ++j)
    268     {
    269     if (j & 1)
    270     {
    271         ycaOut[j].r = ycaIn[i - 13].r *  0.002128f +
    272               ycaIn[i - 11].r * -0.007540f +
    273               ycaIn[i -  9].r *  0.019597f +
    274               ycaIn[i -  7].r * -0.043159f +
    275               ycaIn[i -  5].r *  0.087929f +
    276               ycaIn[i -  3].r * -0.186077f +
    277               ycaIn[i -  1].r *  0.627123f +
    278               ycaIn[i +  1].r *  0.627123f +
    279               ycaIn[i +  3].r * -0.186077f +
    280               ycaIn[i +  5].r *  0.087929f +
    281               ycaIn[i +  7].r * -0.043159f +
    282               ycaIn[i +  9].r *  0.019597f +
    283               ycaIn[i + 11].r * -0.007540f +
    284               ycaIn[i + 13].r *  0.002128f;
    285 
    286         ycaOut[j].b = ycaIn[i - 13].b *  0.002128f +
    287               ycaIn[i - 11].b * -0.007540f +
    288               ycaIn[i -  9].b *  0.019597f +
    289               ycaIn[i -  7].b * -0.043159f +
    290               ycaIn[i -  5].b *  0.087929f +
    291               ycaIn[i -  3].b * -0.186077f +
    292               ycaIn[i -  1].b *  0.627123f +
    293               ycaIn[i +  1].b *  0.627123f +
    294               ycaIn[i +  3].b * -0.186077f +
    295               ycaIn[i +  5].b *  0.087929f +
    296               ycaIn[i +  7].b * -0.043159f +
    297               ycaIn[i +  9].b *  0.019597f +
    298               ycaIn[i + 11].b * -0.007540f +
    299               ycaIn[i + 13].b *  0.002128f;
    300     }
    301     else
    302     {
    303         ycaOut[j].r = ycaIn[i].r;
    304         ycaOut[j].b = ycaIn[i].b;
    305     }
    306 
    307     ycaOut[j].g = ycaIn[i].g;
    308     ycaOut[j].a = ycaIn[i].a;
    309     }
    310 }
    311 
    312 
    313 void
    314 reconstructChromaVert (int n,
    315                const Rgba * const ycaIn[N],
    316                Rgba ycaOut[/*n*/])
    317 {
    318     for (int i = 0; i < n; ++i)
    319     {
    320     ycaOut[i].r = ycaIn[ 0][i].r *  0.002128f +
    321               ycaIn[ 2][i].r * -0.007540f +
    322               ycaIn[ 4][i].r *  0.019597f +
    323               ycaIn[ 6][i].r * -0.043159f +
    324               ycaIn[ 8][i].r *  0.087929f +
    325               ycaIn[10][i].r * -0.186077f +
    326               ycaIn[12][i].r *  0.627123f +
    327               ycaIn[14][i].r *  0.627123f +
    328               ycaIn[16][i].r * -0.186077f +
    329               ycaIn[18][i].r *  0.087929f +
    330               ycaIn[20][i].r * -0.043159f +
    331               ycaIn[22][i].r *  0.019597f +
    332               ycaIn[24][i].r * -0.007540f +
    333               ycaIn[26][i].r *  0.002128f;
    334 
    335     ycaOut[i].b = ycaIn[ 0][i].b *  0.002128f +
    336               ycaIn[ 2][i].b * -0.007540f +
    337               ycaIn[ 4][i].b *  0.019597f +
    338               ycaIn[ 6][i].b * -0.043159f +
    339               ycaIn[ 8][i].b *  0.087929f +
    340               ycaIn[10][i].b * -0.186077f +
    341               ycaIn[12][i].b *  0.627123f +
    342               ycaIn[14][i].b *  0.627123f +
    343               ycaIn[16][i].b * -0.186077f +
    344               ycaIn[18][i].b *  0.087929f +
    345               ycaIn[20][i].b * -0.043159f +
    346               ycaIn[22][i].b *  0.019597f +
    347               ycaIn[24][i].b * -0.007540f +
    348               ycaIn[26][i].b *  0.002128f;
    349 
    350     ycaOut[i].g = ycaIn[13][i].g;
    351     ycaOut[i].a = ycaIn[13][i].a;
    352     }
    353 }
    354 
    355 
    356 void
    357 YCAtoRGBA (const Imath::V3f &yw,
    358        int n,
    359        const Rgba ycaIn[/*n*/],
    360        Rgba rgbaOut[/*n*/])
    361 {
    362     for (int i = 0; i < n; ++i)
    363     {
    364     const Rgba &in = ycaIn[i];
    365     Rgba &out = rgbaOut[i];
    366 
    367     if (in.r == 0 && in.b == 0)
    368     {
    369         //
    370         // Special case -- both chroma channels are 0.  To avoid
    371         // rounding errors, we explicitly set the output R, G and B
    372         // channels equal to the input luminance.
    373         //
    374         // The special cases here and in RGBAtoYCA() ensure that
    375         // converting black-and white images from RGBA to YCA and
    376         // back is lossless.
    377         //
    378 
    379         out.r = in.g;
    380         out.g = in.g;
    381         out.b = in.g;
    382         out.a = in.a;
    383     }
    384     else
    385     {
    386         float Y =  in.g;
    387         float r = (in.r + 1) * Y;
    388         float b = (in.b + 1) * Y;
    389         float g = (Y - r * yw.x - b * yw.z) / yw.y;
    390 
    391         out.r = r;
    392         out.g = g;
    393         out.b = b;
    394         out.a = in.a;
    395     }
    396     }
    397 }
    398 
    399 
    400 namespace {
    401 
    402 inline float
    403 saturation (const Rgba &in)
    404 {
    405     float rgbMax = max (in.r, max (in.g, in.b));
    406     float rgbMin = min (in.r, min (in.g, in.b));
    407 
    408     if (rgbMax > 0)
    409     return 1 - rgbMin / rgbMax;
    410     else
    411     return 0;
    412 }
    413 
    414 
    415 void
    416 desaturate (const Rgba &in, float f, const V3f &yw, Rgba &out)
    417 {
    418     float rgbMax = max (in.r, max (in.g, in.b));
    419 
    420     out.r = max (float (rgbMax - (rgbMax - in.r) * f), 0.0f);
    421     out.g = max (float (rgbMax - (rgbMax - in.g) * f), 0.0f);
    422     out.b = max (float (rgbMax - (rgbMax - in.b) * f), 0.0f);
    423     out.a = in.a;
    424 
    425     float Yin  = in.r  * yw.x + in.g  * yw.y + in.b  * yw.z;
    426     float Yout = out.r * yw.x + out.g * yw.y + out.b * yw.z;
    427 
    428     if (Yout > 0)
    429     {
    430     out.r *= Yin / Yout;
    431     out.g *= Yin / Yout;
    432     out.b *= Yin / Yout;
    433     }
    434 }
    435 
    436 } // namespace
    437 
    438 
    439 void
    440 fixSaturation (const Imath::V3f &yw,
    441            int n,
    442            const Rgba * const rgbaIn[3],
    443            Rgba rgbaOut[/*n*/])
    444 {
    445     float neighborA2 = saturation (rgbaIn[0][0]);
    446     float neighborA1 = neighborA2;
    447 
    448     float neighborB2 = saturation (rgbaIn[2][0]);
    449     float neighborB1 = neighborB2;
    450 
    451     for (int i = 0; i < n; ++i)
    452     {
    453     float neighborA0 = neighborA1;
    454     neighborA1 = neighborA2;
    455 
    456     float neighborB0 = neighborB1;
    457     neighborB1 = neighborB2;
    458 
    459     if (i < n - 1)
    460     {
    461         neighborA2 = saturation (rgbaIn[0][i + 1]);
    462         neighborB2 = saturation (rgbaIn[2][i + 1]);
    463     }
    464 
    465     //
    466     // A0       A1       A2
    467     //      rgbaOut[i]
    468     // B0       B1       B2
    469     //
    470 
    471     float sMean = min (1.0f, 0.25f * (neighborA0 + neighborA2 +
    472                       neighborB0 + neighborB2));
    473 
    474     const Rgba &in  = rgbaIn[1][i];
    475     Rgba &out = rgbaOut[i];
    476 
    477     float s = saturation (in);
    478 
    479     if (s > sMean)
    480     {
    481         float sMax = min (1.0f, 1 - (1 - sMean) * 0.25f);
    482 
    483         if (s > sMax)
    484         {
    485         desaturate (in, sMax / s, yw, out);
    486         continue;
    487         }
    488     }
    489 
    490     out = in;
    491     }
    492 }
    493 
    494 } // namespace RgbaYca
    495 } // namespace Imf
    496