kaleidoscope 1.4.2
 
Loading...
Searching...
No Matches
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
13void 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
52 return info;
53}
54
55static int compare(const void *lhsPtr, const void *rhsPtr)
56{
57 const TransformationInfo *lhs = (const TransformationInfo *)lhsPtr;
58 const TransformationInfo *rhs = (const TransformationInfo *)rhsPtr;
59 return (int)(lhs->dstOffset - rhs->dstOffset);
60}
61
62void interpolate(TransformationInfo *dataOut, const TransformationInfo *dataIn, int width, int height)
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}
128
129void rotatePoints(TransformationInfo *outData, const TransformationInfo *orgData, int width, int height, double angle)
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}
154
155void sliceTriangle(TransformationInfo *transformPtr, int width, int height, int n, double scaleDown)
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}
196
197int initKaleidoscope(KaleidoscopeHandle *handler, int n, int width, int height, int nComponents, double scaleDown)
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 if (handler->nPoints <= 0) // Prevent allocation of zero points
279 {
280 goto cleanup;
281 }
282
283 handler->pTransferFunc = (TransformationInfo *)malloc(handler->nPoints * sizeof(TransformationInfo));
284 memcpy(handler->pTransferFunc, buffPtr1, handler->nPoints * sizeof(TransformationInfo));
285 retval = EXIT_SUCCESS;
286
287cleanup:
288 free(buffPtr1);
289 free(buffPtr2);
290
291 if (retval == EXIT_FAILURE)
292 {
293 free(handler->pTransferFunc);
294 }
295
296 return retval;
297}
298
299void processKaleidoscope(const KaleidoscopeHandle *handler, double k, const unsigned char *imgIn, unsigned char *imgOut)
300{
301 long long idx;
302 const long long nComponents = handler->nComponents;
303 const long long nPixels = (long long)handler->width * handler->height * handler->nComponents;
304
305 const unsigned char *srcPtr = imgIn;
306 unsigned char *destPtr = imgOut;
307 const TransformationInfo *ptrTransform = &(handler->pTransferFunc[0]);
308
309 for (idx = 0; idx < nPixels; ++idx, ++destPtr, ++srcPtr) // Dim image
310 {
311 *destPtr = (unsigned char)((*srcPtr) * k);
312 }
313 for (idx = 0; idx < handler->nPoints; ++idx, ++ptrTransform) // Merge
314 {
315 memcpy(&(imgOut[ptrTransform->dstOffset]), &(imgIn[ptrTransform->srcOffset]), nComponents);
316 }
317}
318
320{
321 if (handler)
322 free(handler->pTransferFunc);
323}
void getKaleidoscopeVersion(int *major, int *minor, int *patch)
Get the Kaleidoscope Library version as integer.
void processKaleidoscope(const KaleidoscopeHandle *handler, double k, const unsigned char *imgIn, unsigned char *imgOut)
Applies kaleidoscope effect to image.
char * getKaleidoscopeLibraryInfo()
Get the Kaleidoscope Library info as string.
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)
int initKaleidoscope(KaleidoscopeHandle *handler, int n, int width, int height, int nComponents, double scaleDown)
Initializes kaleidoscope handler.
char * getKaleidoscopeVersionString()
Get the Kaleidoscope Library version as string.
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 deInitKaleidoscope(KaleidoscopeHandle *handler)
Deinitializes kaleidoscope handler.
struct TransformationInfo_t TransformationInfo
struct KaleidoscopeHandle_t KaleidoscopeHandle
int height
Image height.
int width
Image width.
long long nPoints
Total number of points of transfer function.
struct TransformationInfo_t * pTransferFunc
Transformation info.
unsigned char nComponents
Number of components (eg 3 for RGB)
unsigned long long srcOffset
Offset from source image.
unsigned long long dstOffset
Offset from destination image.
Point2D srcLocation
Location from source image.
Point2D dstLocation
Location to destination image.