summaryrefslogtreecommitdiffstats
path: root/src/imageplugins/lensdistortion/pixelaccess.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/imageplugins/lensdistortion/pixelaccess.cpp')
-rw-r--r--src/imageplugins/lensdistortion/pixelaccess.cpp314
1 files changed, 314 insertions, 0 deletions
diff --git a/src/imageplugins/lensdistortion/pixelaccess.cpp b/src/imageplugins/lensdistortion/pixelaccess.cpp
new file mode 100644
index 00000000..a6041f94
--- /dev/null
+++ b/src/imageplugins/lensdistortion/pixelaccess.cpp
@@ -0,0 +1,314 @@
+/* ============================================================
+ *
+ * This file is a part of digiKam project
+ * http://www.digikam.org
+ *
+ * Date : 2004-12-27
+ * Description : acess pixels method for lens distortion algorithm.
+ *
+ * Copyright (C) 2004-2007 by Gilles Caulier <caulier dot gilles at gmail dot com>
+ * Copyright (C) 2006-2007 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
+ *
+ * This program 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 2, or (at your option)
+ * any later version.
+ *
+ * This program 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.
+ *
+ * ============================================================ */
+
+// C++ includes.
+
+#include <cstring>
+#include <cmath>
+#include <cstdlib>
+
+// Local includes.
+
+#include "ddebug.h"
+#include "pixelaccess.h"
+
+namespace DigikamLensDistortionImagesPlugin
+{
+
+PixelAccess::PixelAccess(Digikam::DImg *srcImage)
+{
+ m_image = srcImage;
+
+ m_width = PixelAccessWidth;
+ m_height = PixelAccessHeight;
+
+ m_depth = m_image->bytesDepth();
+ m_imageWidth = m_image->width();
+ m_imageHeight = m_image->height();
+ m_sixteenBit = m_image->sixteenBit();
+
+ for ( int i = 0 ; i < PixelAccessRegions ; i++ )
+ {
+ m_buffer[i] = new Digikam::DImg(m_image->copy(0, 0, m_width, m_height));
+
+ m_tileMinX[i] = 1;
+ m_tileMaxX[i] = m_width - 2;
+ m_tileMinY[i] = 1;
+ m_tileMaxY[i] = m_height - 2;
+ }
+}
+
+PixelAccess::~PixelAccess()
+{
+ for( int i = 0 ; i < PixelAccessRegions ; i++ )
+ delete m_buffer[i];
+}
+
+uchar* PixelAccess::pixelAccessAddress(int i, int j)
+{
+ return m_buffer[0]->bits() + m_depth * (m_width * (j + 1 - m_tileMinY[0]) + (i + 1 - m_tileMinX[0]));
+}
+
+// Swap region[n] with region[0].
+void PixelAccess::pixelAccessSelectRegion(int n)
+{
+ Digikam::DImg *temp;
+ int a, b, c, d;
+ int i;
+
+ temp = m_buffer[n];
+ a = m_tileMinX[n];
+ b = m_tileMaxX[n];
+ c = m_tileMinY[n];
+ d = m_tileMaxY[n];
+
+ for( i = n ; i > 0 ; i--)
+ {
+ m_buffer[i] = m_buffer[i-1];
+ m_tileMinX[i] = m_tileMinX[i-1];
+ m_tileMaxX[i] = m_tileMaxX[i-1];
+ m_tileMinY[i] = m_tileMinY[i-1];
+ m_tileMaxY[i] = m_tileMaxY[i-1];
+ }
+
+ m_buffer[0] = temp;
+ m_tileMinX[0] = a;
+ m_tileMaxX[0] = b;
+ m_tileMinY[0] = c;
+ m_tileMaxY[0] = d;
+}
+
+// Buffer[0] is cleared, should start at [i, j], fill rows that overlap image.
+void PixelAccess::pixelAccessDoEdge(int i, int j)
+{
+ int lineStart, lineEnd;
+ int rowStart, rowEnd;
+ int lineWidth;
+ uchar* line;
+
+ lineStart = i;
+ if (lineStart < 0) lineStart = 0;
+ lineEnd = i + m_width;
+ if (lineEnd > m_imageWidth) lineEnd = m_imageWidth;
+ lineWidth = lineEnd - lineStart;
+
+ if( lineStart >= lineEnd )
+ return;
+
+ rowStart = j;
+ if (rowStart < 0) rowStart = 0;
+ rowEnd = j + m_height;
+ if (rowEnd > m_imageHeight) rowEnd = m_imageHeight;
+
+ for( int y = rowStart ; y < rowEnd ; y++ )
+ {
+ line = pixelAccessAddress(lineStart, y);
+ memcpy(line, m_image->scanLine(y) + lineStart * m_depth, lineWidth * m_depth);
+ }
+}
+
+// Moves buffer[0] so that [x, y] is inside it.
+void PixelAccess::pixelAccessReposition(int xInt, int yInt)
+{
+ int newStartX = xInt - PixelAccessXOffset;
+ int newStartY = yInt - PixelAccessYOffset;
+
+ m_tileMinX[0] = newStartX + 1;
+ m_tileMaxX[0] = newStartX + m_width - 2;
+ m_tileMinY[0] = newStartY + 1;
+ m_tileMaxY[0] = newStartY + m_height - 2;
+
+
+ if ( (newStartX < 0) || ((newStartX + m_width) >= m_imageWidth) ||
+ (newStartY < 0) || ((newStartY + m_height) >= m_imageHeight) )
+ {
+ // some data is off edge of image
+
+ m_buffer[0]->fill(Digikam::DColor(0,0,0,0, m_sixteenBit));
+
+ // This could probably be done by bitBltImage but I did not figure out how,
+ // so leave the working code here. And no, it is not this:
+ //m_buffer[0]->bitBltImage(m_image, newStartX, newStartY, m_width, m_height, 0, 0);
+
+ if ( ((newStartX + m_width) < 0) || (newStartX >= m_imageWidth) ||
+ ((newStartY + m_height) < 0) || (newStartY >= m_imageHeight) )
+ {
+ // totally outside, just leave it.
+ }
+ else
+ {
+ pixelAccessDoEdge(newStartX, newStartY);
+ }
+ }
+ else
+ {
+ m_buffer[0]->bitBltImage(m_image, newStartX, newStartY, m_width, m_height, 0, 0);
+ }
+}
+
+void PixelAccess::pixelAccessGetCubic(double srcX, double srcY, double brighten, uchar* dst)
+{
+ int xInt, yInt;
+ double dx, dy;
+ uchar *corner;
+
+ xInt = (int)floor(srcX);
+ dx = srcX - xInt;
+ yInt = (int)floor(srcY);
+ dy = srcY - yInt;
+
+ // We need 4x4 pixels, xInt-1 to xInt+2 horz, yInt-1 to yInt+2 vert
+ // they're probably in the last place we looked...
+
+ if ((xInt >= m_tileMinX[0]) && (xInt < m_tileMaxX[0]) &&
+ (yInt >= m_tileMinY[0]) && (yInt < m_tileMaxY[0]) )
+ {
+ corner = pixelAccessAddress(xInt - 1, yInt - 1);
+ cubicInterpolate(corner, m_depth * m_width, dst, m_sixteenBit, dx, dy, brighten);
+ return;
+ }
+
+ // Or maybe it was a while back...
+
+ for ( int i = 1 ; i < PixelAccessRegions ; i++)
+ {
+ if ((xInt >= m_tileMinX[i]) && (xInt < m_tileMaxX[i]) &&
+ (yInt >= m_tileMinY[i]) && (yInt < m_tileMaxY[i]) )
+ {
+ // Check here first next time
+
+ pixelAccessSelectRegion(i);
+ corner = pixelAccessAddress(xInt - 1, yInt - 1);
+ cubicInterpolate(corner, m_depth * m_width, dst, m_sixteenBit, dx, dy, brighten);
+ return;
+ }
+ }
+
+ // Nope, recycle an old region.
+
+ pixelAccessSelectRegion(PixelAccessRegions - 1);
+ pixelAccessReposition(xInt, yInt);
+
+ corner = pixelAccessAddress(xInt - 1, yInt - 1);
+ cubicInterpolate(corner, m_depth * m_width, dst, m_sixteenBit, dx, dy, brighten);
+}
+
+/*
+ * Catmull-Rom cubic interpolation
+ *
+ * equally spaced points p0, p1, p2, p3
+ * interpolate 0 <= u < 1 between p1 and p2
+ *
+ * (1 u u^2 u^3) ( 0.0 1.0 0.0 0.0 ) (p0)
+ * ( -0.5 0.0 0.5 0.0 ) (p1)
+ * ( 1.0 -2.5 2.0 -0.5 ) (p2)
+ * ( -0.5 1.5 -1.5 0.5 ) (p3)
+ *
+ */
+void PixelAccess::cubicInterpolate(uchar* src, int rowStride, uchar* dst,
+ bool sixteenBit, double dx, double dy, double brighten)
+{
+ float um1, u, up1, up2;
+ float vm1, v, vp1, vp2;
+ int c;
+ const int numberOfComponents = 4;
+ float verts[4 * numberOfComponents];
+
+ um1 = ((-0.5 * dx + 1.0) * dx - 0.5) * dx;
+ u = (1.5 * dx - 2.5) * dx * dx + 1.0;
+ up1 = ((-1.5 * dx + 2.0) * dx + 0.5) * dx;
+ up2 = (0.5 * dx - 0.5) * dx * dx;
+
+ vm1 = ((-0.5 * dy + 1.0) * dy - 0.5) * dy;
+ v = (1.5 * dy - 2.5) * dy * dy + 1.0;
+ vp1 = ((-1.5 * dy + 2.0) * dy + 0.5) * dy;
+ vp2 = (0.5 * dy - 0.5) * dy * dy;
+
+ if (sixteenBit)
+ {
+ unsigned short *src16 = (unsigned short *)src;
+ unsigned short *dst16 = (unsigned short *)dst;
+
+ // for each component, read the values of 4 pixels into array
+
+ for (c = 0 ; c < 4 * numberOfComponents ; c++)
+ {
+ verts[c] = vm1 * src16[c] + v * src16[c+rowStride] + vp1 * src16[c+rowStride*2] + vp2 * src16[c+rowStride*3];
+ }
+
+ // for each component, compute resulting value from array
+
+ for (c = 0 ; c < numberOfComponents ; c++)
+ {
+ float result;
+ result = um1 * verts[c] + u * verts[c+numberOfComponents]
+ + up1 * verts[c+numberOfComponents*2] + up2 * verts[c+numberOfComponents*3];
+ result *= brighten;
+
+ if (result < 0.0)
+ {
+ dst16[c] = 0;
+ }
+ else if (result > 65535.0)
+ {
+ dst16[c] = 65535;
+ }
+ else
+ {
+ dst16[c] = (uint)result;
+ }
+ }
+ }
+ else
+ {
+ for (c = 0 ; c < 4 * numberOfComponents ; c++)
+ {
+ verts[c] = vm1 * src[c] + v * src[c+rowStride] + vp1 * src[c+rowStride*2] + vp2 * src[c+rowStride*3];
+ }
+
+ for (c = 0 ; c < numberOfComponents ; c++)
+ {
+ float result;
+ result = um1 * verts[c] + u * verts[c+numberOfComponents]
+ + up1 * verts[c+numberOfComponents*2] + up2 * verts[c+numberOfComponents*3];
+ result *= brighten;
+
+ if (result < 0.0)
+ {
+ dst[c] = 0;
+ }
+ else if (result > 255.0)
+ {
+ dst[c] = 255;
+ }
+ else
+ {
+ dst[c] = (uint)result;
+ }
+ }
+ }
+}
+
+} // NameSpace DigikamLensDistortionImagesPlugin
+