pikl 0.2.7-x86-mswin32 → 0.2.8-x86-mswin32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Manifest.txt +23 -0
- data/ext/pikl/decrease/fsdither.h +554 -0
- data/ext/pikl/decrease/median.c +1179 -0
- data/ext/pikl/decrease/median.h +7 -0
- data/ext/pikl/decrease/neuquan5.c +563 -0
- data/ext/pikl/decrease/neuquant.h +62 -0
- data/ext/pikl/decrease/wu.c +447 -0
- data/ext/pikl/decrease/wu.h +7 -0
- data/ext/pikl/pikl_affine.c +250 -0
- data/ext/pikl/pikl_affine.h +20 -0
- data/ext/pikl/pikl_blur.c +244 -0
- data/ext/pikl/pikl_blur.h +12 -0
- data/ext/pikl/pikl_decrease.c +126 -0
- data/ext/pikl/pikl_decrease.h +19 -0
- data/ext/pikl/pikl_effect2.c +240 -0
- data/ext/pikl/pikl_effect2.h +55 -0
- data/ext/pikl/pikl_effect3.c +266 -0
- data/ext/pikl/pikl_effect3.h +12 -0
- data/ext/pikl/pikl_effect4.c +495 -0
- data/ext/pikl/pikl_effect4.h +12 -0
- data/ext/pikl/pikl_pattern.c +611 -0
- data/ext/pikl/pikl_pattern.h +12 -0
- data/ext/pikl/pikl_scrap.c +731 -0
- data/ext/pikl/pikl_scrap.h +12 -0
- data/lib/pikl/version.rb +1 -1
- metadata +26 -3
@@ -0,0 +1,611 @@
|
|
1
|
+
#include "pikl_pattern.h"
|
2
|
+
|
3
|
+
static int pkl_pattern_draw_line(PKLImage pkl, double *wd, int pw, int ph);
|
4
|
+
static int pkl_pattern_draw_average(PKLImage pkl, double *wd, int pw, int ph);
|
5
|
+
|
6
|
+
//=============================================================================
|
7
|
+
// pkl_pattern_hexagon
|
8
|
+
//=============================================================================
|
9
|
+
PKLExport int pkl_pattern_hexagon(PKLImage pkl, int pw, int ph, PKL_PAINT_TYPE type)
|
10
|
+
{
|
11
|
+
double ww, hh, *wd;
|
12
|
+
int i, result;
|
13
|
+
|
14
|
+
wd = malloc(sizeof(double)*ph);
|
15
|
+
if(!wd) return(1);
|
16
|
+
|
17
|
+
ww = (double)pw;
|
18
|
+
hh = (double)ph;
|
19
|
+
|
20
|
+
/* パターン座標を構築する */
|
21
|
+
for(i=0; i<ph; i++){
|
22
|
+
if((double)i < hh/6.0){
|
23
|
+
wd[i] = ww * (double)i*6.0/hh;
|
24
|
+
}else
|
25
|
+
if((double)i < hh/2.0){
|
26
|
+
wd[i] = ww;
|
27
|
+
}else
|
28
|
+
if((double)i < hh*2.0/3.0){
|
29
|
+
wd[i] = ww*4.0 - ww*(double)i*6.0/hh;
|
30
|
+
}else{
|
31
|
+
wd[i] = 0.0;
|
32
|
+
}
|
33
|
+
}
|
34
|
+
|
35
|
+
/* 塗りタイプ別の処理 */
|
36
|
+
switch(type){
|
37
|
+
case PKL_PAINT_AVE:
|
38
|
+
result = pkl_pattern_draw_average(pkl, wd, pw, ph);
|
39
|
+
break;
|
40
|
+
case PKL_PAINT_LINE:
|
41
|
+
default:
|
42
|
+
result = pkl_pattern_draw_line(pkl, wd, pw, ph);
|
43
|
+
}
|
44
|
+
|
45
|
+
free(wd);
|
46
|
+
return(result);
|
47
|
+
}
|
48
|
+
|
49
|
+
//=============================================================================
|
50
|
+
// pkl_pattern_diamond
|
51
|
+
//=============================================================================
|
52
|
+
PKLExport int pkl_pattern_diamond(PKLImage pkl, int pw, int ph, PKL_PAINT_TYPE type)
|
53
|
+
{
|
54
|
+
double ww, hh, *wd;
|
55
|
+
int i, result;
|
56
|
+
|
57
|
+
wd = malloc(sizeof(double)*ph);
|
58
|
+
if(!wd) return(1);
|
59
|
+
|
60
|
+
ww = (double)pw;
|
61
|
+
hh = (double)ph;
|
62
|
+
|
63
|
+
/* パターン座標を構築する */
|
64
|
+
for(i=0; i<ph; i++){
|
65
|
+
if((double)i < hh/2.0){
|
66
|
+
wd[i] = ww*(double)i*2.0/hh;
|
67
|
+
}else{
|
68
|
+
wd[i] = ww*2.0 - ww*(double)i*2.0/hh;
|
69
|
+
}
|
70
|
+
}
|
71
|
+
|
72
|
+
/* 塗りタイプ別の処理 */
|
73
|
+
switch(type){
|
74
|
+
case PKL_PAINT_AVE:
|
75
|
+
result = pkl_pattern_draw_average(pkl, wd, pw, ph);
|
76
|
+
break;
|
77
|
+
case PKL_PAINT_LINE:
|
78
|
+
default:
|
79
|
+
result = pkl_pattern_draw_line(pkl, wd, pw, ph);
|
80
|
+
}
|
81
|
+
|
82
|
+
free(wd);
|
83
|
+
return(result);
|
84
|
+
}
|
85
|
+
|
86
|
+
//=============================================================================
|
87
|
+
// pkl_pattern_circle
|
88
|
+
//=============================================================================
|
89
|
+
PKLExport int pkl_pattern_circle(PKLImage pkl, int pw, int ph, PKL_PAINT_TYPE type)
|
90
|
+
{
|
91
|
+
double ww, hh, *wd;
|
92
|
+
int i, result;
|
93
|
+
|
94
|
+
wd = malloc(sizeof(double)*ph);
|
95
|
+
if(!wd) return(1);
|
96
|
+
|
97
|
+
ww = (double)pw;
|
98
|
+
hh = (double)ph;
|
99
|
+
|
100
|
+
/* パターン座標を構築する */
|
101
|
+
for(i=0; i<ph; i++){
|
102
|
+
if((double)i < hh/2.0){
|
103
|
+
wd[i] = ww*(double)i*2.0/hh - (ww/8.0)*sin((double)i*4.0/hh*M_PI);
|
104
|
+
}else{
|
105
|
+
wd[i] = ww*2.0 - ww*(double)i*2.0/hh + (ww/8.0)*sin((double)(i-hh/2.0)*4.0/hh*M_PI);
|
106
|
+
}
|
107
|
+
}
|
108
|
+
|
109
|
+
/* 塗りタイプ別の処理 */
|
110
|
+
switch(type){
|
111
|
+
case PKL_PAINT_AVE:
|
112
|
+
result = pkl_pattern_draw_average(pkl, wd, pw, ph);
|
113
|
+
break;
|
114
|
+
case PKL_PAINT_LINE:
|
115
|
+
default:
|
116
|
+
result = pkl_pattern_draw_line(pkl, wd, pw, ph);
|
117
|
+
}
|
118
|
+
|
119
|
+
free(wd);
|
120
|
+
return(result);
|
121
|
+
}
|
122
|
+
|
123
|
+
//=============================================================================
|
124
|
+
// pkl_pattern_brick
|
125
|
+
//=============================================================================
|
126
|
+
PKLExport int pkl_pattern_brick(PKLImage pkl, int pw, int ph, PKL_PAINT_TYPE type)
|
127
|
+
{
|
128
|
+
double ww, hh, *wd;
|
129
|
+
int i, result;
|
130
|
+
|
131
|
+
wd = malloc(sizeof(double)*ph);
|
132
|
+
if(!wd) return(1);
|
133
|
+
|
134
|
+
ww = (double)pw;
|
135
|
+
hh = (double)ph;
|
136
|
+
|
137
|
+
/* パターン座標を構築する */
|
138
|
+
for(i=0; i<ph; i++){
|
139
|
+
if((double)i < hh/2.0){
|
140
|
+
wd[i] = ww;
|
141
|
+
}else{
|
142
|
+
wd[i] = 0.0;
|
143
|
+
}
|
144
|
+
}
|
145
|
+
|
146
|
+
/* 塗りタイプ別の処理 */
|
147
|
+
switch(type){
|
148
|
+
case PKL_PAINT_AVE:
|
149
|
+
result = pkl_pattern_draw_average(pkl, wd, pw, ph);
|
150
|
+
break;
|
151
|
+
case PKL_PAINT_LINE:
|
152
|
+
default:
|
153
|
+
result = pkl_pattern_draw_line(pkl, wd, pw, ph);
|
154
|
+
}
|
155
|
+
|
156
|
+
free(wd);
|
157
|
+
return(result);
|
158
|
+
}
|
159
|
+
|
160
|
+
//=============================================================================
|
161
|
+
// pkl_pattern_draw_line
|
162
|
+
//=============================================================================
|
163
|
+
static int pkl_pattern_draw_line(PKLImage pkl, double *wd, int pw, int ph)
|
164
|
+
{
|
165
|
+
unsigned char clipcolor[PKL_CHANNEL], *p;
|
166
|
+
int i, j, s, idx, k, color[PKL_CHANNEL];
|
167
|
+
double ww, hh, rm;
|
168
|
+
int count, ptn=0;
|
169
|
+
|
170
|
+
if(pw<0 || pw>pkl->width || ph<0 || ph>pkl->height) return(1);
|
171
|
+
|
172
|
+
ww = (double)pw;
|
173
|
+
hh = (double)ph;
|
174
|
+
|
175
|
+
//x方向に母点分ずつずらしていく
|
176
|
+
for(j=0; j<pkl->width+pw; j+=pw){
|
177
|
+
//パターンの切り替え
|
178
|
+
ptn = !ptn;
|
179
|
+
|
180
|
+
for(i=0; i<pkl->height; i++){
|
181
|
+
memset(color, 0, sizeof(color));
|
182
|
+
count=0;
|
183
|
+
|
184
|
+
//パターン配列のインデックスを算出
|
185
|
+
//(余剰を算出すれば、パターン配列を順番に処理できるから)
|
186
|
+
idx = i % ph;
|
187
|
+
|
188
|
+
//パターンを幅=pwの範囲で縦方向に見るので
|
189
|
+
//パターン距離(wd)をpwから引くことで横方向の距離を算出できる
|
190
|
+
//パターンは繰り返しなので、pw++ごとに切り替えればよい
|
191
|
+
rm = ptn ? wd[idx] : ww-wd[idx];
|
192
|
+
|
193
|
+
//jをパターンの中心として、両側へ広がりのある領域のピクセル平均を取る
|
194
|
+
for(s=j-rm; s<=j+rm; s++){
|
195
|
+
if(s<0 || s>=pkl->width) continue;
|
196
|
+
p = &pkl->image[(i*pkl->width+s)*pkl->channel];
|
197
|
+
for(k=0; k<pkl->channel; k++)
|
198
|
+
color[k] += *p++;
|
199
|
+
count++;
|
200
|
+
}
|
201
|
+
if(count==0) continue;
|
202
|
+
for(k=0; k<pkl->channel; k++)
|
203
|
+
clipcolor[k] = PKL_COLOR_CLIP(color[k]/count);
|
204
|
+
|
205
|
+
//作った色を横方向に適用する
|
206
|
+
for(s=j-rm; s<=j+rm; s++){
|
207
|
+
if(s<0 || s>=pkl->width) continue;
|
208
|
+
memcpy(&pkl->image[(i*pkl->width+s)*pkl->channel], clipcolor, pkl->channel);
|
209
|
+
}
|
210
|
+
}
|
211
|
+
}
|
212
|
+
return(0);
|
213
|
+
}
|
214
|
+
|
215
|
+
//=============================================================================
|
216
|
+
// pkl_pattern_draw_average
|
217
|
+
//=============================================================================
|
218
|
+
static int pkl_pattern_draw_average(PKLImage pkl, double *wd, int pw, int ph)
|
219
|
+
{
|
220
|
+
unsigned char clipcolor[PKL_CHANNEL], *p;
|
221
|
+
int i, j, s, t, k, color[PKL_CHANNEL];
|
222
|
+
int count, ys, idx, ptn=0;
|
223
|
+
double ww, hh, rm;
|
224
|
+
|
225
|
+
if(pw<0 || pw>pkl->width || ph<0 || ph>pkl->height) return(1);
|
226
|
+
|
227
|
+
ww = (double)pw;
|
228
|
+
hh = (double)ph;
|
229
|
+
|
230
|
+
for(j=0; j<pkl->width+pw; j+=pw){
|
231
|
+
ptn = !ptn;
|
232
|
+
ys = (ptn) ? 0 : (-ph/2);
|
233
|
+
|
234
|
+
for(i=ys; i<pkl->height; i+=ph){
|
235
|
+
memset(color, 0, sizeof(color));
|
236
|
+
count=0;
|
237
|
+
rm=wd[0];
|
238
|
+
|
239
|
+
for(t=i; t<i+ph; t++){
|
240
|
+
if(t<0 || t>=pkl->height) continue;
|
241
|
+
|
242
|
+
idx = t % ph;
|
243
|
+
rm = ptn ? wd[idx] : ww-wd[idx];
|
244
|
+
for(s=j-rm; s<=j+rm; s++){
|
245
|
+
if(s<0 || s>=pkl->width) continue;
|
246
|
+
p = &pkl->image[(t*pkl->width+s)*pkl->channel];
|
247
|
+
for(k=0; k<pkl->channel; k++)
|
248
|
+
color[k] += *p++;
|
249
|
+
count++;
|
250
|
+
}
|
251
|
+
}
|
252
|
+
|
253
|
+
/* パターン領域内の平均算出 */
|
254
|
+
if(count==0) continue;
|
255
|
+
for(k=0; k<pkl->channel; k++)
|
256
|
+
clipcolor[k] = PKL_COLOR_CLIP(color[k]/count);
|
257
|
+
|
258
|
+
/* パターン領域を同一色で塗りつぶす */
|
259
|
+
for(t=i; t<i+ph; t++){
|
260
|
+
if(t<0 || t>=pkl->height) continue;
|
261
|
+
idx = t % ph;
|
262
|
+
rm = ptn ? wd[idx] : ww-wd[idx];
|
263
|
+
|
264
|
+
for(s=j-rm; s<=j+rm; s++){
|
265
|
+
if(s<0 || s>=pkl->width) continue;
|
266
|
+
memcpy(&pkl->image[(t*pkl->width+s)*pkl->channel], clipcolor, pkl->channel);
|
267
|
+
}
|
268
|
+
|
269
|
+
//境界線
|
270
|
+
//if(j-rm-1>=0)
|
271
|
+
// memset(&pkl->image[(t*pkl->width+(int)(j-rm-1))*pkl->channel], 0, pkl->channel);
|
272
|
+
//if(j+rm+1<pkl->width)
|
273
|
+
// memset(&pkl->image[(t*pkl->width+(int)(j+rm+1))*pkl->channel], 0, pkl->channel);
|
274
|
+
//if(t-1>=0)
|
275
|
+
// memset(&pkl->image[((t-1)*pkl->width+s)*pkl->channel], 0, pkl->channel);
|
276
|
+
//if(t+1<pkl->height)
|
277
|
+
// memset(&pkl->image[((t+1)*pkl->width+s)*pkl->channel], 0, pkl->channel);
|
278
|
+
}
|
279
|
+
}
|
280
|
+
}
|
281
|
+
return(0);
|
282
|
+
}
|
283
|
+
|
284
|
+
//=============================================================================
|
285
|
+
// voronoi_type1 datatype
|
286
|
+
//=============================================================================
|
287
|
+
struct VoronoiPoint {
|
288
|
+
int x, y;
|
289
|
+
long color[PKL_CHANNEL];
|
290
|
+
unsigned char ave[PKL_CHANNEL];
|
291
|
+
int count;
|
292
|
+
};
|
293
|
+
|
294
|
+
//=============================================================================
|
295
|
+
// voronoi_type1_query
|
296
|
+
//=============================================================================
|
297
|
+
static void voronoi_type1_query(PKLImage pkl, struct VoronoiPoint *vptr, int *id, int zone, int xzone, int yzone)
|
298
|
+
{
|
299
|
+
struct VoronoiPoint *p;
|
300
|
+
int i, j, k, tx, ty, xx, yy, minIx, minIy;
|
301
|
+
double d, mind;
|
302
|
+
|
303
|
+
//母点を生成
|
304
|
+
srand48(1);
|
305
|
+
p = vptr;
|
306
|
+
for(i=0; i<yzone; i++){
|
307
|
+
for(j=0; j<xzone; j++){
|
308
|
+
tx = j * zone + lrand48()%zone;
|
309
|
+
ty = i * zone + lrand48()%zone;
|
310
|
+
p->x = tx>=pkl->width ? pkl->width-1 : tx;
|
311
|
+
p->y = ty>=pkl->height ? pkl->height-1 : ty;
|
312
|
+
p++;
|
313
|
+
}
|
314
|
+
}
|
315
|
+
|
316
|
+
for(i=0; i<pkl->height; i++){
|
317
|
+
yy = i/zone;
|
318
|
+
for(j=0; j<pkl->width; j++){
|
319
|
+
xx = j/zone;
|
320
|
+
mind=10000000;
|
321
|
+
minIx=minIy=0;
|
322
|
+
|
323
|
+
//カレントピクセルに最も近い母点を探す
|
324
|
+
for(ty=yy-1; ty<=yy+1; ty++){
|
325
|
+
if(ty<0 || ty>yzone-1) continue;
|
326
|
+
for(tx=xx-1; tx<=xx+1; tx++){
|
327
|
+
if(tx<0 || tx>xzone-1) continue;
|
328
|
+
d = (vptr[ty*xzone+tx].x-j)*(vptr[ty*xzone+tx].x-j) +
|
329
|
+
(vptr[ty*xzone+tx].y-i)*(vptr[ty*xzone+tx].y-i);
|
330
|
+
if(d < mind){
|
331
|
+
mind = d;
|
332
|
+
minIx = tx;
|
333
|
+
minIy = ty;
|
334
|
+
}
|
335
|
+
}
|
336
|
+
}
|
337
|
+
|
338
|
+
for(k=0; k<pkl->channel; k++)
|
339
|
+
vptr[minIy*xzone+minIx].color[k] += pkl->image[(i*pkl->width+j)*pkl->channel+k];
|
340
|
+
vptr[minIy*xzone+minIx].count++;
|
341
|
+
|
342
|
+
//各ピクセルのボロノイIDをセット
|
343
|
+
id[i*pkl->width+j] = minIy*xzone+minIx;
|
344
|
+
}
|
345
|
+
}
|
346
|
+
}
|
347
|
+
|
348
|
+
//=============================================================================
|
349
|
+
// pkl_voronoi_type1
|
350
|
+
//=============================================================================
|
351
|
+
PKLExport int pkl_voronoi_type1(PKLImage pkl, int zone, int bordercolor, int test)
|
352
|
+
{
|
353
|
+
struct VoronoiPoint *vptr, *p;
|
354
|
+
int xzone, yzone, *id;
|
355
|
+
int i, j, k, tx, ty;
|
356
|
+
unsigned char border[PKL_CHANNEL];
|
357
|
+
|
358
|
+
|
359
|
+
if(zone < 2) return(1);
|
360
|
+
if(zone>=pkl->width || zone>=pkl->height) return(1);
|
361
|
+
xzone = pkl->width/zone;
|
362
|
+
if((pkl->width%zone) != 0) xzone++;
|
363
|
+
yzone = pkl->height/zone;
|
364
|
+
if((pkl->height%zone) != 0) yzone++;
|
365
|
+
|
366
|
+
for(i=0; i<pkl->channel; i++)
|
367
|
+
border[i] = (bordercolor>>((pkl->channel-i)*8) & 0xFF);
|
368
|
+
|
369
|
+
//ボロノイ管理データ
|
370
|
+
vptr = malloc(sizeof(struct VoronoiPoint) * xzone*yzone);
|
371
|
+
memset(vptr, 0, sizeof(struct VoronoiPoint) * xzone*yzone);
|
372
|
+
|
373
|
+
//各座標のボロノイIDを格納するデータ
|
374
|
+
id = malloc(sizeof(int) * pkl->width*pkl->height);
|
375
|
+
|
376
|
+
//ボロノイ管理データを作る
|
377
|
+
voronoi_type1_query(pkl, vptr, id, zone, xzone, yzone);
|
378
|
+
|
379
|
+
if(test){
|
380
|
+
//分割シュミレーション(母点を置く)
|
381
|
+
memset(pkl->image, 0xff, pkl->width*pkl->height*pkl->channel);
|
382
|
+
for(i=0; i<xzone*yzone; i++)
|
383
|
+
memcpy(&pkl->image[(vptr[i].y*pkl->width+vptr[i].x)*pkl->channel], border, pkl->channel);
|
384
|
+
}else{
|
385
|
+
//各ボロノイポイントの平均色算出
|
386
|
+
for(ty=0; ty<yzone; ty++){
|
387
|
+
for(tx=0; tx<xzone; tx++){
|
388
|
+
if(vptr[ty*xzone+tx].count == 0) continue;
|
389
|
+
p = &vptr[ty*xzone+tx];
|
390
|
+
for(k=0; k<pkl->channel; k++)
|
391
|
+
p->ave[k] = PKL_COLOR_CLIP(p->color[k]/p->count);
|
392
|
+
}
|
393
|
+
}
|
394
|
+
//色を設定
|
395
|
+
for(i=0; i<pkl->height; i++)
|
396
|
+
for(j=0; j<pkl->width; j++)
|
397
|
+
memcpy(&pkl->image[(i*pkl->width+j)*pkl->channel], vptr[id[i*pkl->width+j]].ave, pkl->channel);
|
398
|
+
}
|
399
|
+
|
400
|
+
//境界線を引く
|
401
|
+
if(bordercolor!=-1){
|
402
|
+
int currentId, hit=0;
|
403
|
+
for(j=0; j<pkl->height; j++){
|
404
|
+
for(i=0; i<pkl->width; i++){
|
405
|
+
hit=0;
|
406
|
+
currentId = id[j*pkl->width+i];
|
407
|
+
if(i-1>=0 && currentId!=id[j*pkl->width+i-1]) hit++;
|
408
|
+
if(i+1<pkl->width && currentId!=id[j*pkl->width+i+1]) hit++;
|
409
|
+
if(j-1>=0 && currentId!=id[(j-1)*pkl->width+i+1]) hit++;
|
410
|
+
if(j+1<pkl->height && currentId!=id[(j+1)*pkl->width+i+1]) hit++;
|
411
|
+
if(hit)
|
412
|
+
memcpy(&pkl->image[(j*pkl->width+i)*pkl->channel], border, pkl->channel);
|
413
|
+
}
|
414
|
+
}
|
415
|
+
}
|
416
|
+
free(id);
|
417
|
+
free(vptr);
|
418
|
+
return(0);
|
419
|
+
}
|
420
|
+
|
421
|
+
//=============================================================================
|
422
|
+
// voronoi_type2 datatype
|
423
|
+
//=============================================================================
|
424
|
+
//ボロノイの母点管理用(1つの母点から隣接する母点の個数)
|
425
|
+
#define VORONOI_CNT 10 //根拠はない
|
426
|
+
|
427
|
+
struct VORONOI {
|
428
|
+
int x, y; //母点座標
|
429
|
+
int id; //管理用ID
|
430
|
+
long color[PKL_CHANNEL]; //ターゲット領域の色累積領域
|
431
|
+
int count; //累積ピクセル数
|
432
|
+
int next[VORONOI_CNT]; //隣接する母点のID
|
433
|
+
};
|
434
|
+
|
435
|
+
//=============================================================================
|
436
|
+
// vcompare
|
437
|
+
//=============================================================================
|
438
|
+
static int vcompare(const void *a, const void *b)
|
439
|
+
{
|
440
|
+
struct VORONOI *t1 = (struct VORONOI *)a;
|
441
|
+
struct VORONOI *t2 = (struct VORONOI *)b;
|
442
|
+
|
443
|
+
if(t1->y == t2->y)
|
444
|
+
return(t1->x - t2->x);
|
445
|
+
return(t1->y - t2->y);
|
446
|
+
}
|
447
|
+
|
448
|
+
//=============================================================================
|
449
|
+
// voronoi_setid
|
450
|
+
//=============================================================================
|
451
|
+
static void voronoi_setid(int *ary, int id)
|
452
|
+
{
|
453
|
+
int i;
|
454
|
+
|
455
|
+
for(i=0; i<VORONOI_CNT; i++){
|
456
|
+
if(ary[i] == -1){
|
457
|
+
ary[i] = id;
|
458
|
+
return;
|
459
|
+
}
|
460
|
+
}
|
461
|
+
}
|
462
|
+
|
463
|
+
//=============================================================================
|
464
|
+
// voronoi_type2_query
|
465
|
+
//=============================================================================
|
466
|
+
static void voronoi_type2_query(PKLImage pkl, struct VORONOI *kp, int *ip, int count)
|
467
|
+
{
|
468
|
+
int i, j, k, min_id, pre_id;
|
469
|
+
double d, dx, dy, min_d;
|
470
|
+
|
471
|
+
//母点をランダムに生成する
|
472
|
+
srand48((long)count);
|
473
|
+
for(i=0; i<count; i++){
|
474
|
+
kp[i].x = lrand48() % pkl->width;
|
475
|
+
kp[i].y = lrand48() % pkl->height;
|
476
|
+
kp[i].id = i;
|
477
|
+
}
|
478
|
+
|
479
|
+
//生成した母点座標を左上から右下に向かってソートする
|
480
|
+
qsort(kp, count, sizeof(struct VORONOI), vcompare);
|
481
|
+
|
482
|
+
min_id = 0; //最初の母点ID
|
483
|
+
pre_id = 0; //前ピクセルの母点ID
|
484
|
+
|
485
|
+
//各母点の最近傍の母点を探索する
|
486
|
+
for(j=0; j<pkl->height; j++){
|
487
|
+
for(i=0; i<pkl->width; i++){
|
488
|
+
// 前ピクセルの母点との距離を求める
|
489
|
+
dx = kp[pre_id].x-i;
|
490
|
+
dy = kp[pre_id].y-j;
|
491
|
+
min_d = sqrt(dx*dx+dy*dy);
|
492
|
+
|
493
|
+
//現在のピクセルの右上により近い母点があるか検索
|
494
|
+
for(k=pre_id-1; k>=0 && (kp[k].y>=j-min_d); k--){
|
495
|
+
if(kp[k].x >= i && kp[k].x <= i+min_d){
|
496
|
+
dx = kp[k].x-i;
|
497
|
+
dy = kp[k].y-j;
|
498
|
+
d = sqrt(dx*dx+dy*dy);
|
499
|
+
if(d<min_d){
|
500
|
+
min_id=k;
|
501
|
+
min_d=d;
|
502
|
+
}
|
503
|
+
}
|
504
|
+
}
|
505
|
+
//現在のピクセルの右下により近い母点があるか検索
|
506
|
+
for(k=pre_id+1; k<count && (kp[k].y<=j+min_d); k++){
|
507
|
+
if(kp[k].x >= i && kp[k].x <= i+min_d){
|
508
|
+
dx = kp[k].x-i;
|
509
|
+
dy = kp[k].y-j;
|
510
|
+
d = sqrt(dx*dx+dy*dy);
|
511
|
+
if(d<min_d){
|
512
|
+
min_id=k;
|
513
|
+
min_d=d;
|
514
|
+
}
|
515
|
+
}
|
516
|
+
}
|
517
|
+
//最も近くにある母点のIDを設定する
|
518
|
+
if(pre_id != min_id){
|
519
|
+
voronoi_setid(kp[pre_id].next, min_id);
|
520
|
+
voronoi_setid(kp[min_id].next, pre_id);
|
521
|
+
}
|
522
|
+
|
523
|
+
//現在の座標のIDに決定したボロノイ管理IDを設定する
|
524
|
+
ip[j*pkl->width+i] = min_id;
|
525
|
+
pre_id = min_id;
|
526
|
+
}
|
527
|
+
}
|
528
|
+
}
|
529
|
+
|
530
|
+
//=============================================================================
|
531
|
+
// pkl_voronoi_type2
|
532
|
+
//=============================================================================
|
533
|
+
PKLExport int pkl_voronoi_type2(PKLImage pkl, int count, int bordercolor, int test)
|
534
|
+
{
|
535
|
+
struct VORONOI *kp;
|
536
|
+
int i, j, k, *ip;
|
537
|
+
unsigned char border[PKL_CHANNEL];
|
538
|
+
|
539
|
+
//母点数の閾値
|
540
|
+
if(count < 10) return(1);
|
541
|
+
|
542
|
+
for(i=0; i<pkl->channel; i++)
|
543
|
+
border[i] = (bordercolor>>((pkl->channel-i)*8) & 0xFF);
|
544
|
+
|
545
|
+
//各座標の母点IDを格納する領域
|
546
|
+
ip = malloc(sizeof(int) * pkl->width * pkl->height);
|
547
|
+
memset(ip, -1, sizeof(int) * pkl->width * pkl->height);
|
548
|
+
|
549
|
+
//母点管理領域(母点数分用意)
|
550
|
+
kp = malloc(sizeof(struct VORONOI) * count);
|
551
|
+
memset(kp, 0, sizeof(struct VORONOI) * count);
|
552
|
+
for(i=0; i<count; i++)
|
553
|
+
memset(kp[i].next, -1, sizeof(int)*VORONOI_CNT);
|
554
|
+
|
555
|
+
//ボロノイ管理データを作る
|
556
|
+
voronoi_type2_query(pkl, kp, ip, count);
|
557
|
+
|
558
|
+
if(test){
|
559
|
+
//分割シュミレーション(母点を置く)
|
560
|
+
memset(pkl->image, 0xff, pkl->width*pkl->height*pkl->channel);
|
561
|
+
for(i=0; i<count; i++)
|
562
|
+
memcpy(&pkl->image[(kp[i].y*pkl->width+kp[i].x)*pkl->channel], border, pkl->channel);
|
563
|
+
}else{
|
564
|
+
//ボロノイ分割されたので、各セルの平均色を算出するためにセルの色を累積する
|
565
|
+
for(j=0; j<pkl->height; j++) {
|
566
|
+
for(i=0; i<pkl->width; i++) {
|
567
|
+
//ipを参照することで、現在の座標がどのIDに所属するかわかる
|
568
|
+
if(ip[j*pkl->width+i] == -1) continue;
|
569
|
+
//IDごとに色を累積する
|
570
|
+
kp[ ip[j*pkl->width+i] ].count++;
|
571
|
+
for(k=0; k<pkl->channel; k++)
|
572
|
+
kp[ ip[j*pkl->width+i] ].color[k] += pkl->image[(j*pkl->width+i)*pkl->channel+k];
|
573
|
+
}
|
574
|
+
}
|
575
|
+
|
576
|
+
//各セルの平均色を作る
|
577
|
+
for(i=0; i<count; i++){
|
578
|
+
for(k=0; k<pkl->channel; k++){
|
579
|
+
if(kp[i].count!=0)
|
580
|
+
kp[i].color[k] = PKL_COLOR_CLIP(kp[i].color[k]/kp[i].count);
|
581
|
+
}
|
582
|
+
}
|
583
|
+
|
584
|
+
//色を置く
|
585
|
+
for(j=0; j<pkl->height; j++)
|
586
|
+
for(i=0; i<pkl->width; i++)
|
587
|
+
for(k=0; k<pkl->channel; k++)
|
588
|
+
pkl->image[(j*pkl->width+i)*pkl->channel+k] = kp[ ip[j*pkl->width+i] ].color[k];
|
589
|
+
}
|
590
|
+
|
591
|
+
//境界線を引く
|
592
|
+
if(bordercolor!=-1){
|
593
|
+
int currentId, hit=0;
|
594
|
+
for(j=0; j<pkl->height; j++){
|
595
|
+
for(i=0; i<pkl->width; i++){
|
596
|
+
hit=0;
|
597
|
+
currentId = ip[j*pkl->width+i];
|
598
|
+
if(i-1>=0 && currentId!=ip[j*pkl->width+i-1]) hit++;
|
599
|
+
if(i+1<pkl->width && currentId!=ip[j*pkl->width+i+1]) hit++;
|
600
|
+
if(j-1>=0 && currentId!=ip[(j-1)*pkl->width+i+1]) hit++;
|
601
|
+
if(j+1<pkl->height && currentId!=ip[(j+1)*pkl->width+i+1]) hit++;
|
602
|
+
if(hit)
|
603
|
+
memcpy(&pkl->image[(j*pkl->width+i)*pkl->channel], border, pkl->channel);
|
604
|
+
}
|
605
|
+
}
|
606
|
+
}
|
607
|
+
|
608
|
+
free(kp);
|
609
|
+
free(ip);
|
610
|
+
return(0);
|
611
|
+
}
|