1
/* ============================================================
3
* This file is a part of digiKam project
4
* http://www.digikam.org
7
* Description : access pixels method for lens distortion algorithm.
9
* Copyright (C) 2004-2010 by Gilles Caulier <caulier dot gilles at gmail dot com>
10
* Copyright (C) 2006-2010 by Marcel Wiesweg <marcel dot wiesweg at gmx dot de>
12
* This program is free software; you can redistribute it
13
* and/or modify it under the terms of the GNU General
14
* Public License as published by the Free Software Foundation;
15
* either version 2, or (at your option)
18
* This program is distributed in the hope that it will be useful,
19
* but WITHOUT ANY WARRANTY; without even the implied warranty of
20
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21
* GNU General Public License for more details.
23
* ============================================================ */
25
#include "pixelaccess.h"
36
PixelAccess::PixelAccess(DImg* srcImage)
40
m_width = PixelAccessWidth;
41
m_height = PixelAccessHeight;
43
m_depth = m_image->bytesDepth();
44
m_imageWidth = m_image->width();
45
m_imageHeight = m_image->height();
46
m_sixteenBit = m_image->sixteenBit();
48
for ( int i = 0 ; i < PixelAccessRegions ; ++i )
50
m_buffer[i] = new DImg(m_image->copy(0, 0, m_width, m_height));
53
m_tileMaxX[i] = m_width - 2;
55
m_tileMaxY[i] = m_height - 2;
59
PixelAccess::~PixelAccess()
61
for ( int i = 0 ; i < PixelAccessRegions ; ++i )
67
uchar* PixelAccess::pixelAccessAddress(int i, int j)
69
return m_buffer[0]->bits() + m_depth * (m_width * (j + 1 - m_tileMinY[0]) + (i + 1 - m_tileMinX[0]));
72
// Swap region[n] with region[0].
73
void PixelAccess::pixelAccessSelectRegion(int n)
85
for ( i = n ; i > 0 ; --i)
87
m_buffer[i] = m_buffer[i-1];
88
m_tileMinX[i] = m_tileMinX[i-1];
89
m_tileMaxX[i] = m_tileMaxX[i-1];
90
m_tileMinY[i] = m_tileMinY[i-1];
91
m_tileMaxY[i] = m_tileMaxY[i-1];
101
// Buffer[0] is cleared, should start at [i, j], fill rows that overlap image.
102
void PixelAccess::pixelAccessDoEdge(int i, int j)
104
int lineStart, lineEnd;
105
int rowStart, rowEnd;
116
lineEnd = i + m_width;
118
if (lineEnd > m_imageWidth)
120
lineEnd = m_imageWidth;
123
lineWidth = lineEnd - lineStart;
125
if ( lineStart >= lineEnd )
137
rowEnd = j + m_height;
139
if (rowEnd > m_imageHeight)
141
rowEnd = m_imageHeight;
144
for ( int y = rowStart ; y < rowEnd ; ++y )
146
line = pixelAccessAddress(lineStart, y);
147
memcpy(line, m_image->scanLine(y) + lineStart * m_depth, lineWidth * m_depth);
151
// Moves buffer[0] so that [x, y] is inside it.
152
void PixelAccess::pixelAccessReposition(int xInt, int yInt)
154
int newStartX = xInt - PixelAccessXOffset;
155
int newStartY = yInt - PixelAccessYOffset;
157
m_tileMinX[0] = newStartX + 1;
158
m_tileMaxX[0] = newStartX + m_width - 2;
159
m_tileMinY[0] = newStartY + 1;
160
m_tileMaxY[0] = newStartY + m_height - 2;
163
if ( (newStartX < 0) || ((newStartX + m_width) >= m_imageWidth) ||
164
(newStartY < 0) || ((newStartY + m_height) >= m_imageHeight) )
166
// some data is off edge of image
168
m_buffer[0]->fill(DColor(0,0,0,0, m_sixteenBit));
170
// This could probably be done by bitBltImage but I did not figure out how,
171
// so leave the working code here. And no, it is not this:
172
//m_buffer[0]->bitBltImage(m_image, newStartX, newStartY, m_width, m_height, 0, 0);
174
if ( ((newStartX + m_width) < 0) || (newStartX >= m_imageWidth) ||
175
((newStartY + m_height) < 0) || (newStartY >= m_imageHeight) )
177
// totally outside, just leave it.
181
pixelAccessDoEdge(newStartX, newStartY);
186
m_buffer[0]->bitBltImage(m_image, newStartX, newStartY, m_width, m_height, 0, 0);
190
void PixelAccess::pixelAccessGetCubic(double srcX, double srcY, double brighten, uchar* dst)
196
xInt = (int)floor(srcX);
198
yInt = (int)floor(srcY);
201
// We need 4x4 pixels, xInt-1 to xInt+2 horz, yInt-1 to yInt+2 vert
202
// they're probably in the last place we looked...
204
if ((xInt >= m_tileMinX[0]) && (xInt < m_tileMaxX[0]) &&
205
(yInt >= m_tileMinY[0]) && (yInt < m_tileMaxY[0]) )
207
corner = pixelAccessAddress(xInt - 1, yInt - 1);
208
cubicInterpolate(corner, m_depth * m_width, dst, m_sixteenBit, dx, dy, brighten);
212
// Or maybe it was a while back...
214
for ( int i = 1 ; i < PixelAccessRegions ; ++i)
216
if ((xInt >= m_tileMinX[i]) && (xInt < m_tileMaxX[i]) &&
217
(yInt >= m_tileMinY[i]) && (yInt < m_tileMaxY[i]) )
219
// Check here first next time
221
pixelAccessSelectRegion(i);
222
corner = pixelAccessAddress(xInt - 1, yInt - 1);
223
cubicInterpolate(corner, m_depth * m_width, dst, m_sixteenBit, dx, dy, brighten);
228
// Nope, recycle an old region.
230
pixelAccessSelectRegion(PixelAccessRegions - 1);
231
pixelAccessReposition(xInt, yInt);
233
corner = pixelAccessAddress(xInt - 1, yInt - 1);
234
cubicInterpolate(corner, m_depth * m_width, dst, m_sixteenBit, dx, dy, brighten);
238
* Catmull-Rom cubic interpolation
240
* equally spaced points p0, p1, p2, p3
241
* interpolate 0 <= u < 1 between p1 and p2
243
* (1 u u^2 u^3) ( 0.0 1.0 0.0 0.0 ) (p0)
244
* ( -0.5 0.0 0.5 0.0 ) (p1)
245
* ( 1.0 -2.5 2.0 -0.5 ) (p2)
246
* ( -0.5 1.5 -1.5 0.5 ) (p3)
249
void PixelAccess::cubicInterpolate(uchar* src, int rowStride, uchar* dst,
250
bool sixteenBit, double dx, double dy, double brighten)
252
float um1, u, up1, up2;
253
float vm1, v, vp1, vp2;
255
const int numberOfComponents = 4;
256
float verts[4 * numberOfComponents];
258
um1 = ((-0.5 * dx + 1.0) * dx - 0.5) * dx;
259
u = (1.5 * dx - 2.5) * dx * dx + 1.0;
260
up1 = ((-1.5 * dx + 2.0) * dx + 0.5) * dx;
261
up2 = (0.5 * dx - 0.5) * dx * dx;
263
vm1 = ((-0.5 * dy + 1.0) * dy - 0.5) * dy;
264
v = (1.5 * dy - 2.5) * dy * dy + 1.0;
265
vp1 = ((-1.5 * dy + 2.0) * dy + 0.5) * dy;
266
vp2 = (0.5 * dy - 0.5) * dy * dy;
270
unsigned short* src16 = (unsigned short*)src;
271
unsigned short* dst16 = (unsigned short*)dst;
273
// for each component, read the values of 4 pixels into array
275
for (c = 0 ; c < 4 * numberOfComponents ; ++c)
277
verts[c] = vm1 * src16[c] + v * src16[c+rowStride] + vp1 * src16[c+rowStride*2] + vp2 * src16[c+rowStride*3];
280
// for each component, compute resulting value from array
282
for (c = 0 ; c < numberOfComponents ; ++c)
285
result = um1 * verts[c] + u * verts[c+numberOfComponents]
286
+ up1 * verts[c+numberOfComponents*2] + up2 * verts[c+numberOfComponents*3];
293
else if (result > 65535.0)
299
dst16[c] = (uint)result;
305
for (c = 0 ; c < 4 * numberOfComponents ; ++c)
307
verts[c] = vm1 * src[c] + v * src[c+rowStride] + vp1 * src[c+rowStride*2] + vp2 * src[c+rowStride*3];
310
for (c = 0 ; c < numberOfComponents ; ++c)
313
result = um1 * verts[c] + u * verts[c+numberOfComponents]
314
+ up1 * verts[c+numberOfComponents*2] + up2 * verts[c+numberOfComponents*3];
321
else if (result > 255.0)
327
dst[c] = (uint)result;
333
} // namespace Digikam