kaleidoscope 1.4.0
 
Loading...
Searching...
No Matches
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>
Include dependency graph for kaleidoscope.c:

Go to the source code of this file.

Functions

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

Function Documentation

◆ compare()

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

Definition at line 55 of file kaleidoscope.c.

56{
57 const TransformationInfo *lhs = (const TransformationInfo *)lhsPtr;
58 const TransformationInfo *rhs = (const TransformationInfo *)rhsPtr;
59 return (int)(lhs->dstOffset - rhs->dstOffset);
60}
Data struct for transformation information.
unsigned long long dstOffset
Offset from destination image.
Here is the caller graph for this function:

◆ deInitKaleidoscope()

void deInitKaleidoscope ( KaleidoscopeHandle * handler)

Deinitializes kaleidoscope handler.

Parameters
[in]handlerKaleidoscope effect handler

Definition at line 314 of file kaleidoscope.c.

315{
316 if (handler)
317 free(handler->pTransferFunc);
318}
struct TransformationInfo_t * pTransferFunc
Transformation info.
Here is the caller graph for this function:

◆ 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
52 return info;
53}
Here is the caller graph for this function:

◆ 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 197 of file kaleidoscope.c.

198{
199 int jdx;
200
201 int retval = EXIT_FAILURE;
202 const int nPixels = width * height;
203 TransformationInfo *buffPtr1 = NULL;
204 TransformationInfo *buffPtr2 = NULL;
205
206 // Check parameters
207 if (handler == NULL || n <= 2 || width <= 0 || height <= 0 || nComponents <= 0 || scaleDown <= 0.0 ||
208 scaleDown >= 1.0)
209 {
210 return EXIT_FAILURE;
211 }
212
213 assert(handler);
214 assert(n > 2);
215 assert(width > 0);
216 assert(height > 0);
217 assert(nComponents > 0);
218 assert(scaleDown > 0.0);
219 assert(scaleDown < 1.0);
220
221 handler->width = width;
222 handler->height = height;
223 handler->nComponents = (unsigned char)nComponents;
224
225 buffPtr1 = (TransformationInfo *)calloc(nPixels, sizeof(TransformationInfo));
226 buffPtr2 = (TransformationInfo *)calloc(nPixels, sizeof(TransformationInfo));
227 if (!buffPtr1 || !buffPtr2)
228 {
229 goto cleanup;
230 }
231
232 sliceTriangle(buffPtr1, width, height, n, scaleDown);
233
234 // Rotate all points and fix origin to left top
235 for (int idx = 0; idx < n; ++idx)
236 {
237 double rotationAngle = idx * (360.0 / n);
238 rotatePoints(buffPtr2, buffPtr1, width, height, rotationAngle);
239 }
240
241 // Fill rotation artifacts
242 memset(buffPtr1, 0, sizeof(TransformationInfo) * width * height);
243 interpolate(buffPtr1, buffPtr2, width, height);
244
245 // Remove zeros and set to points for handler
246 handler->nPoints = 0;
247 for (int idx = 0; idx < nPixels; ++idx)
248 {
249 const TransformationInfo *ptr = &buffPtr1[idx];
250 if (!(ptr->srcLocation.x) || !(ptr->srcLocation.y))
251 {
252 continue;
253 }
254
255 buffPtr1[handler->nPoints] = *ptr;
256 buffPtr1[handler->nPoints].srcOffset =
257 ptr->srcLocation.x * nComponents + ptr->srcLocation.y * width * nComponents;
258 buffPtr1[handler->nPoints].dstOffset =
259 ptr->dstLocation.x * nComponents + ptr->dstLocation.y * width * nComponents;
260 ++(handler->nPoints);
261 }
262
263 // Sort
264 qsort(buffPtr1, handler->nPoints, sizeof(TransformationInfo), compare);
265
266 // Deduplicate
267 jdx = 0;
268 for (int idx = 1; idx < handler->nPoints; ++idx)
269 {
270 if (compare(&buffPtr1[jdx], &buffPtr1[idx]))
271 {
272 buffPtr1[jdx] = buffPtr1[idx];
273 ++jdx;
274 }
275 }
276 handler->nPoints = jdx;
277
278 handler->pTransferFunc = (TransformationInfo *)malloc(handler->nPoints * sizeof(TransformationInfo));
279 memcpy(handler->pTransferFunc, buffPtr1, handler->nPoints * sizeof(TransformationInfo));
280 retval = EXIT_SUCCESS;
281
282cleanup:
283 free(buffPtr1);
284 free(buffPtr2);
285
286 if (retval == EXIT_FAILURE)
287 {
288 free(handler->pTransferFunc);
289 }
290
291 return retval;
292}
void sliceTriangle(TransformationInfo *transformPtr, int width, int height, int n, double scaleDown)
Slices a suitable triangle from image.
static int compare(const void *lhsPtr, const void *rhsPtr)
void interpolate(TransformationInfo *dataOut, const TransformationInfo *dataIn, int width, int height)
A simple interpolation function. Internal use only.
void rotatePoints(TransformationInfo *outData, const TransformationInfo *orgData, int width, int height, double angle)
Rotates the coordinates of sliced triangle. Internal use only.
int height
Image height.
int width
Image width.
long long nPoints
Total number of points of transfer function.
unsigned char nComponents
Number of components (eg 3 for RGB)
unsigned long long srcOffset
Offset from source image.
Point2D srcLocation
Location from source image.
Point2D dstLocation
Location to destination image.
Here is the call graph for this function:
Here is the caller graph for this function:

◆ interpolate()

void interpolate ( TransformationInfo * dataOut,
const 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 62 of file kaleidoscope.c.

63{
64 // Very simple implementation of nearest neighbour interpolation
65 for (int idx = 1; idx < height - 1; ++idx)
66 {
67 int heightOffset = idx * width;
68 for (int jdx = 1; jdx < width - 1; ++jdx)
69 {
70 const TransformationInfo *ptrIn = &dataIn[heightOffset + jdx];
71 TransformationInfo *ptrOut = &dataOut[heightOffset + jdx];
72 if (!(ptrIn->dstLocation.x) && !(ptrIn->dstLocation.y))
73 {
74 ptrOut->dstLocation.x = jdx;
75 ptrOut->dstLocation.y = idx;
76 if (((ptrIn - 1)->dstLocation.x) || ((ptrIn - 1)->dstLocation.y)) // Left
77 {
78 ptrOut->srcLocation.x = (ptrIn - 1)->srcLocation.x + 1;
79 ptrOut->srcLocation.y = (ptrIn - 1)->srcLocation.y;
80 }
81 else if (((ptrIn + 1)->dstLocation.x) || ((ptrIn + 1)->dstLocation.y)) // Right
82 {
83 ptrOut->srcLocation.x = (ptrIn + 1)->srcLocation.x - 1;
84 ptrOut->srcLocation.y = (ptrIn + 1)->srcLocation.y;
85 }
86 else if (((ptrIn - width)->dstLocation.x) || ((ptrIn - width)->dstLocation.y)) // Top
87 {
88 ptrOut->srcLocation.x = (ptrIn - width)->srcLocation.x;
89 ptrOut->srcLocation.y = (ptrIn - width)->srcLocation.y - 1;
90 }
91 else if (((ptrIn + width)->dstLocation.x) || ((ptrIn + width)->dstLocation.y)) // Bottom
92 {
93 ptrOut->srcLocation.x = (ptrIn + width)->srcLocation.x;
94 ptrOut->srcLocation.y = (ptrIn + width)->srcLocation.y + 1;
95 }
96 else if (((ptrIn - width - 1)->dstLocation.x) || ((ptrIn - width - 1)->dstLocation.y)) // Top-Left
97 {
98 ptrOut->srcLocation.x = (ptrIn - width - 1)->srcLocation.x - 1;
99 ptrOut->srcLocation.y = (ptrIn - width - 1)->srcLocation.y - 1;
100 }
101 else if (((ptrIn - width + 1)->dstLocation.x) || ((ptrIn - width + 1)->dstLocation.y)) // Top-Right
102 {
103 ptrOut->srcLocation.x = (ptrIn - width + 1)->srcLocation.x + 1;
104 ptrOut->srcLocation.y = (ptrIn - width + 1)->srcLocation.y - 1;
105 }
106 else if (((ptrIn + width - 1)->dstLocation.x) || ((ptrIn + width - 1)->dstLocation.y)) // Bottom-Left
107 {
108 ptrOut->srcLocation.x = (ptrIn + width - 1)->srcLocation.x - 1;
109 ptrOut->srcLocation.y = (ptrIn + width - 1)->srcLocation.y - 1;
110 }
111 else if (((ptrIn + width + 1)->dstLocation.x) || ((ptrIn + width + 1)->dstLocation.y)) // Bottom-Right
112 {
113 ptrOut->srcLocation.x = (ptrIn + width + 1)->srcLocation.x + 1;
114 ptrOut->srcLocation.y = (ptrIn + width + 1)->srcLocation.y + 1;
115 }
116 else
117 {
118 memset(ptrOut, 0, sizeof(TransformationInfo));
119 }
120 }
121 else
122 {
123 *ptrOut = *ptrIn;
124 }
125 }
126 }
127}
Here is the caller graph for this function:

◆ processKaleidoscope()

void processKaleidoscope ( const KaleidoscopeHandle * handler,
double k,
const 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 294 of file kaleidoscope.c.

295{
296 long long idx;
297 const long long nComponents = handler->nComponents;
298 const long long nPixels = (long long)handler->width * handler->height * handler->nComponents;
299
300 const unsigned char *srcPtr = imgIn;
301 unsigned char *destPtr = imgOut;
302 const TransformationInfo *ptrTransform = &(handler->pTransferFunc[0]);
303
304 for (idx = 0; idx < nPixels; ++idx, ++destPtr, ++srcPtr) // Dim image
305 {
306 *destPtr = (unsigned char)((*srcPtr) * k);
307 }
308 for (idx = 0; idx < handler->nPoints; ++idx, ++ptrTransform) // Merge
309 {
310 memcpy(&(imgOut[ptrTransform->dstOffset]), &(imgIn[ptrTransform->srcOffset]), nComponents);
311 }
312}
Here is the caller graph for this function:

◆ rotatePoints()

void rotatePoints ( TransformationInfo * outData,
const 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 129 of file kaleidoscope.c.

130{
131 double cosVal = cos(angle * M_PI / 180);
132 double sinVal = sin(angle * M_PI / 180);
133
134 for (int 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}
Here is the caller graph for this function:

◆ sliceTriangle()

void 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

Definition at line 155 of file kaleidoscope.c.

156{
157 // Variables
158 const double topAngle = 360.0 / n;
159 const double tanVal = tan(topAngle / 2.0 * M_PI / 180.0); // tan(topAngle / 2) in radians
160 const int triangleHeight = (int)fmin(round(width / (2.0 * tanVal)), height - 1);
161 const int heightStart = (height - triangleHeight) / 2;
162 const int heightEnd = (height + triangleHeight) / 2;
163 const int scaleDownOffset = (int)(height * scaleDown / 2);
164
165 // Ensure limits within image
166 assert(heightStart >= 0);
167 assert(heightStart <= height);
168 assert(heightEnd >= 0);
169 assert(heightEnd <= height);
170
171 for (int idx = heightStart; idx < heightEnd; ++idx)
172 {
173 const int currentBaseLength = (int)((idx - heightStart) * tanVal);
174
175 const int widthStart = (width / 2 - currentBaseLength);
176 const int widthEnd = (width / 2 + currentBaseLength);
177
178 // Ensure limits within image
179 if (widthStart < 0 || widthStart > width || widthEnd < 0 || widthEnd > width)
180 {
181 continue;
182 }
183
184 TransformationInfo *ptr = &transformPtr[idx * width];
185 for (int 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}
Here is the caller graph for this function: