/* * This file is part of RawTherapee. * * Copyright (c) 2004-2010 Gabor Horvath * * RawTherapee is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * RawTherapee is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ #ifndef _IIMAGE_ #define _IIMAGE_ #include #include #include #include #include "../rtgui/threadutils.h" #include "rt_math.h" #include "alignedbuffer.h" #include "imagedimensions.h" #include "LUT.h" #include "coord2d.h" #include "procparams.h" #include "color.h" #include "colortemp.h" #define TR_NONE 0 #define TR_R90 1 #define TR_R180 2 #define TR_R270 3 #define TR_VFLIP 4 #define TR_HFLIP 8 #define TR_ROT 3 #define CHECK_BOUNDS 0 namespace rtengine { extern const char sImage8[]; extern const char sImage16[]; extern const char sImagefloat[]; class ProgressListener; class Color; enum TypeInterpolation { TI_Nearest, TI_Bilinear }; // -------------------------------------------------------------------- // Generic classes // -------------------------------------------------------------------- class ImageDatas : virtual public ImageDimensions { public: template void convertTo (S srcValue, D &dstValue) { dstValue = static_cast(srcValue); } // parameters that will never be used, replaced by the subclasses r, g and b parameters! // they are still necessary to implement operator() in this parent class virtual ~ImageDatas() {} virtual void allocate (int W, int H) {} virtual void rotate (int deg) {} // free the memory allocated for the image data without deleting the object. virtual void flushData () { allocate(0,0); } virtual void hflip () {} virtual void vflip () {} // Read the raw dump of the data void readData (FILE *fh) {} // Write a raw dump of the data void writeData (FILE *fh) {} virtual void normalizeInt (int srcMinVal, int srcMaxVal) {}; virtual void normalizeFloat (float srcMinVal, float srcMaxVal) {}; virtual void computeHistogramAutoWB (double &avg_r, double &avg_g, double &avg_b, int &n, LUTu &histogram, int compression) {} virtual void getSpotWBData (double &reds, double &greens, double &blues, int &rn, int &gn, int &bn, std::vector &red, std::vector &green, std::vector &blue, int tran) {} virtual void getAutoWBMultipliers (double &rm, double &gm, double &bm) { rm=gm=bm=1.0; } virtual const char* getType () const { return "unknown"; } }; template <> inline void ImageDatas::convertTo (unsigned short srcValue, unsigned char &dstValue) { dstValue = (unsigned char)(srcValue >> 8); } template <> inline void ImageDatas::convertTo (unsigned char srcValue, int &dstValue) { dstValue = (int)(srcValue) << 8; } template <> inline void ImageDatas::convertTo (unsigned char srcValue, unsigned short &dstValue) { dstValue = (unsigned short)(srcValue) << 8; } template <> inline void ImageDatas::convertTo (float srcValue, unsigned char &dstValue) { dstValue = (unsigned char)( (unsigned short)(srcValue) >> 8 ); } template <> inline void ImageDatas::convertTo (unsigned char srcValue, float &dstValue) { dstValue = float( (unsigned short)(srcValue) << 8 ); } // -------------------------------------------------------------------- // Planar order classes // -------------------------------------------------------------------- template class PlanarPtr { protected: AlignedBuffer ab; public: #if CHECK_BOUNDS int width_, height_; #endif T** ptrs; #if CHECK_BOUNDS PlanarPtr() : width_(0), height_(0), ptrs (NULL) {} #else PlanarPtr() : ptrs (NULL){} #endif bool resize(int newSize) { if (ab.resize(newSize)) { ptrs=ab.data; return true; } else { ptrs=NULL; return false; } } void swap (PlanarPtr &other) { ab.swap(other.ab); T** tmpsPtrs = other.ptrs; other.ptrs = ptrs; ptrs = tmpsPtrs; #if CHECK_BOUNDS int tmp = other.width_; other.width_ = width_; width_ = tmp; tmp = other.height_; other.height_ = height_; height_ = tmp; #endif } T*& operator() (unsigned row) { #if CHECK_BOUNDS assert (row < height_); #endif return ptrs[row]; } // Will send back the start of a row, starting with a red, green or blue value T* operator() (unsigned row) const { #if CHECK_BOUNDS assert (row < height_); #endif return ptrs[row]; } // Will send back a value at a given row, col position T& operator() (unsigned row, unsigned col) { #if CHECK_BOUNDS assert (row < height_ && col < width_); #endif return ptrs[row][col]; } const T operator() (unsigned row, unsigned col) const { #if CHECK_BOUNDS assert (row < height_ && col < width_); #endif return ptrs[row][col]; } }; template class PlanarWhateverData : virtual public ImageDatas { private: AlignedBuffer abData; int rowstride; // Plan size, in bytes (all padding bytes included) public: T* data; PlanarPtr v; // v stands for "value", whatever it represent PlanarWhateverData() : rowstride(0), data (NULL) {} PlanarWhateverData(int w, int h) : rowstride(0), data (NULL) { allocate(w, h); } // Send back the row stride. WARNING: unit = byte, not element! int getRowStride () { return rowstride; } void swap(PlanarWhateverData &other) { abData.swap(other.abData); v.swap(other.v); T* tmpData = other.data; other.data = data; data = tmpData; int tmpWidth = other.width; other.width = width; width = tmpWidth; int tmpHeight = other.height; other.height = height; height = tmpHeight; #if CHECK_BOUNDS v.width_ = width; v.height_ = height; #endif } // use as pointer to data //operator void*() { return data; }; /* If any of the required allocation fails, "width" and "height" are set to -1, and all remaining buffer are freed * Can be safely used to reallocate an existing image */ void allocate (int W, int H) { if (W==width && H==height) return; width=W; height=H; #if CHECK_BOUNDS v.width_ = width; v.height_ = height; #endif if (sizeof(T) > 1) { // 128 bits memory alignment for >8bits data rowstride = ( width*sizeof(T)+15 )/16*16; } else { // No memory alignment for 8bits data rowstride = width*sizeof(T); } // find the padding length to ensure a 128 bits alignment for each row size_t size = rowstride * height; if (!width) { size = 0; rowstride = 0; } if (size && abData.resize(size, 1) && v.resize(height) ) { data = abData.data; } else { // asking for a new size of 0 is safe and will free memory, if any! abData.resize(0); data = NULL; v.resize(0); width = height = -1; #if CHECK_BOUNDS v.width_ = v.height_ = -1; #endif return; } char *start = (char*)(data); for (int i=0; i *dest) { assert (dest!=NULL); // Make sure that the size is the same, reallocate if necessary dest->allocate(width, height); if (dest->width == -1) { return; } for (int i=0; iv(i), v(i), width*sizeof(T)); } } void rotate (int deg) { if (deg==90) { PlanarWhateverData rotatedImg(height, width); // New image, rotated for (int ny=0; ny rotatedImg(height, width); // New image, rotated for (int nx=0; nx32 && height>50; #pragma omp parallel for schedule(static) if(bigImage) #endif for (int i=0; i void resizeImgTo (int nw, int nh, TypeInterpolation interp, PlanarWhateverData *imgPtr) { //printf("resizeImgTo: resizing %s image data (%d x %d) to %s (%d x %d)\n", getType(), width, height, imgPtr->getType(), imgPtr->width, imgPtr->height); if (interp == TI_Nearest) { for (int i=0; iv(i,j)); } } } else if (interp == TI_Bilinear) { for (int i=0; i=height) sy = height-1; float dy = float(i)*float(height)/float(nh) - float(sy); int ny = sy+1; if (ny>=height) ny = sy; for (int j=0; j=width) sx = width; float dx = float(j)*float(width)/float(nw) - float(sx); int nx = sx+1; if (nx>=width) nx = sx; convertTo(v(sy,sx)*(1.f-dx)*(1.f-dy) + v(sy,nx)*dx*(1.f-dy) + v(ny,sx)*(1.f-dx)*dy + v(ny,nx)*dx*dy, imgPtr->v(i,j)); } } } else { // This case should never occur! for (int i=0; i32 && height>50; #pragma omp parallel for schedule(static) if(bigImage) #endif for (int i=0; i32 && height>50; #pragma omp parallel for schedule(static) if(bigImage) #endif for (int i=0; i please creates specialization if necessary unsigned long int n = 0; int halfSquare = squareSize/2; transformPixel (posX, posY, tran, x, y); for (int iy=y-halfSquare; iy=0 && iy>=0 && ixv(iy, ix)); ++n; } } } value = n ? T(accumulator/float(n)) : T(0); } void readData (FILE *f) { for (int i=0; i class PlanarRGBData : virtual public ImageDatas { private: AlignedBuffer abData; int rowstride; // Plan size, in bytes (all padding bytes included) int planestride; // Row length, in bytes (padding bytes included) public: T* data; PlanarPtr r; PlanarPtr g; PlanarPtr b; PlanarRGBData() : rowstride(0), planestride(0), data (NULL) {} PlanarRGBData(int w, int h) : rowstride(0), planestride(0), data (NULL) { allocate(w, h); } // Send back the row stride. WARNING: unit = byte, not element! int getRowStride () { return rowstride; } // Send back the plane stride. WARNING: unit = byte, not element! int getPlaneStride () { return planestride; } void swap(PlanarRGBData &other) { abData.swap(other.abData); r.swap(other.r); g.swap(other.g); b.swap(other.b); T* tmpData = other.data; other.data = data; data = tmpData; int tmpWidth = other.width; other.width = width; width = tmpWidth; int tmpHeight = other.height; other.height = height; height = tmpHeight; #if CHECK_BOUNDS r.width_ = width; r.height_ = height; g.width_ = width; g.height_ = height; b.width_ = width; b.height_ = height; #endif } // use as pointer to data //operator void*() { return data; }; /* If any of the required allocation fails, "width" and "height" are set to -1, and all remaining buffer are freed * Can be safely used to reallocate an existing image */ void allocate (int W, int H) { if (W==width && H==height) return; width=W; height=H; #if CHECK_BOUNDS r.width_ = width; r.height_ = height; g.width_ = width; g.height_ = height; b.width_ = width; b.height_ = height; #endif if (sizeof(T) > 1) { // 128 bits memory alignment for >8bits data rowstride = ( width*sizeof(T)+15 )/16*16; planestride = rowstride * height; } else { // No memory alignment for 8bits data rowstride = width*sizeof(T); planestride = rowstride * height; } // find the padding length to ensure a 128 bits alignment for each row size_t size = rowstride * 3*height; if (!width) { size = 0; rowstride = 0; } if (size && abData.resize(size, 1) && r.resize(height) && g.resize(height) && b.resize(height) ) { data = abData.data; } else { // asking for a new size of 0 is safe and will free memory, if any! abData.resize(0); data = NULL; r.resize(0); g.resize(0); b.resize(0); width = height = -1; #if CHECK_BOUNDS r.width_ = r.height_ = -1; g.width_ = g.height_ = -1; b.width_ = b.height_ = -1; #endif return; } char *redstart = (char*)(data); char *greenstart = (char*)(data) + planestride; char *bluestart = (char*)(data) + 2*planestride; for (int i=0; i *dest) { assert (dest!=NULL); // Make sure that the size is the same, reallocate if necessary dest->allocate(width, height); if (dest->width == -1) { printf("ERROR: PlanarRGBData::copyData >>> allocation failed!\n"); return; } for (int i=0; ir(i), r(i), width*sizeof(T)); memcpy (dest->g(i), g(i), width*sizeof(T)); memcpy (dest->b(i), b(i), width*sizeof(T)); } } void rotate (int deg) { if (deg==90) { PlanarRGBData rotatedImg(height, width); // New image, rotated for (int ny=0; ny rotatedImg(height, width); // New image, rotated for (int nx=0; nx32 && height>50; #pragma omp parallel for schedule(static) if(bigImage) #endif for (int i=0; i void resizeImgTo (int nw, int nh, TypeInterpolation interp, IC *imgPtr) { //printf("resizeImgTo: resizing %s image data (%d x %d) to %s (%d x %d)\n", getType(), width, height, imgPtr->getType(), imgPtr->width, imgPtr->height); if (interp == TI_Nearest) { for (int i=0; ir(i,j)); convertTo(g(ri,ci), imgPtr->g(i,j)); convertTo(b(ri,ci), imgPtr->b(i,j)); } } } else if (interp == TI_Bilinear) { for (int i=0; i=height) sy = height-1; float dy = float(i)*float(height)/float(nh) - float(sy); int ny = sy+1; if (ny>=height) ny = sy; for (int j=0; j=width) sx = width; float dx = float(j)*float(width)/float(nw) - float(sx); int nx = sx+1; if (nx>=width) nx = sx; convertTo(r(sy,sx)*(1.f-dx)*(1.f-dy) + r(sy,nx)*dx*(1.f-dy) + r(ny,sx)*(1.f-dx)*dy + r(ny,nx)*dx*dy, imgPtr->r(i,j)); convertTo(g(sy,sx)*(1.f-dx)*(1.f-dy) + g(sy,nx)*dx*(1.f-dy) + g(ny,sx)*(1.f-dx)*dy + g(ny,nx)*dx*dy, imgPtr->g(i,j)); convertTo(b(sy,sx)*(1.f-dx)*(1.f-dy) + b(sy,nx)*dx*(1.f-dy) + b(ny,sx)*(1.f-dx)*dy + b(ny,nx)*dx*dy, imgPtr->b(i,j)); } } } else { // This case should never occur! for (int i=0; i32 && height>50; #pragma omp parallel for schedule(static) if(bigImage) #endif for (int i=0; i32 && height>50; #pragma omp parallel for schedule(static) if(bigImage) #endif for (int i=0; i>histcompr); histogram.clear(); for (int i=0; i(r(i,j), r_); convertTo(g(i,j), g_); convertTo(b(i,j), b_); histogram[(int)Color::igamma_srgb (r_)>>histcompr]++; histogram[(int)Color::igamma_srgb (g_)>>histcompr]++; histogram[(int)Color::igamma_srgb (b_)>>histcompr]++; } } void computeHistogramAutoWB (double &avg_r, double &avg_g, double &avg_b, int &n, LUTu &histogram, const int compression) { histogram.clear(); avg_r = avg_g = avg_b = 0.; n=0; for (unsigned int i=0; i<(unsigned int)(height); i++) for (unsigned int j=0; j<(unsigned int)(width); j++) { float r_, g_, b_; convertTo(r(i,j), r_); convertTo(g(i,j), g_); convertTo(b(i,j), b_); int rtemp = Color::igamma_srgb (r_); int gtemp = Color::igamma_srgb (g_); int btemp = Color::igamma_srgb (b_); histogram[rtemp>>compression]++; histogram[gtemp>>compression]+=2; histogram[btemp>>compression]++; // autowb computation if (r_>64000.f || g_>64000.f || b_>64000.f) continue; avg_r += double(r_); avg_g += double(g_); avg_b += double(b_); n++; } } void getAutoWBMultipliers (double &rm, double &gm, double &bm) { double avg_r = 0.; double avg_g = 0.; double avg_b = 0.; int n = 0; //int p = 6; for (unsigned int i=0; i<(unsigned int)(height); i++) for (unsigned int j=0; j<(unsigned int)(width); j++) { float r_, g_, b_; convertTo(r(i,j), r_); convertTo(g(i,j), g_); convertTo(b(i,j), b_); if (r_>64000.f || g_>64000.f || b_>64000.f) continue; avg_r += double(r_); avg_g += double(g_); avg_b += double(b_); /*avg_r += intpow( (double)r(i, j), p); avg_g += intpow( (double)g(i, j), p); avg_b += intpow( (double)b(i, j), p);*/ n++; } rm = avg_r/double(n); gm = avg_g/double(n); bm = avg_b/double(n); } void transformPixel (int x, int y, int tran, int& tx, int& ty) { if (!tran) { tx = x; ty = y; return; } int W = width; int H = height; int sw = W, sh = H; if ((tran & TR_ROT) == TR_R90 || (tran & TR_ROT) == TR_R270) { sw = H; sh = W; } int ppx = x, ppy = y; if (tran & TR_HFLIP) ppx = sw - 1 - x; if (tran & TR_VFLIP) ppy = sh - 1 - y; tx = ppx; ty = ppy; if ((tran & TR_ROT) == TR_R180) { tx = W - 1 - ppx; ty = H - 1 - ppy; } else if ((tran & TR_ROT) == TR_R90) { tx = ppy; ty = H - 1 - ppx; } else if ((tran & TR_ROT) == TR_R270) { tx = W - 1 - ppy; ty = ppx; } } virtual void getSpotWBData (double &reds, double &greens, double &blues, int &rn, int &gn, int &bn, std::vector &red, std::vector &green, std::vector &blue, int tran) { int x; int y; reds = 0, greens = 0, blues = 0; rn = 0, gn = 0, bn = 0; for (size_t i=0; i=0 && y>=0 && x(this->r(y, x), v); reds += double(v); rn++; } transformPixel (green[i].x, green[i].y, tran, x, y); if (x>=0 && y>=0 && x(this->g(y, x), v); greens += double(v); gn++; } transformPixel (blue[i].x, blue[i].y, tran, x, y); if (x>=0 && y>=0 && x(this->b(y, x), v); blues += double(v); bn++; } } } void getPipetteData (T &valueR, T &valueG, T &valueB, int posX, int posY, int squareSize, int tran) { int x; int y; float accumulatorR = 0.f; // using float to avoid range overflow; -> please creates specialization if necessary float accumulatorG = 0.f; // " float accumulatorB = 0.f; // " unsigned long int n = 0; int halfSquare = squareSize/2; transformPixel (posX, posY, tran, x, y); for (int iy=y-halfSquare; iy=0 && iy>=0 && ixr(iy, ix)); accumulatorG += float(this->g(iy, ix)); accumulatorB += float(this->b(iy, ix)); ++n; } } } valueR = n ? T(accumulatorR/float(n)) : T(0); valueG = n ? T(accumulatorG/float(n)) : T(0); valueB = n ? T(accumulatorB/float(n)) : T(0); } void readData (FILE *f) { for (int i=0; i class ChunkyPtr { private: T* ptr; int width; public: #if CHECK_BOUNDS int width_, height_; #endif #if CHECK_BOUNDS ChunkyPtr() : ptr (NULL), width(-1), width_(0), height_(0) {} #else ChunkyPtr() : ptr (NULL), width(-1) {} #endif void init(T* base, int w=-1) { ptr = base; width=w; } void swap (ChunkyPtr &other) { T* tmpsPtr = other.ptr; other.ptr = ptr; ptr = tmpsPtr; int tmpWidth = other.width; other.width = width; width = tmpWidth; #if CHECK_BOUNDS int tmp = other.width_; other.width_ = width_; width_ = tmp; tmp = other.height_; other.height_ = height_; height_ = tmp; #endif } // Will send back the start of a row, starting with a red, green or blue value T* operator() (unsigned row) const { #if CHECK_BOUNDS assert (row < height_); #endif return &ptr[3*(row*width)]; } // Will send back a value at a given row, col position T& operator() (unsigned row, unsigned col) { #if CHECK_BOUNDS assert (row < height_ && col < width_); #endif return ptr[3*(row*width+col)]; } const T operator() (unsigned row, unsigned col) const { #if CHECK_BOUNDS assert (row < height_ && col < width_); #endif return ptr[3*(row*width+col)]; } }; template class ChunkyRGBData : virtual public ImageDatas { private: AlignedBuffer abData; public: T* data; ChunkyPtr r; ChunkyPtr g; ChunkyPtr b; ChunkyRGBData() : data (NULL) {} ChunkyRGBData(int w, int h) : data (NULL) { allocate(w, h); } /** Returns the pixel data, in r/g/b order from top left to bottom right continuously. * @return a pointer to the pixel data */ const T* getData () { return data; } void swap(ChunkyRGBData &other) { abData.swap(other.abData); r.swap(other.r); g.swap(other.g); b.swap(other.b); T* tmpData = other.data; other.data = data; data = tmpData; int tmpWidth = other.width; other.width = width; width = tmpWidth; int tmpHeight = other.height; other.height = height; height = tmpHeight; #if CHECK_BOUNDS r.width_ = width; r.height_ = height; g.width_ = width; g.height_ = height; b.width_ = width; b.height_ = height; #endif } /* * If any of the required allocation fails, "width" and "height" are set to -1, and all remaining buffer are freed * Can be safely used to reallocate an existing image or to free up it's memory with "allocate (0,0);" */ void allocate (int W, int H) { if (W==width && H==height) return; width=W; height=H; #if CHECK_BOUNDS r.width_ = width; r.height_ = height; g.width_ = width; g.height_ = height; b.width_ = width; b.height_ = height; #endif abData.resize(width*height*3); if (!abData.isEmpty()) { data = abData.data; r.init(data, width); g.init(data+1, width); b.init(data+2, width); } else { data = NULL; r.init(NULL); g.init(NULL); b.init(NULL); width = height = -1; #if CHECK_BOUNDS r.width_ = r.height_ = -1; g.width_ = g.height_ = -1; b.width_ = b.height_ = -1; #endif } } /** Copy the data to another ChunkyRGBData */ void copyData(ChunkyRGBData *dest) { assert (dest!=NULL); // Make sure that the size is the same, reallocate if necessary dest->allocate(width, height); if (dest->width == -1) { printf("ERROR: ChunkyRGBData::copyData >>> allocation failed!\n"); return; } memcpy (dest->data, data, 3*width*height*sizeof(T)); } void rotate (int deg) { if (deg==90) { ChunkyRGBData rotatedImg(height, width); // New image, rotated for (int ny=0; ny rotatedImg(height, width); // New image, rotated for (int nx=0; nx void resizeImgTo (int nw, int nh, TypeInterpolation interp, IC *imgPtr) { //printf("resizeImgTo: resizing %s image data (%d x %d) to %s (%d x %d)\n", getType(), width, height, imgPtr->getType(), imgPtr->width, imgPtr->height); if (interp == TI_Nearest) { for (int i=0; ir(i,j)); convertTo(g(ri,ci), imgPtr->g(i,j)); convertTo(b(ri,ci), imgPtr->b(i,j)); } } } else if (interp == TI_Bilinear) { for (int i=0; i=height) sy = height-1; float dy = float(i)*float(height)/float(nh) - float(sy); int ny = sy+1; if (ny>=height) ny = sy; for (int j=0; j=width) sx = width; float dx = float(j)*float(width)/float(nw) - float(sx); int nx = sx+1; if (nx>=width) nx = sx; T valR = r(sy,sx)*(1.f-dx)*(1.f-dy) + r(sy,nx)*dx*(1.f-dy) + r(ny,sx)*(1.f-dx)*dy + r(ny,nx)*dx*dy; T valG = g(sy,sx)*(1.f-dx)*(1.f-dy) + g(sy,nx)*dx*(1.f-dy) + g(ny,sx)*(1.f-dx)*dy + g(ny,nx)*dx*dy; T valB = b(sy,sx)*(1.f-dx)*(1.f-dy) + b(sy,nx)*dx*(1.f-dy) + b(ny,sx)*(1.f-dx)*dy + b(ny,nx)*dx*dy; convertTo(valR, imgPtr->r(i,j)); convertTo(valG, imgPtr->g(i,j)); convertTo(valB, imgPtr->b(i,j)); } } } else { // This case should never occur! for (int i=0; i lBuffer(3*width); T* lineBuffer = lBuffer.data; size_t size = 3*width*sizeof(T); for (int i=0; i>histcompr); histogram.clear(); for (int i=0; i(r(i,j), r_); convertTo(g(i,j), g_); convertTo(b(i,j), b_); histogram[(int)Color::igamma_srgb (r_)>>histcompr]++; histogram[(int)Color::igamma_srgb (g_)>>histcompr]++; histogram[(int)Color::igamma_srgb (b_)>>histcompr]++; } } void computeHistogramAutoWB (double &avg_r, double &avg_g, double &avg_b, int &n, LUTu &histogram, const int compression) { histogram.clear(); avg_r = avg_g = avg_b = 0.; n=0; for (unsigned int i=0; i<(unsigned int)(height); i++) for (unsigned int j=0; j<(unsigned int)(width); j++) { float r_, g_, b_; convertTo(r(i,j), r_); convertTo(g(i,j), g_); convertTo(b(i,j), b_); int rtemp = Color::igamma_srgb (r_); int gtemp = Color::igamma_srgb (g_); int btemp = Color::igamma_srgb (b_); histogram[rtemp>>compression]++; histogram[gtemp>>compression]+=2; histogram[btemp>>compression]++; // autowb computation if (r_>64000.f || g_>64000.f || b_>64000.f) continue; avg_r += double(r_); avg_g += double(g_); avg_b += double(b_); n++; } } void getAutoWBMultipliers (double &rm, double &gm, double &bm) { double avg_r = 0.; double avg_g = 0.; double avg_b = 0.; int n = 0; //int p = 6; for (unsigned int i=0; i<(unsigned int)(height); i++) for (unsigned int j=0; j<(unsigned int)(width); j++) { float r_, g_, b_; convertTo(r(i,j), r_); convertTo(g(i,j), g_); convertTo(b(i,j), b_); if (r_>64000.f || g_>64000.f || b_>64000.f) continue; avg_r += double(r_); avg_g += double(g_); avg_b += double(b_); /*avg_r += intpow( (double)r(i, j), p); avg_g += intpow( (double)g(i, j), p); avg_b += intpow( (double)b(i, j), p);*/ n++; } rm = avg_r/double(n); gm = avg_g/double(n); bm = avg_b/double(n); } void transformPixel (int x, int y, int tran, int& tx, int& ty) { if (!tran) { tx = x; ty = y; return; } int W = width; int H = height; int sw = W, sh = H; if ((tran & TR_ROT) == TR_R90 || (tran & TR_ROT) == TR_R270) { sw = H; sh = W; } int ppx = x, ppy = y; if (tran & TR_HFLIP) ppx = sw - 1 - x; if (tran & TR_VFLIP) ppy = sh - 1 - y; tx = ppx; ty = ppy; if ((tran & TR_ROT) == TR_R180) { tx = W - 1 - ppx; ty = H - 1 - ppy; } else if ((tran & TR_ROT) == TR_R90) { tx = ppy; ty = H - 1 - ppx; } else if ((tran & TR_ROT) == TR_R270) { tx = W - 1 - ppy; ty = ppx; } } virtual void getSpotWBData (double &reds, double &greens, double &blues, int &rn, int &gn, int &bn, std::vector &red, std::vector &green, std::vector &blue, int tran) { int x; int y; reds = 0, greens = 0, blues = 0; rn = 0, gn = 0, bn = 0; for (size_t i=0; i=0 && y>=0 && x(this->r(y, x), v); reds += double(v); rn++; } transformPixel (green[i].x, green[i].y, tran, x, y); if (x>=0 && y>=0 && x(this->g(y, x), v); greens += double(v); gn++; } transformPixel (blue[i].x, blue[i].y, tran, x, y); if (x>=0 && y>=0 && x(this->b(y, x), v); blues += double(v); bn++; } } } void readData (FILE *f) { for (int i=0; i { public: virtual ~IImagefloat() {} }; /** @brief This class represents an image having a classical 8 bits/pixel representation */ class IImage8 : public IImage, public ChunkyRGBData { public: virtual ~IImage8() {} }; /** @brief This class represents an image having a 16 bits/pixel planar representation. The planes are stored as two dimensional arrays. All the rows have a 128 bits alignment. */ class IImage16 : public IImage, public PlanarRGBData { public: virtual ~IImage16() {} }; } #endif