kaleidoscope  1.4.0
Functions
kaleidoscope.c File Reference
#include "kaleidoscope.h"
#include "kaleidoscope-config.h"
#include <assert.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

Go to the source code of this file.

Functions

void getKaleidoscopeVersion (int *major, int *minor, int *patch)
 Get the Kaleidoscope Library version as integer. More...
 
char * getKaleidoscopeVersionString ()
 Get the Kaleidoscope Library version as string. More...
 
char * getKaleidoscopeLibraryInfo ()
 Get the Kaleidoscope Library info as string. More...
 
int compare (const void *lhsPtr, const void *rhsPtr)
 
void interpolate (TransformationInfo *dataOut, TransformationInfo *dataIn, int width, int height)
 A simple interpolation function. Internal use only. More...
 
void rotatePoints (TransformationInfo *outData, TransformationInfo *orgData, int width, int height, double angle)
 Rotates the coordinates of sliced triangle. Internal use only. More...
 
int sliceTriangle (TransformationInfo *transformPtr, int width, int height, int n, double scaleDown)
 Slices a suitable triangle from image. More...
 
int initKaleidoscope (KaleidoscopeHandle *handler, int n, int width, int height, int nComponents, double scaleDown)
 Initializes kaleidoscope handler. More...
 
void processKaleidoscope (KaleidoscopeHandle *handler, double k, unsigned char *imgIn, unsigned char *imgOut)
 Applies kaleidoscope effect to image. More...
 
void deInitKaleidoscope (KaleidoscopeHandle *handler)
 Deinitializes kaleidoscope handler. More...
 

Function Documentation

◆ compare()

int compare ( const void *  lhsPtr,
const void *  rhsPtr 
)

Definition at line 56 of file kaleidoscope.c.

57 {
58  TransformationInfo *lhs = (TransformationInfo *)lhsPtr;
59  TransformationInfo *rhs = (TransformationInfo *)rhsPtr;
60  return lhs->dstOffset - rhs->dstOffset;
61 }
Data struct for transformation information.
Definition: kaleidoscope.h:18
unsigned long long dstOffset
Offset from destination image.
Definition: kaleidoscope.h:26

◆ deInitKaleidoscope()

void deInitKaleidoscope ( KaleidoscopeHandle handler)

Deinitializes kaleidoscope handler.

Parameters
[in]handlerKaleidoscope effect handler

Definition at line 304 of file kaleidoscope.c.

305 {
306  if (handler)
307  free(handler->pTransferFunc);
308 }
struct TransformationInfo_t * pTransferFunc
Transformation info.
Definition: kaleidoscope.h:44

◆ getKaleidoscopeLibraryInfo()

char* getKaleidoscopeLibraryInfo ( )

Get the Kaleidoscope Library info as string.

Returns
char* Library information

Definition at line 30 of file kaleidoscope.c.

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 }

◆ getKaleidoscopeVersion()

void getKaleidoscopeVersion ( int *  major,
int *  minor,
int *  patch 
)

Get the Kaleidoscope Library version as integer.

Parameters
[in,out]majorMajor number
[in,out]minorMinor number
[in,out]patchPatch number

Definition at line 13 of file kaleidoscope.c.

14 {
15  if (major && minor && patch)
16  {
17  *major = PROJECT_MAJOR_VERSION;
18  *minor = PROJECT_MINOR_VERSION;
19  *patch = PROJECT_PATCH_VERSION;
20  }
21 }

◆ getKaleidoscopeVersionString()

char* getKaleidoscopeVersionString ( )

Get the Kaleidoscope Library version as string.

Returns
char* Library version

Definition at line 23 of file kaleidoscope.c.

24 {
25  static char info[sizeof(PROJECT_VERSION)];
26  strncpy(info, PROJECT_VERSION, sizeof(PROJECT_VERSION));
27  return info;
28 }

◆ initKaleidoscope()

int initKaleidoscope ( KaleidoscopeHandle handler,
int  n,
int  width,
int  height,
int  nComponents,
double  scaleDown 
)

Initializes kaleidoscope handler.

Parameters
[in,out]handlerKaleidoscope effect handler
[in]nNumber of images for effect
[in]widthImage width
[in]heightImage height
[in]nComponentsNumber of image components (eg 3 for RGB)
[in]scaleDownScale down ratio to shrink image. Must be between 0.0 and 1.0
Returns
int 0 on success, negative otherwise

Definition at line 199 of file kaleidoscope.c.

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 }
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
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
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
unsigned char nComponents
Number of components (eg 3 for RGB)
Definition: kaleidoscope.h:40
unsigned long long srcOffset
Offset from source image.
Definition: kaleidoscope.h:24
Point2D srcLocation
Location from source image.
Definition: kaleidoscope.h:20
Point2D dstLocation
Location to destination image.
Definition: kaleidoscope.h:22

◆ interpolate()

void interpolate ( TransformationInfo dataOut,
TransformationInfo dataIn,
int  width,
int  height 
)

A simple interpolation function. Internal use only.

Parameters
[out]dataOutOutput (interpolated) binary image
[in]dataInInput binary image
[in]widthWidth of input image
[in]heightHeight of input image

Definition at line 63 of file kaleidoscope.c.

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 }

◆ processKaleidoscope()

void processKaleidoscope ( KaleidoscopeHandle handler,
double  k,
unsigned char *  imgIn,
unsigned char *  imgOut 
)

Applies kaleidoscope effect to image.

Parameters
[in]handlerKaleidoscope effect handler
[in]kVariable to dim background. Should be between 0.0 and 1.0
[in]imgInInput image
[out]imgOutOutput image

Definition at line 288 of file kaleidoscope.c.

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 }

◆ rotatePoints()

void rotatePoints ( TransformationInfo outData,
TransformationInfo orgData,
int  width,
int  height,
double  angle 
)

Rotates the coordinates of sliced triangle. Internal use only.

Parameters
[out]outDataRotated data
[in]orgDataSliced data coordinates
[in]widthWidth of input image
[in]heightHeight of input image
[in]angleTop angle of sliced triangle

Definition at line 128 of file kaleidoscope.c.

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 }

◆ sliceTriangle()

int sliceTriangle ( TransformationInfo transformPtr,
int  width,
int  height,
int  n,
double  scaleDown 
)

Slices a suitable triangle from image.

Parameters
[out]transformPtrSliced triangle coordinates
[in]widthWidth of input image
[in]heightHeight of input image
[in]nNumber of images for effect
[in]scaleDownScale down ratio to shrink image
Returns
int 0 on success, -1 otherwise

Definition at line 155 of file kaleidoscope.c.

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 }