Author: post
Date: 2011-01-30 16:27:27 +0100 (Sun, 30 Jan 2011)
New Revision: 322

Modified:
   RawSpeed/PefDecoder.cpp
   RawSpeed/RawDecoder.cpp
   RawSpeed/RawImage.cpp
   RawSpeed/RawImage.h
Log:
Use black areas on cameras to calculate more precise black levels on cameras 
that support this (mainly Canon).

Modified: RawSpeed/PefDecoder.cpp
===================================================================
--- RawSpeed/PefDecoder.cpp     2011-01-30 15:21:39 UTC (rev 321)
+++ RawSpeed/PefDecoder.cpp     2011-01-30 15:27:27 UTC (rev 322)
@@ -94,7 +94,7 @@
   vector<TiffIFD*> data = mRootIFD->getIFDsWithTag(MODEL);
 
   if (data.empty())
-    ThrowRDE("ARW Meta Decoder: Model name found");
+    ThrowRDE("PEF Meta Decoder: Model name found");
 
   TiffIFD* raw = data[0];
 

Modified: RawSpeed/RawDecoder.cpp
===================================================================
--- RawSpeed/RawDecoder.cpp     2011-01-30 15:21:39 UTC (rev 321)
+++ RawSpeed/RawDecoder.cpp     2011-01-30 15:27:27 UTC (rev 322)
@@ -230,6 +230,7 @@
 
   mRaw->blackLevel = cam->black;
   mRaw->whitePoint = cam->white;
+  mRaw->blackAreas = cam->blackAreas;
 
 }
 

Modified: RawSpeed/RawImage.cpp
===================================================================
--- RawSpeed/RawImage.cpp       2011-01-30 15:21:39 UTC (rev 321)
+++ RawSpeed/RawImage.cpp       2011-01-30 15:27:27 UTC (rev 322)
@@ -106,6 +106,19 @@
   return &data[y*pitch+x*bpp];
 }
 
+uchar8* RawImageData::getDataUncropped(uint32 x, uint32 y) {
+  if ((int)x >= dim.x+mOffset.x)
+    ThrowRDE("RawImageData::getDataUncropped - X Position outside image 
requested.");
+  if ((int)y >= dim.y+mOffset.y) {
+    ThrowRDE("RawImageData::getDataUncropped - Y Position outside image 
requested.");
+  }
+
+  if (!data)
+    ThrowRDE("RawImageData::getDataUncropped - Data not yet allocated.");
+
+  return &data[y*pitch+x*bpp];
+}
+
 void RawImageData::subFrame(iPoint2D offset, iPoint2D new_size) {
   if (!new_size.isThisInside(dim - offset)) {
     printf("WARNING: RawImageData::subFrame - Attempted to create new subframe 
larger than original size. Crop skipped.\n");
@@ -120,6 +133,61 @@
   dim = new_size;
 }
 
+void RawImageData::calculateBlackAreas() {
+  int* histogram = (int*)malloc(4*65536*sizeof(int));
+  memset(histogram, 0, 4*65536*sizeof(int));
+  int totalpixels = 0;
+
+  for (uint32 i = 0; i < blackAreas.size(); i++) {
+    BlackArea area = blackAreas[i];
+    /* Process horizontal area */
+    if (!area.isVertical) {
+      for (uint32 y = area.offset; y < area.offset+area.size; y++) {
+        ushort16 *pixel = (ushort16*)getDataUncropped(mOffset.x, y);
+        int* localhist = &histogram[(y&1)*(65536*2)];
+        for (int x = mOffset.x; x < dim.x; x++) {
+          localhist[((x&1)<<16) + *pixel]++;
+        }
+      }
+      totalpixels += area.size * dim.x;
+    }
+
+    /* Process vertical area */
+    if (area.isVertical) {
+      for (int y = mOffset.y; y < dim.y; y++) {
+        ushort16 *pixel = (ushort16*)getDataUncropped(area.offset, y);
+        int* localhist = &histogram[(y&1)*(65536*2)];
+        for (uint32 x = area.offset; x < area.size; x++) {
+          localhist[((x&1)<<16) + *pixel]++;
+        }
+      }
+    }
+    totalpixels += area.size * dim.y;
+  }
+
+  if (!totalpixels) {
+    for (int i = 0 ; i < 4; i++)
+      blackLevelSeparate[i] = blackLevel;
+    return;
+  }
+
+  /* Calculate median value of black areas for each component */
+  /* Adjust the number of total pixels so it is the same as the median of each 
histogram */
+  totalpixels /= 4*2;
+
+  for (int i = 0 ; i < 4; i++) {
+    int* localhist = &histogram[i*65536];
+    int acc_pixels = localhist[0];
+    int pixel_value = 0;
+    while (acc_pixels <= totalpixels && pixel_value < 65535) {
+      pixel_value++;
+      acc_pixels += localhist[pixel_value];
+    }
+    blackLevelSeparate[i] = pixel_value;
+  }
+  free(histogram);
+}
+
 void RawImageData::scaleBlackWhite() {
   const int skipBorder = 150;
   int gw = (dim.x - skipBorder) * cpp;
@@ -141,20 +209,13 @@
     printf("Estimated black:%d, Estimated white: %d\n", blackLevel, 
whitePoint);
   }
 
-  if (whitePoint <= blackLevel) {
-    printf("WARNING: RawImageData::scaleBlackWhite - Unable to estimate 
Black/White level, skipping scaling.\n");
-    return;
-  }
-
-  float f = 65535.0f / (float)(whitePoint - blackLevel);
-  if (whitePoint == 65535 && blackLevel == 0)
-    return;
-  scaleValues(f);
+  calculateBlackAreas();
+  scaleValues();
 }
 
 #if _MSC_VER > 1399 || defined(__SSE2__)
 
-void RawImageData::scaleValues(float f) {
+void RawImageData::scaleValues() {
   bool use_sse2;
 #ifdef _MSC_VER 
   int info[4];
@@ -165,26 +226,47 @@
 #endif
 
   // Check SSE2
-  if (f >= 0.0f && use_sse2) {
+  if (use_sse2) {
 
-    __m128i ssescale;
-    __m128i ssesub;
     __m128i sseround;
     __m128i ssesub2;
     __m128i ssesign;
+    uint32* sub_mul = (uint32*)_aligned_malloc(16*4*2, 16);
     uint32 gw = pitch / 16;
-    uint32 i = (int)(1024.0f * f);  // 10 bit fraction
-    i |= i << 16;
-    uint32 b = blackLevel | (blackLevel << 16);
+    // 10 bit fraction
+    uint32 mul = (int)(1024.0f * 65535.0f / (float)(whitePoint - 
blackLevelSeparate[mOffset.x&1]));  
+    mul |= ((int)(1024.0f * 65535.0f / (float)(whitePoint - 
blackLevelSeparate[(mOffset.x+1)&1])))<<16;
+    uint32 b = blackLevelSeparate[mOffset.x&1] | 
(blackLevelSeparate[(mOffset.x+1)&1]<<16);
 
-    ssescale = _mm_set_epi32(i, i, i, i);
-    ssesub = _mm_set_epi32(b, b, b, b);
+    for (int i = 0; i< 4; i++) {
+      sub_mul[i] = b;     // Subtract even lines
+      sub_mul[4+i] = mul;   // Multiply even lines
+    }
+
+    mul = (int)(1024.0f * 65535.0f / (float)(whitePoint - 
blackLevelSeparate[2+(mOffset.x&1)]));
+    mul |= ((int)(1024.0f * 65535.0f / (float)(whitePoint - 
blackLevelSeparate[2+((mOffset.x+1)&1)])))<<16;
+    b = blackLevelSeparate[2+(mOffset.x&1)] | 
(blackLevelSeparate[2+((mOffset.x+1)&1)]<<16);
+
+    for (int i = 0; i< 4; i++) {
+      sub_mul[8+i] = b;   // Subtract odd lines
+      sub_mul[12+i] = mul;  // Multiply odd lines
+    }
+
     sseround = _mm_set_epi32(512, 512, 512, 512);
     ssesub2 = _mm_set_epi32(32768, 32768, 32768, 32768);
     ssesign = _mm_set_epi32(0x80008000, 0x80008000, 0x80008000, 0x80008000);
 
     for (int y = 0; y < dim.y; y++) {
       __m128i* pixel = (__m128i*) & data[(mOffset.y+y)*pitch];
+      __m128i ssescale, ssesub;
+      if (((y+mOffset.y)&1) == 0) { 
+        ssesub = _mm_load_si128((__m128i*)&sub_mul[0]);
+        ssescale = _mm_load_si128((__m128i*)&sub_mul[4]);
+      } else {
+        ssesub = _mm_load_si128((__m128i*)&sub_mul[8]);
+        ssescale = _mm_load_si128((__m128i*)&sub_mul[12]);
+      }
+
       for (uint32 x = 0 ; x < gw; x++) {
         __m128i pix_high;
         __m128i temp;
@@ -213,14 +295,27 @@
         pixel++;
       }
     }
+    _aligned_free(sub_mul);
   } else {
     // Not SSE2
     int gw = dim.x * cpp;
-    int scale = (int)(16384.0f * f);  // 14 bit fraction
+    int mul[4];
+    int sub[4];
+    for (int i = 0; i < 4; i++) {
+      int v = i;
+      if ((mOffset.x&1) != 0)
+        v ^= 1;
+      if ((mOffset.y&1) != 0)
+        v ^= 2;
+      mul[i] = (int)(16384.0f * 65535.0f / (float)(whitePoint - 
blackLevelSeparate[v]));
+      sub[i] = blackLevelSeparate[v];
+    }
     for (int y = 0; y < dim.y; y++) {
       ushort16 *pixel = (ushort16*)getData(0, y);
+      int *mul_local = &mul[2*(y&1)];
+      int *sub_local = &sub[2*(y&1)];
       for (int x = 0 ; x < gw; x++) {
-        pixel[x] = clampbits(((pixel[x] - blackLevel) * scale + 8192) >> 14, 
16);
+        pixel[x] = clampbits(((pixel[x] - sub_local[x&1]) * mul_local[x&1] + 
8192) >> 14, 16);
       }
     }
   }
@@ -228,13 +323,25 @@
 
 #else
 
-void RawImageData::scaleValues(float f) {
+void RawImageData::scaleValues() {
   int gw = dim.x * cpp;
-  int scale = (int)(16384.0f * f);  // 14 bit fraction
+  int mul[4];
+  int sub[4];
+  for (int i = 0; i < 4; i++) {
+    int v = i;
+    if ((mOffset.x&1) != 0)
+      v ^= 1;
+    if ((mOffset.y&1) != 0)
+      v ^= 2;
+    mul[i] = (int)(16384.0f * 65535.0f / (float)(whitePoint - 
blackLevelSeparate[v]));
+    sub[i] = blackLevelSeparate[v];
+  }
   for (int y = 0; y < dim.y; y++) {
     ushort16 *pixel = (ushort16*)getData(0, y);
+    int *mul_local = &mul[2*(y&1)];
+    int *sub_local = &sub[2*(y&1)];
     for (int x = 0 ; x < gw; x++) {
-      pixel[x] = clampbits(((pixel[x] - blackLevel) * scale + 8192) >> 14, 16);
+      pixel[x] = clampbits(((pixel[x] - sub_local[x&1]) * mul_local[x&1] + 
8192) >> 14, 16);
     }
   }
 }

Modified: RawSpeed/RawImage.h
===================================================================
--- RawSpeed/RawImage.h 2011-01-30 15:21:39 UTC (rev 321)
+++ RawSpeed/RawImage.h 2011-01-30 15:27:27 UTC (rev 322)
@@ -41,19 +41,22 @@
   virtual void destroyData();
   uchar8* getData();
   uchar8* getData(uint32 x, uint32 y);    // Not super fast, but safe. Don't 
use per pixel.
+  uchar8* getDataUncropped(uint32 x, uint32 y);
   virtual void subFrame( iPoint2D offset, iPoint2D new_size );
   void scaleBlackWhite();
   bool isCFA;
   ColorFilterArray cfa;
   int blackLevel;
+  int blackLevelSeparate[4];
   int whitePoint;
   vector<BlackArea> blackAreas;
   iPoint2D subsampling;
   bool isAllocated() {return !!data;}
-  void scaleValues(float scale);
+  void scaleValues();
 protected:
   RawImageData(void);
   RawImageData(iPoint2D dim, uint32 bpp, uint32 cpp=1);
+  void calculateBlackAreas();
   uint32 dataRefCount;
   uchar8* data;
   uint32 cpp;      // Components per pixel


_______________________________________________
Rawstudio-commit mailing list
[email protected]
http://rawstudio.org/cgi-bin/mailman/listinfo/rawstudio-commit

Reply via email to