kaleidoscope  1.4.0
kaleidoscope.c
Go to the documentation of this file.
1 #include "kaleidoscope.h"
2 #include "kaleidoscope-config.h"
3 
4 #ifdef WIN32
5 #define _USE_MATH_DEFINES
6 #endif
7 #include <assert.h>
8 #include <math.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 
13 void getKaleidoscopeVersion(int *major, int *minor, int *patch)
14 {
15  if (major && minor && patch)
16  {
17  *major = PROJECT_MAJOR_VERSION;
18  *minor = PROJECT_MINOR_VERSION;
19  *patch = PROJECT_PATCH_VERSION;
20  }
21 }
22 
24 {
25  static char info[sizeof(PROJECT_VERSION)];
26  strncpy(info, PROJECT_VERSION, sizeof(PROJECT_VERSION));
27  return info;
28 }
29 
31 {
32  int offset = 0;
33  static char info[125];
34 
35  strncpy(info, PROJECT_VERSION, sizeof(PROJECT_VERSION));
36  offset += sizeof(PROJECT_VERSION);
37  memset(&info[offset - 1], 32, 1);
38  strncpy(&info[offset], COMPILER_NAME, sizeof(COMPILER_NAME));
39  offset += sizeof(COMPILER_NAME);
40  memset(&info[offset - 1], 32, 1);
41  strncpy(&info[offset], COMPILER_VERSION, sizeof(COMPILER_VERSION));
42  offset += sizeof(COMPILER_VERSION);
43  memset(&info[offset - 1], 32, 1);
44  strncpy(&info[offset], BUILD_TYPE, sizeof(BUILD_TYPE));
45  offset += sizeof(BUILD_TYPE);
46  memset(&info[offset - 1], 32, 1);
47  strncpy(&info[offset], PROJECT_BUILD_DATE, sizeof(PROJECT_BUILD_DATE));
48  offset += sizeof(PROJECT_BUILD_DATE);
49  memset(&info[offset - 1], 32, 1);
50  strncpy(&info[offset], PROJECT_BUILD_TIME, sizeof(PROJECT_BUILD_TIME));
51  // offset += sizeof(PROJECT_BUILD_TIME);
52 
53  return info;
54 }
55 
56 int compare(const void *lhsPtr, const void *rhsPtr)
57 {
58  TransformationInfo *lhs = (TransformationInfo *)lhsPtr;
59  TransformationInfo *rhs = (TransformationInfo *)rhsPtr;
60  return lhs->dstOffset - rhs->dstOffset;
61 }
62 
63 void interpolate(TransformationInfo *dataOut, TransformationInfo *dataIn, int width, int height)
64 {
65  int idx, jdx;
66 
67  // Very simple implementation of nearest neighbour interpolation
68  for (idx = 1; idx < height - 1; ++idx)
69  {
70  int heightOffset = idx * width;
71  for (jdx = 1; jdx < width - 1; ++jdx)
72  {
73  TransformationInfo *ptrIn = &dataIn[heightOffset + jdx];
74  TransformationInfo *ptrOut = &dataOut[heightOffset + jdx];
75  if (!(ptrIn->dstLocation.x) && !(ptrIn->dstLocation.y))
76  {
77  ptrOut->dstLocation.x = jdx;
78  ptrOut->dstLocation.y = idx;
79  if (((ptrIn - 1)->dstLocation.x) || ((ptrIn - 1)->dstLocation.y)) // Left
80  {
81  ptrOut->srcLocation.x = (ptrIn - 1)->srcLocation.x + 1;
82  ptrOut->srcLocation.y = (ptrIn - 1)->srcLocation.y;
83  }
84  else if (((ptrIn + 1)->dstLocation.x) || ((ptrIn + 1)->dstLocation.y)) // Right
85  {
86  ptrOut->srcLocation.x = (ptrIn + 1)->srcLocation.x - 1;
87  ptrOut->srcLocation.y = (ptrIn + 1)->srcLocation.y;
88  }
89  else if (((ptrIn - width)->dstLocation.x) || ((ptrIn - width)->dstLocation.y)) // Top
90  {
91  ptrOut->srcLocation.x = (ptrIn - width)->srcLocation.x;
92  ptrOut->srcLocation.y = (ptrIn - width)->srcLocation.y - 1;
93  }
94  else if (((ptrIn + width)->dstLocation.x) || ((ptrIn + width)->dstLocation.y)) // Bottom
95  {
96  ptrOut->srcLocation.x = (ptrIn + width)->srcLocation.x;
97  ptrOut->srcLocation.y = (ptrIn + width)->srcLocation.y + 1;
98  }
99  else if (((ptrIn - width - 1)->dstLocation.x) || ((ptrIn - width - 1)->dstLocation.y)) // Top-Left
100  {
101  ptrOut->srcLocation.x = (ptrIn - width - 1)->srcLocation.x - 1;
102  ptrOut->srcLocation.y = (ptrIn - width - 1)->srcLocation.y - 1;
103  }
104  else if (((ptrIn - width + 1)->dstLocation.x) || ((ptrIn - width + 1)->dstLocation.y)) // Top-Right
105  {
106  ptrOut->srcLocation.x = (ptrIn - width + 1)->srcLocation.x + 1;
107  ptrOut->srcLocation.y = (ptrIn - width + 1)->srcLocation.y - 1;
108  }
109  else if (((ptrIn + width - 1)->dstLocation.x) || ((ptrIn + width - 1)->dstLocation.y)) // Bottom-Left
110  {
111  ptrOut->srcLocation.x = (ptrIn + width - 1)->srcLocation.x - 1;
112  ptrOut->srcLocation.y = (ptrIn + width - 1)->srcLocation.y - 1;
113  }
114  else if (((ptrIn + width + 1)->dstLocation.x) || ((ptrIn + width + 1)->dstLocation.y)) // Bottom-Right
115  {
116  ptrOut->srcLocation.x = (ptrIn + width + 1)->srcLocation.x + 1;
117  ptrOut->srcLocation.y = (ptrIn + width + 1)->srcLocation.y + 1;
118  }
119  else
120  memset(ptrOut, 0, sizeof(TransformationInfo));
121  }
122  else
123  *ptrOut = *ptrIn;
124  }
125  }
126 }
127 
128 void rotatePoints(TransformationInfo *outData, TransformationInfo *orgData, int width, int height, double angle)
129 {
130  int idx;
131  double cosVal = cos(angle * M_PI / 180);
132  double sinVal = sin(angle * M_PI / 180);
133 
134  for (idx = 0; idx < width * height; ++idx)
135  {
136  if (orgData[idx].dstLocation.x || orgData[idx].dstLocation.y)
137  {
138  int newX = (int)round(orgData[idx].dstLocation.x * cosVal + orgData[idx].dstLocation.y * sinVal);
139  int newY = (int)round(orgData[idx].dstLocation.y * cosVal - orgData[idx].dstLocation.x * sinVal);
140 
141  // Fix origin to top left again
142  newX += (width / 2);
143  newY += (height / 2);
144 
145  if (newX <= width && newX >= 0 && newY <= height && newY >= 0)
146  {
147  outData[newY * width + newX].srcLocation = orgData[idx].srcLocation;
148  outData[newY * width + newX].dstLocation.x = newX;
149  outData[newY * width + newX].dstLocation.y = newY;
150  }
151  }
152  }
153 }
154 
155 int sliceTriangle(TransformationInfo *transformPtr, int width, int height, int n, double scaleDown)
156 {
157  int idx, jdx;
158 
159  // Variables
160  const double topAngle = 360.0 / n;
161  const double tanVal = tan(topAngle / 2.0 * M_PI / 180.0); // tan(topAngle / 2) in radians
162  const int triangleHeight = (int)fmin(round(width / (2.0 * tanVal)), height - 1);
163  const int heightStart = (height - triangleHeight) / 2;
164  const int heightEnd = (height + triangleHeight) / 2;
165  const int scaleDownOffset = (int)(height * scaleDown / 2);
166 
167  // Ensure limits within image
168  assert(heightStart >= 0);
169  assert(heightStart <= height);
170  assert(heightEnd >= 0);
171  assert(heightEnd <= height);
172 
173  for (idx = heightStart; idx < heightEnd; ++idx)
174  {
175  const int currentBaseLength = (int)((idx - heightStart) * tanVal);
176 
177  const int widthStart = (width / 2 - currentBaseLength);
178  const int widthEnd = (width / 2 + currentBaseLength);
179 
180  // Ensure limits within image
181  if (widthStart < 0 || widthStart > width || widthEnd < 0 || widthEnd > width)
182  continue;
183 
184  TransformationInfo *ptr = &transformPtr[idx * width];
185  for (jdx = widthStart; jdx <= widthEnd; ++jdx)
186  {
187  ptr[jdx].srcLocation.x = jdx;
188  ptr[jdx].srcLocation.y = idx;
189 
190  // Calculate coordinates respect to center to prepare rotating
191  ptr[jdx].dstLocation.x = (int)((jdx - width / 2) * scaleDown);
192  ptr[jdx].dstLocation.y = (int)((idx - heightStart - height / 2) * scaleDown + scaleDownOffset);
193  }
194  }
195 
196  return EXIT_SUCCESS;
197 }
198 
199 int initKaleidoscope(KaleidoscopeHandle *handler, int n, int width, int height, int nComponents, double scaleDown)
200 {
201  int idx, jdx;
202 
203  int retval = EXIT_FAILURE;
204  const int nPixels = width * height;
205  TransformationInfo *buffPtr1 = NULL, *buffPtr2 = NULL;
206 
207  // Check parameters
208  if (handler == NULL || n <= 2 || width <= 0 || height <= 0 || nComponents <= 0 || scaleDown <= 0.0 ||
209  scaleDown >= 1.0)
210  return EXIT_FAILURE;
211 
212  assert(handler);
213  assert(n > 2);
214  assert(width > 0);
215  assert(height > 0);
216  assert(nComponents > 0);
217  assert(scaleDown > 0.0);
218  assert(scaleDown < 1.0);
219 
220  handler->width = width;
221  handler->height = height;
222  handler->nComponents = nComponents;
223 
224  buffPtr1 = (TransformationInfo *)calloc(nPixels, sizeof(TransformationInfo));
225  buffPtr2 = (TransformationInfo *)calloc(nPixels, sizeof(TransformationInfo));
226  if (!buffPtr1 || !buffPtr2)
227  goto cleanup;
228 
229  if (sliceTriangle(buffPtr1, width, height, n, scaleDown))
230  goto cleanup;
231 
232  // Rotate all points and fix origin to left top
233  for (idx = 0; idx < n; ++idx)
234  {
235  double rotationAngle = idx * (360.0 / n);
236  rotatePoints(buffPtr2, buffPtr1, width, height, rotationAngle);
237  }
238 
239  // Fill rotation artifacts
240  memset(buffPtr1, 0, sizeof(TransformationInfo) * width * height);
241  interpolate(buffPtr1, buffPtr2, width, height);
242 
243  // Remove zeros and set to points for handler
244  handler->nPoints = 0;
245  for (idx = 0; idx < nPixels; ++idx)
246  {
247  TransformationInfo *ptr = &buffPtr1[idx];
248  if (!(ptr->srcLocation.x) || !(ptr->srcLocation.y))
249  continue;
250 
251  buffPtr1[handler->nPoints] = *ptr;
252  buffPtr1[handler->nPoints].srcOffset =
253  ptr->srcLocation.x * nComponents + ptr->srcLocation.y * width * nComponents;
254  buffPtr1[handler->nPoints].dstOffset =
255  ptr->dstLocation.x * nComponents + ptr->dstLocation.y * width * nComponents;
256  ++(handler->nPoints);
257  }
258 
259  // Sort
260  qsort(buffPtr1, handler->nPoints, sizeof(TransformationInfo), compare);
261 
262  // Deduplicate
263  jdx = 0;
264  for (idx = 1; idx < handler->nPoints; ++idx)
265  {
266  if (compare(&buffPtr1[jdx], &buffPtr1[idx]))
267  {
268  buffPtr1[jdx] = buffPtr1[idx];
269  ++jdx;
270  }
271  }
272  handler->nPoints = jdx;
273 
274  handler->pTransferFunc = (TransformationInfo *)malloc(handler->nPoints * sizeof(TransformationInfo));
275  memcpy(handler->pTransferFunc, buffPtr1, handler->nPoints * sizeof(TransformationInfo));
276  retval = EXIT_SUCCESS;
277 
278 cleanup:
279  free(buffPtr1);
280  free(buffPtr2);
281 
282  if (retval == EXIT_FAILURE)
283  free(handler->pTransferFunc);
284 
285  return retval;
286 }
287 
288 void processKaleidoscope(KaleidoscopeHandle *handler, double k, unsigned char *imgIn, unsigned char *imgOut)
289 {
290  long long idx;
291  const long long nComponents = handler->nComponents;
292  const long long nPixels = (long long)handler->width * handler->height * handler->nComponents;
293 
294  unsigned char *srcPtr = imgIn;
295  unsigned char *destPtr = imgOut;
296  TransformationInfo *ptrTransform = &(handler->pTransferFunc[0]);
297 
298  for (idx = 0; idx < nPixels; ++idx, ++destPtr, ++srcPtr) // Dim image
299  *destPtr = (unsigned char)((*srcPtr) * k);
300  for (idx = 0; idx < handler->nPoints; ++idx, ++ptrTransform) // Merge
301  memcpy(&(imgOut[ptrTransform->dstOffset]), &(imgIn[ptrTransform->srcOffset]), nComponents);
302 }
303 
305 {
306  if (handler)
307  free(handler->pTransferFunc);
308 }
void getKaleidoscopeVersion(int *major, int *minor, int *patch)
Get the Kaleidoscope Library version as integer.
Definition: kaleidoscope.c:13
char * getKaleidoscopeLibraryInfo()
Get the Kaleidoscope Library info as string.
Definition: kaleidoscope.c:30
int initKaleidoscope(KaleidoscopeHandle *handler, int n, int width, int height, int nComponents, double scaleDown)
Initializes kaleidoscope handler.
Definition: kaleidoscope.c:199
char * getKaleidoscopeVersionString()
Get the Kaleidoscope Library version as string.
Definition: kaleidoscope.c:23
void interpolate(TransformationInfo *dataOut, TransformationInfo *dataIn, int width, int height)
A simple interpolation function. Internal use only.
Definition: kaleidoscope.c:63
void rotatePoints(TransformationInfo *outData, TransformationInfo *orgData, int width, int height, double angle)
Rotates the coordinates of sliced triangle. Internal use only.
Definition: kaleidoscope.c:128
void processKaleidoscope(KaleidoscopeHandle *handler, double k, unsigned char *imgIn, unsigned char *imgOut)
Applies kaleidoscope effect to image.
Definition: kaleidoscope.c:288
int compare(const void *lhsPtr, const void *rhsPtr)
Definition: kaleidoscope.c:56
int sliceTriangle(TransformationInfo *transformPtr, int width, int height, int n, double scaleDown)
Slices a suitable triangle from image.
Definition: kaleidoscope.c:155
void deInitKaleidoscope(KaleidoscopeHandle *handler)
Deinitializes kaleidoscope handler.
Definition: kaleidoscope.c:304
Struct for kaleidoscope effect generator.
Definition: kaleidoscope.h:34
int height
Image height.
Definition: kaleidoscope.h:38
int width
Image width.
Definition: kaleidoscope.h:36
long long nPoints
Total number of points of transfer function.
Definition: kaleidoscope.h:42
struct TransformationInfo_t * pTransferFunc
Transformation info.
Definition: kaleidoscope.h:44
unsigned char nComponents
Number of components (eg 3 for RGB)
Definition: kaleidoscope.h:40
Data struct for transformation information.
Definition: kaleidoscope.h:18
unsigned long long srcOffset
Offset from source image.
Definition: kaleidoscope.h:24
unsigned long long dstOffset
Offset from destination image.
Definition: kaleidoscope.h:26
Point2D srcLocation
Location from source image.
Definition: kaleidoscope.h:20
Point2D dstLocation
Location to destination image.
Definition: kaleidoscope.h:22