"Fossies" - the Fresh Open Source Software Archive

Member "rawtherapee-5.7/rtengine/imagefloat.cc" (10 Sep 2019, 17258 Bytes) of package /linux/misc/rawtherapee-5.7.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "imagefloat.cc" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 5.6_vs_5.7.

    1 /*
    2  *  This file is part of RawTherapee.
    3  *
    4  *  Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
    5  *
    6  *  RawTherapee is free software: you can redistribute it and/or modify
    7  *  it under the terms of the GNU General Public License as published by
    8  *  the Free Software Foundation, either version 3 of the License, or
    9  *  (at your option) any later version.
   10  *
   11  *  RawTherapee is distributed in the hope that it will be useful,
   12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   14  *  GNU General Public License for more details.
   15  *
   16  *  You should have received a copy of the GNU General Public License
   17  *  along with RawTherapee.  If not, see <https://www.gnu.org/licenses/>.
   18  */
   19 #include <tiffio.h>
   20 #include "imagefloat.h"
   21 #include "image16.h"
   22 #include "image8.h"
   23 #include <cstring>
   24 #include "rtengine.h"
   25 #include "mytime.h"
   26 #include "iccstore.h"
   27 #include "alignedbuffer.h"
   28 #include "rt_math.h"
   29 #include "color.h"
   30 #include "procparams.h"
   31 
   32 using namespace rtengine;
   33 
   34 Imagefloat::Imagefloat ()
   35 {
   36 }
   37 
   38 Imagefloat::Imagefloat (int w, int h)
   39 {
   40     allocate (w, h);
   41 }
   42 
   43 Imagefloat::~Imagefloat ()
   44 {
   45 }
   46 
   47 // Call this method to handle floating points input values of different size
   48 void Imagefloat::setScanline (int row, const unsigned char* buffer, int bps, unsigned int numSamples)
   49 {
   50 
   51     if (data == nullptr) {
   52         return;
   53     }
   54 
   55     // The DNG decoder convert to 32 bits float data even if the file contains 16 or 24 bits data.
   56     // DNG_HalfToFloat and DNG_FP24ToFloat from dcraw.cc can be used to manually convert
   57     // from 16 and 24 bits to 32 bits float respectively
   58     switch (sampleFormat) {
   59     case (IIOSF_FLOAT16): {
   60         int ix = 0;
   61         const uint16_t* sbuffer = (const uint16_t*) buffer;
   62 
   63         for (int i = 0; i < width; i++) {
   64             r(row, i) = 65535.f * DNG_HalfToFloat(sbuffer[ix++]);
   65             g(row, i) = 65535.f * DNG_HalfToFloat(sbuffer[ix++]);
   66             b(row, i) = 65535.f * DNG_HalfToFloat(sbuffer[ix++]);
   67         }
   68 
   69         break;
   70     }
   71     //case (IIOSF_FLOAT24):
   72     case (IIOSF_FLOAT32): {
   73         int ix = 0;
   74         const float* sbuffer = (const float*) buffer;
   75 
   76         for (int i = 0; i < width; i++) {
   77             r(row, i) = 65535.f * sbuffer[ix++];
   78             g(row, i) = 65535.f * sbuffer[ix++];
   79             b(row, i) = 65535.f * sbuffer[ix++];
   80         }
   81 
   82         break;
   83     }
   84 
   85     case (IIOSF_LOGLUV24):
   86     case (IIOSF_LOGLUV32): {
   87         int ix = 0;
   88         const float* sbuffer = (const float*) buffer;
   89         float xyzvalues[3], rgbvalues[3];
   90 
   91         for (int i = 0; i < width; i++) {
   92             xyzvalues[0] = sbuffer[ix++];
   93             xyzvalues[1] = sbuffer[ix++];
   94             xyzvalues[2] = sbuffer[ix++];
   95             // TODO: we may have to handle other color space than sRGB!
   96             Color::xyz2srgb(xyzvalues[0], xyzvalues[1], xyzvalues[2], rgbvalues[0], rgbvalues[1], rgbvalues[2]);
   97             r(row, i) = rgbvalues[0];
   98             g(row, i) = rgbvalues[1];
   99             b(row, i) = rgbvalues[2];
  100         }
  101 
  102         break;
  103     }
  104 
  105     default:
  106         // Other type are ignored, but could be implemented if necessary
  107         break;
  108     }
  109 }
  110 
  111 
  112 void Imagefloat::getScanline (int row, unsigned char* buffer, int bps, bool isFloat) const
  113 {
  114 
  115     if (data == nullptr) {
  116         return;
  117     }
  118 
  119     if (isFloat) {
  120         if (bps == 32) {
  121             int ix = 0;
  122             float* sbuffer = (float*) buffer;
  123             // agriggio -- assume the image is normalized to [0, 65535]
  124             for (int i = 0; i < width; i++) {
  125                 sbuffer[ix++] = r(row, i) / 65535.f;
  126                 sbuffer[ix++] = g(row, i) / 65535.f;
  127                 sbuffer[ix++] = b(row, i) / 65535.f;
  128             }
  129         } else if (bps == 16) {
  130             int ix = 0;
  131             uint16_t* sbuffer = (uint16_t*) buffer;
  132             // agriggio -- assume the image is normalized to [0, 65535]
  133             for (int i = 0; i < width; i++) {
  134                 sbuffer[ix++] = DNG_FloatToHalf(r(row, i) / 65535.f);
  135                 sbuffer[ix++] = DNG_FloatToHalf(g(row, i) / 65535.f);
  136                 sbuffer[ix++] = DNG_FloatToHalf(b(row, i) / 65535.f);
  137             }
  138         }
  139     } else {
  140         unsigned short *sbuffer = (unsigned short *)buffer;
  141         for (int i = 0, ix = 0; i < width; i++) {
  142             float ri = r(row, i);
  143             float gi = g(row, i);
  144             float bi = b(row, i);
  145             if (bps == 16) {
  146                 sbuffer[ix++] = CLIP(ri);
  147                 sbuffer[ix++] = CLIP(gi);
  148                 sbuffer[ix++] = CLIP(bi);
  149             } else if (bps == 8) {
  150                 buffer[ix++] = rtengine::uint16ToUint8Rounded(CLIP(ri));
  151                 buffer[ix++] = rtengine::uint16ToUint8Rounded(CLIP(gi));
  152                 buffer[ix++] = rtengine::uint16ToUint8Rounded(CLIP(bi));
  153             }
  154         }
  155     }
  156 }
  157 
  158 Imagefloat* Imagefloat::copy () const
  159 {
  160 
  161     Imagefloat* cp = new Imagefloat (width, height);
  162     copyData(cp);
  163     return cp;
  164 }
  165 
  166 // This is called by the StdImageSource class. We assume that fp images from StdImageSource don't have to deal with gamma
  167 void Imagefloat::getStdImage (const ColorTemp &ctemp, int tran, Imagefloat* image, PreviewProps pp) const
  168 {
  169 
  170     // compute channel multipliers
  171     float rm = 1.f, gm = 1.f, bm = 1.f;
  172     if (ctemp.getTemp() >= 0) {
  173         double drm, dgm, dbm;
  174         ctemp.getMultipliers (drm, dgm, dbm);
  175         rm = drm;
  176         gm = dgm;
  177         bm = dbm;
  178 
  179         rm = 1.0 / rm;
  180         gm = 1.0 / gm;
  181         bm = 1.0 / bm;
  182         float mul_lum = 0.299 * rm + 0.587 * gm + 0.114 * bm;
  183         rm /= mul_lum;
  184         gm /= mul_lum;
  185         bm /= mul_lum;
  186     }
  187 
  188     int sx1, sy1, sx2, sy2;
  189 
  190     transform (pp, tran, sx1, sy1, sx2, sy2);
  191 
  192     int imwidth = image->width; // Destination image
  193     int imheight = image->height; // Destination image
  194 
  195     if (((tran & TR_ROT) == TR_R90) || ((tran & TR_ROT) == TR_R270)) {
  196         int swap = imwidth;
  197         imwidth = imheight;
  198         imheight = swap;
  199     }
  200 
  201     int maxx = width; // Source image
  202     int maxy = height; // Source image
  203     int mtran = tran & TR_ROT;
  204     int skip = pp.getSkip();
  205 
  206     // improve speed by integrating the area division into the multipliers
  207     // switched to using ints for the red/green/blue channel buffer.
  208     // Incidentally this improves accuracy too.
  209     float area = skip * skip;
  210     float rm2 = rm;
  211     float gm2 = gm;
  212     float bm2 = bm;
  213     rm /= area;
  214     gm /= area;
  215     bm /= area;
  216 
  217     const auto CLIP0 = [](float v) -> float { return std::max(v, 0.f); };
  218 
  219 #ifdef _OPENMP
  220     #pragma omp parallel
  221     {
  222 #endif
  223         AlignedBuffer<float> abR(imwidth);
  224         AlignedBuffer<float> abG(imwidth);
  225         AlignedBuffer<float> abB(imwidth);
  226         float *lineR  = abR.data;
  227         float *lineG  = abG.data;
  228         float *lineB =  abB.data;
  229 
  230 #ifdef _OPENMP
  231         #pragma omp for
  232 #endif
  233 
  234         for (int iy = 0; iy < imheight; iy++) {
  235             if (skip == 1) {
  236                 // special case (speedup for 1:1 scale)
  237                 // i: source image, first line of the current destination row
  238                 int src_y = sy1 + iy;
  239 
  240                 // overflow security check, not sure that it's necessary
  241                 if (src_y >= maxy) {
  242                     continue;
  243                 }
  244 
  245                 for (int dst_x = 0, src_x = sx1; dst_x < imwidth; dst_x++, src_x++) {
  246                     // overflow security check, not sure that it's necessary
  247                     if (src_x >= maxx) {
  248                         continue;
  249                     }
  250 
  251                     lineR[dst_x] = CLIP0(rm2 * r(src_y, src_x));
  252                     lineG[dst_x] = CLIP0(gm2 * g(src_y, src_x));
  253                     lineB[dst_x] = CLIP0(bm2 * b(src_y, src_x));
  254                 }
  255             } else {
  256                 // source image, first line of the current destination row
  257                 int src_y = sy1 + skip * iy;
  258 
  259                 if (src_y >= maxy) {
  260                     continue;
  261                 }
  262 
  263                 for (int dst_x = 0, src_x = sx1; dst_x < imwidth; dst_x++, src_x += skip) {
  264                     if (src_x >= maxx) {
  265                         continue;
  266                     }
  267 
  268                     int src_sub_width = MIN(maxx - src_x, skip);
  269                     int src_sub_height = MIN(maxy - src_y, skip);
  270 
  271                     float rtot, gtot, btot; // RGB accumulators
  272                     rtot = gtot = btot = 0.;
  273 
  274                     for (int src_sub_y = 0; src_sub_y < src_sub_height; src_sub_y++)
  275                         for (int src_sub_x = 0; src_sub_x < src_sub_width; src_sub_x++) {
  276                             rtot += r(src_y + src_sub_y, src_x + src_sub_x);
  277                             gtot += g(src_y + src_sub_y, src_x + src_sub_x);
  278                             btot += b(src_y + src_sub_y, src_x + src_sub_x);
  279                         }
  280 
  281                     // convert back to gamma and clip
  282                     if (src_sub_width == skip && src_sub_height == skip) {
  283                         // Common case where the sub-region is complete
  284                         lineR[dst_x] = CLIP0(rm * rtot);
  285                         lineG[dst_x] = CLIP0(gm * gtot);
  286                         lineB[dst_x] = CLIP0(bm * btot);
  287                     } else {
  288                         // computing a special factor for this incomplete sub-region
  289                         float area = src_sub_width * src_sub_height;
  290                         lineR[dst_x] = CLIP0(rm2 * rtot / area);
  291                         lineG[dst_x] = CLIP0(gm2 * gtot / area);
  292                         lineB[dst_x] = CLIP0(bm2 * btot / area);
  293                     }
  294                 }
  295             }
  296 
  297             if      (mtran == TR_NONE)
  298                 for (int dst_x = 0, src_x = sx1; dst_x < imwidth; dst_x++, src_x += skip) {
  299                     image->r(iy, dst_x) = lineR[dst_x];
  300                     image->g(iy, dst_x) = lineG[dst_x];
  301                     image->b(iy, dst_x) = lineB[dst_x];
  302                 }
  303             else if (mtran == TR_R180)
  304                 for (int dst_x = 0; dst_x < imwidth; dst_x++) {
  305                     image->r(imheight - 1 - iy, imwidth - 1 - dst_x) = lineR[dst_x];
  306                     image->g(imheight - 1 - iy, imwidth - 1 - dst_x) = lineG[dst_x];
  307                     image->b(imheight - 1 - iy, imwidth - 1 - dst_x) = lineB[dst_x];
  308                 }
  309             else if (mtran == TR_R90)
  310                 for (int dst_x = 0, src_x = sx1; dst_x < imwidth; dst_x++, src_x += skip) {
  311                     image->r(dst_x, imheight - 1 - iy) = lineR[dst_x];
  312                     image->g(dst_x, imheight - 1 - iy) = lineG[dst_x];
  313                     image->b(dst_x, imheight - 1 - iy) = lineB[dst_x];
  314                 }
  315             else if (mtran == TR_R270)
  316                 for (int dst_x = 0, src_x = sx1; dst_x < imwidth; dst_x++, src_x += skip) {
  317                     image->r(imwidth - 1 - dst_x, iy) = lineR[dst_x];
  318                     image->g(imwidth - 1 - dst_x, iy) = lineG[dst_x];
  319                     image->b(imwidth - 1 - dst_x, iy) = lineB[dst_x];
  320                 }
  321         }
  322 
  323 #ifdef _OPENMP
  324     }
  325 #endif
  326 }
  327 
  328 Image8*
  329 Imagefloat::to8() const
  330 {
  331     Image8* img8 = new Image8(width, height);
  332 #ifdef _OPENMP
  333     #pragma omp parallel for schedule(static)
  334 #endif
  335 
  336     for (int h = 0; h < height; ++h) {
  337         for (int w = 0; w < width; ++w) {
  338             img8->r(h, w) = uint16ToUint8Rounded(CLIP(r(h, w)));
  339             img8->g(h, w) = uint16ToUint8Rounded(CLIP(g(h, w)));
  340             img8->b(h, w) = uint16ToUint8Rounded(CLIP(b(h, w)));
  341         }
  342     }
  343 
  344     return img8;
  345 }
  346 
  347 Image16*
  348 Imagefloat::to16() const
  349 {
  350     Image16* img16 = new Image16(width, height);
  351 #ifdef _OPENMP
  352     #pragma omp parallel for schedule(static)
  353 #endif
  354 
  355     for (int h = 0; h < height; ++h) {
  356         for (int w = 0; w < width; ++w) {
  357             img16->r(h, w) = CLIP(r(h, w));
  358             img16->g(h, w) = CLIP(g(h, w));
  359             img16->b(h, w) = CLIP(b(h, w));
  360         }
  361     }
  362 
  363     return img16;
  364 }
  365 
  366 void Imagefloat::normalizeFloat(float srcMinVal, float srcMaxVal)
  367 {
  368 
  369     float scale = MAXVALD / (srcMaxVal - srcMinVal);
  370     int w = width;
  371     int h = height;
  372 
  373 #ifdef _OPENMP
  374     #pragma omp parallel for firstprivate(w, h, srcMinVal, scale) schedule(dynamic, 5)
  375 #endif
  376 
  377     for (int y = 0; y < h; y++) {
  378         for (int x = 0; x < w; x++) {
  379             r(y, x) = (r(y, x) - srcMinVal) * scale;
  380             g(y, x) = (g(y, x) - srcMinVal) * scale;
  381             b(y, x) = (b(y, x) - srcMinVal) * scale;
  382         }
  383     }
  384 }
  385 
  386 // convert values's range to [0;1] ; this method assumes that the input values's range is [0;65535]
  387 void Imagefloat::normalizeFloatTo1()
  388 {
  389 
  390     int w = width;
  391     int h = height;
  392 
  393 #ifdef _OPENMP
  394     #pragma omp parallel for firstprivate(w, h) schedule(dynamic, 5)
  395 #endif
  396 
  397     for (int y = 0; y < h; y++) {
  398         for (int x = 0; x < w; x++) {
  399             r(y, x) /= 65535.f;
  400             g(y, x) /= 65535.f;
  401             b(y, x) /= 65535.f;
  402         }
  403     }
  404 }
  405 
  406 // convert values's range to [0;65535 ; this method assumes that the input values's range is [0;1]
  407 void Imagefloat::normalizeFloatTo65535()
  408 {
  409 
  410     int w = width;
  411     int h = height;
  412 
  413 #ifdef _OPENMP
  414     #pragma omp parallel for firstprivate(w, h) schedule(dynamic, 5)
  415 #endif
  416 
  417     for (int y = 0; y < h; y++) {
  418         for (int x = 0; x < w; x++) {
  419             r(y, x) *= 65535.f;
  420             g(y, x) *= 65535.f;
  421             b(y, x) *= 65535.f;
  422         }
  423     }
  424 }
  425 
  426 void Imagefloat::calcCroppedHistogram(const ProcParams &params, float scale, LUTu & hist)
  427 {
  428 
  429     hist.clear();
  430 
  431     // Set up factors to calc the lightness
  432     TMatrix wprof = ICCStore::getInstance()->workingSpaceMatrix (params.icm.workingProfile);
  433 
  434     float facRed   = wprof[1][0];
  435     float facGreen = wprof[1][1];
  436     float facBlue  = wprof[1][2];
  437 
  438 
  439     // calc pixel size
  440     int x1, x2, y1, y2;
  441     params.crop.mapToResized(width, height, scale, x1, x2, y1, y2);
  442 
  443 #ifdef _OPENMP
  444     #pragma omp parallel
  445 #endif
  446     {
  447         LUTu histThr(65536);
  448         histThr.clear();
  449 #ifdef _OPENMP
  450         #pragma omp for nowait
  451 #endif
  452 
  453         for (int y = y1; y < y2; y++) {
  454             for (int x = x1; x < x2; x++) {
  455                 int i = (int)(facRed * r(y, x) + facGreen * g(y, x) + facBlue * b(y, x));
  456 
  457                 if (i < 0) {
  458                     i = 0;
  459                 } else if (i > 65535) {
  460                     i = 65535;
  461                 }
  462 
  463                 histThr[i]++;
  464             }
  465         }
  466 
  467 #ifdef _OPENMP
  468         #pragma omp critical
  469 #endif
  470         {
  471             for(int i = 0; i <= 0xffff; i++) {
  472                 hist[i] += histThr[i];
  473             }
  474         }
  475     }
  476 
  477 }
  478 
  479 // Parallelized transformation; create transform with cmsFLAGS_NOCACHE!
  480 void Imagefloat::ExecCMSTransform(cmsHTRANSFORM hTransform)
  481 {
  482 
  483     // LittleCMS cannot parallelize planar setups -- Hombre: LCMS2.4 can! But it we use this new feature, memory allocation
  484     // have to be modified too to build temporary buffers that allow multi processor execution
  485 #ifdef _OPENMP
  486     #pragma omp parallel
  487 #endif
  488     {
  489         AlignedBuffer<float> pBuf(width * 3);
  490 
  491 #ifdef _OPENMP
  492         #pragma omp for schedule(dynamic, 16)
  493 #endif
  494 
  495         for (int y = 0; y < height; y++)
  496         {
  497             float *p = pBuf.data, *pR = r(y), *pG = g(y), *pB = b(y);
  498 
  499             for (int x = 0; x < width; x++) {
  500                 *(p++) = *(pR++);
  501                 *(p++) = *(pG++);
  502                 *(p++) = *(pB++);
  503             }
  504 
  505             cmsDoTransform (hTransform, pBuf.data, pBuf.data, width);
  506 
  507             p = pBuf.data;
  508             pR = r(y);
  509             pG = g(y);
  510             pB = b(y);
  511 
  512             for (int x = 0; x < width; x++) {
  513                 *(pR++) = *(p++);
  514                 *(pG++) = *(p++);
  515                 *(pB++) = *(p++);
  516             }
  517         } // End of parallelization
  518     }
  519 }
  520 
  521 // Parallelized transformation; create transform with cmsFLAGS_NOCACHE!
  522 void Imagefloat::ExecCMSTransform(cmsHTRANSFORM hTransform, const LabImage &labImage, int cx, int cy)
  523 {
  524     // LittleCMS cannot parallelize planar Lab float images
  525     // so build temporary buffers to allow multi processor execution
  526 #ifdef _OPENMP
  527     #pragma omp parallel
  528 #endif
  529     {
  530         AlignedBuffer<float> bufferLab(width * 3);
  531         AlignedBuffer<float> bufferRGB(width * 3);
  532 
  533 #ifdef _OPENMP
  534         #pragma omp for schedule(static)
  535 #endif
  536 
  537         for (int y = cy; y < cy + height; y++)
  538         {
  539             float *pRGB, *pR, *pG, *pB;
  540             float *pLab, *pL, *pa, *pb;
  541 
  542             pLab= bufferLab.data;
  543             pL = labImage.L[y] + cx;
  544             pa = labImage.a[y] + cx;
  545             pb = labImage.b[y] + cx;
  546 
  547             for (int x = 0; x < width; x++) {
  548                 *(pLab++) = *(pL++)  / 327.68f;
  549                 *(pLab++) = *(pa++)  / 327.68f;
  550                 *(pLab++) = *(pb++)  / 327.68f;
  551             }
  552 
  553             cmsDoTransform (hTransform, bufferLab.data, bufferRGB.data, width);
  554 
  555             pRGB = bufferRGB.data;
  556             pR = r(y - cy);
  557             pG = g(y - cy);
  558             pB = b(y - cy);
  559 
  560             for (int x = 0; x < width; x++) {
  561                 *(pR++) = *(pRGB++);
  562                 *(pG++) = *(pRGB++);
  563                 *(pB++) = *(pRGB++);
  564             }
  565         } // End of parallelization
  566     }
  567 }