2
* Pure Data Packet. common image processing routines.
3
* Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org>
5
* This program is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation; either version 2 of the License, or
8
* (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software
17
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23
This file contains common code for (portable) low level image processing objects
24
pdp_imageproc_* methods
25
The rest is int pdp_imageproc_<platform>.c
27
There are also highlevel dispatcher methods that operate on packets:
28
pdp_imageproc_dispatch_* methods
35
#include "pdp_imageproc.h"
36
#include "pdp_image.h"
38
#include "pdp_packet.h"
40
#define CLAMP16(x) (((x) > 0x7fff) ? 0x7fff : (((x) < -0x7fff) ? -0x7fff : (x)))
42
u32 pdp_imageproc_legalwidth(int i)
44
if (i>1024) return 1024;
45
if (i>0) return ((((i-1)>>3)+1)<<3);
50
u32 pdp_imageproc_legalheight(int i)
52
if (i>1024) return 1024;
53
if (i>0) return ((((i-1)>>3)+1)<<3);
56
u32 pdp_imageproc_legalwidth_round_down(int i)
58
if (i>1024) return 1024;
59
if (i>8) return ((i>>3)<<3);
64
u32 pdp_imageproc_legalheight_round_down(int i)
66
if (i>1024) return 1024;
67
if (i>8) return ((i>>3)<<3);
72
/* check if two packets are allocated and of the same type */
73
bool pdp_packet_compat(int packet0, int packet1)
76
t_pdp *header0 = pdp_packet_header(packet0);
77
t_pdp *header1 = pdp_packet_header(packet1);
78
if (!(header1)) return 0;
79
if (!(header0)) return 0;
80
if (header0->type != header1->type) return 0;
88
void pdp_imageproc_xor_process(void *x, u32 width, u32 height, s16 *image, s16 *image2)
90
u32 *plane = (u32 *)image;
91
u32 *plane2 = (u32 *)image2;
92
int count = (width * height) >> 1;
95
for (i=0; i<count; i++){
96
plane[i] ^= plane2[i];
100
void pdp_imageproc_and_process(void *x, u32 width, u32 height, s16 *image, s16 *image2)
102
u32 *plane = (u32 *)image;
103
u32 *plane2 = (u32 *)image2;
104
int count = (width * height) >> 1;
107
for (i=0; i<count; i++){
108
plane[i] &= plane2[i];
112
void pdp_imageproc_or_process(void *x, u32 width, u32 height, s16 *image, s16 *image2)
114
u32 *plane = (u32 *)image;
115
u32 *plane2 = (u32 *)image2;
116
int count = (width * height) >> 1;
119
for (i=0; i<count; i++){
120
plane[i] |= plane2[i];
124
void pdp_imageproc_not_process(void *x, u32 width, u32 height, s16 *image)
126
u32 *plane = (u32 *)image;
127
int count = (width * height) >> 1;
130
for (i=0; i<count; i++){
131
plane[i] ^= 0xffffffff;
135
void pdp_imageproc_mask_process(void *x, u32 width, u32 height, s16 *image)
138
u32 *plane = (u32 *)image;
139
int count = (width * height) >> 1;
142
mask = (mask & 0xffff) | (mask << 16);
144
for (i=0; i<count; i++){
149
// produce a plasma image
150
// note: random number generator can be platform specific
151
// however, it should be seeded. (same seed produces the same result)
159
static inline s16 _rand_s16(void)
161
return (s16)(random()<<0);
164
static inline s16 _new_color(s32 one, s32 two, s32 scale)
166
return CLAMP16((one >> 1) + (two >> 1) + ((scale * _rand_s16()) >> 16));
167
//return (one >> 1) + (two >> 1);
170
void *pdp_imageproc_plasma_new(void){return pdp_alloc(sizeof(t_plasma));}
171
void pdp_imageproc_plasma_delete(void *x){pdp_dealloc(x);}
172
void pdp_imageproc_plasma_setseed(void *x, float seed)
174
*((float *)x) = seed;
176
void pdp_imageproc_plasma_setturbulence(void *x, float f)
178
((t_plasma *)x)->scale = CLAMP16(f * ((float)0x7fff));
181
static void _plasma_subdiv(u32 w, u32 h, u32 s, s16 *image, int calc_left, int calc_top, s32 scale)
183
int w0 = ((w-1)>>1); // width of left segments
184
int h0 = ((h-1)>>1); // heigth of top segments
188
/* conditions: w0 <= w1, h0 <= h1 */
190
/* original coordinates */
193
int bottomleft = s * (h-1);
194
int bottomright = bottomleft + topright;
196
/* new subdivision coordinates */
199
int bottom = bottomleft + w0;
200
int right = topright + left;
201
int center = left + top;
203
if (w0 && h0){ /* left-right and top-bottom subdivide */
205
/* calculate corner pixel colours */
206
if (calc_top) image[top] = _new_color(image[topleft], image[topright], scale);
207
if (calc_left) image[left] = _new_color(image[topleft], image[bottomleft], scale);
208
image[right] = _new_color(image[topright], image[bottomright], scale);
209
image[bottom] = _new_color(image[bottomleft], image[bottomright], scale);
210
image[center] = (_new_color(image[top], image[bottom], scale) >> 1)
211
+(_new_color(image[left], image[right], scale) >> 1);
214
/* subdivide (with overlap) */
215
_plasma_subdiv(w0+1, h0+1, s, &image[topleft], 1, 1, scale);
216
_plasma_subdiv(w1, h0+1, s, &image[top], 0, 1, scale);
217
_plasma_subdiv(w0+1, h1, s, &image[left], 1, 0, scale);
218
_plasma_subdiv(w1, h1, s, &image[center], 0, 0, scale);
223
else if(h0) { /* top-bottom subdivide */
227
/* calculate corner pixel colours */
228
if(calc_left) image[left] = _new_color(image[topleft], image[bottomleft], scale);
229
image[right] = _new_color(image[topright], image[bottomright], scale);
231
/* subdivide (without overlap) */
232
_plasma_subdiv(w, h0+1, s, &image[topleft], 1, 0, scale);
233
_plasma_subdiv(w, h1, s, &image[left], 1, 0, scale);
237
else if (w0){ /* left-right subdivide */
239
/* calculate corner pixel colours */
240
if (calc_top) image[top] = _new_color(image[topleft], image[topright], scale);
241
image[bottom] = _new_color(image[bottomleft], image[bottomright],scale);
243
/* subdivide with overlap */
244
_plasma_subdiv(w0+1, h, s, &image[topleft], 0, 1, scale);
245
_plasma_subdiv(w1, h, s, &image[top], 0, 1, scale);
251
void pdp_imageproc_plasma_process(void *x, u32 width, u32 height, s16 *image)
253
s32 scale = (((t_plasma *)x)->scale);
254
srandom (((t_plasma *)x)->seed);
256
/* set initial border colours */
257
image[0] = _rand_s16();
258
image[width-1] = _rand_s16();
259
image[width * (height-1)] = _rand_s16();
260
image[width * height - 1] = _rand_s16();
263
_plasma_subdiv(width, height, width, image, 1, 1, scale);
265
((t_plasma *)x)->seed = random();
271
void pdp_imageproc_zero_process(void *x, u32 width, u32 height, s16 *image)
273
int bytesize = (width * height) << 1;
274
memset(image, 0, bytesize);
277
void pdp_imageproc_constant_process(void *x, u32 width, u32 height, s16 *image)
281
u32 *plane = (u32 *)image;
282
int wordsize = (width * height) >> 1;
283
value = (value & 0xffff) | (value << 16);
284
for (i=0; i<wordsize; i++){
290
/* other stateless operators */
292
/* some 2x16bit vector ops */
294
/* some bit shuffling to ensure 32 bit accesses
295
get the sign bit extended as a mask: - : 0xffff +: 0x0000 */
296
static inline u32 _sign(s32 invec)
298
s32 mask_top = invec;
299
s32 mask_bot = invec;
301
mask_top &= 0x80000000; /* isolate top sign bit */
302
mask_bot <<= 16; /* shift bottom word to top word */
303
mask_bot &= 0x80000000; /* isolate bottom sign bit */
304
mask_top >>= 15; /* shift sign bit into top word */
306
((u32)mask_bot) >>=16; /* shift top word into bottom word */
307
return mask_top |mask_bot;
310
/* clear the least significant bit of the top word
311
to ensure a decoupled vector add */
312
static inline void _decouple(s32 *invec)
314
*invec &= 0xfffeffff;
317
void pdp_imageproc_abs_process(void *x, u32 width, u32 height, s16 *image)
320
s32 *wimage = (s32 *)image;
321
int wsize = (width * height) >> 1;
322
for (i=0; i<wsize; i++){
323
/* this computes c = (c >= 0) ? (c) : (~c) */
324
/* not is used instead of neg to prevent overflow on 0x8000 */
325
/* this maps both 0 and -1 to 0 */
327
wimage[i] ^= _sign(wimage[i]);
332
void pdp_imageproc_zthresh_process(void *x, u32 width, u32 height, s16 *image)
335
s32 *wimage = (s32 *)image;
336
int wsize = (width * height) >> 1;
337
for (i=0; i<wsize; i++){
338
/* this computes c = (c >= 0) ? (c) : (0) */
339
wimage[i] &= ~_sign(wimage[i]);
343
/* hard thresholding: x contains a positive unsigned short int */
344
void pdp_imageproc_hardthresh_process(void *x, u32 width, u32 height, s16 *image)
348
s32 sign1, isign2, a;
349
s32 *wimage = (s32 *)image;
350
int wsize = (width * height) >> 1;
351
thresh |= (thresh << 16);
352
for (i=0; i<wsize; i++){
355
a ^= sign1; /* take abs */
357
a -= thresh; /* subtract threshold */
359
a &= isign2; /* zero thresh */
361
a += thresh & isign2; /* add threshold (if not zero thresholded)*/
367
/* soft thresholding: x contains a positive unsigned short int */
368
void pdp_imageproc_softthresh_process(void *x, u32 width, u32 height, s16 *image)
373
s32 *wimage = (s32 *)image;
374
int wsize = (width * height) >> 1;
375
thresh |= thresh << 16;
376
for (i=0; i<wsize; i++){
379
a ^= sign1; /* take abs */
381
a -= thresh; /* subtract threshold */
383
a &= ~ sign2; /* zero thresh */
385
//a += thresh; /* add threshold */
394
/* turns an image into a positive andmask */
395
void pdp_imageproc_ispositive_process(void *x, u32 width, u32 height, s16 *image)
398
s32 *wimage = (s32 *)image;
399
int wsize = (width * height) >> 1;
400
for (i=0; i<wsize; i++){
401
wimage[i] = ~_sign(wimage[i]);
407
void pdp_imageproc_sign_process(void *x, u32 width, u32 height, s16 *image)
410
s32 *wimage = (s32 *)image;
411
int wsize = (width * height) >> 1;
412
for (i=0; i<wsize; i++){
413
wimage[i] = _sign(wimage[i]) ^ 0x7fff7fff;
418
/* flip left <-> right */
419
void pdp_imageproc_flip_lr_process(void *dummy, u32 width, u32 height, s16 *image)
423
for (y=0; y<height; y++){
425
r = image + width - 1;
438
void pdp_llconv_flip_top_bottom(s16 *data, int width, int height, int pixelsize);
440
void pdp_imageproc_flip_tb_process(void *dummy, u32 width, u32 height, s16 *image)
442
pdp_llconv_flip_top_bottom(image, width, height, 2);
446
/* image processing dispatcher methods */
447
/* if the first packet contains a nonzero channel mask, it will be used instead
448
of the one supplied as argument to the dispatcher functions.
449
the packet's channel mask will be reset to 0 */
451
void pdp_imageproc_dispatch_1buf(void (*process_routine)(void*, u32, u32, s16*), void *x, u32 chanmask, int packet0)
456
unsigned int w,h,d,plane_size,mask;
458
/* if packet is not a valid image return without doing anything */
459
if (!(pdp_packet_image_isvalid(packet0))) return;
461
header0 = pdp_packet_header(packet0);
462
image0 = pdp_packet_image_info(packet0);
463
idata0 = pdp_packet_data (packet0);
470
if (image0->chanmask) chanmask = image0->chanmask;
471
image0->chanmask = 0;
474
switch(image0->encoding){
476
if (chanmask & 1) (*process_routine)(x, w, h, idata0);
479
if (chanmask & 1) (*process_routine)(x, w, h, idata0);
480
idata0 += plane_size;
484
if (chanmask & 2) (*process_routine)(x, w, h, idata0);
485
idata0 += plane_size;
486
if (chanmask & 4) (*process_routine)(x, w, h, idata0);
491
if (chanmask & mask) (*process_routine)(x, w, h, idata0);
492
idata0 += plane_size;
502
void pdp_imageproc_dispatch_2buf(void (*process_routine)(void*, u32, u32, s16*, s16 *), void *x, u32 chanmask, int packet0, int packet1)
506
s16 *idata0, *idata1;
507
unsigned int w,h,d,plane_size,mask;
509
/* if packets are not compatible images, return without doing anything */
510
if (!(pdp_packet_image_compat(packet0, packet1))) return;
512
header0 = pdp_packet_header(packet0);
513
image0 = pdp_packet_image_info(packet0);
514
idata0 = pdp_packet_data (packet0);
515
idata1 = pdp_packet_data (packet1);
522
if (image0->chanmask) chanmask = image0->chanmask;
523
image0->chanmask = 0;
525
switch(image0->encoding){
527
if (chanmask & 1) (*process_routine)(x, w, h, idata0, idata1);
530
if (chanmask & 1) (*process_routine)(x, w, h, idata0, idata1);
531
idata0 += plane_size;
532
idata1 += plane_size;
536
if (chanmask & 2) (*process_routine)(x, w, h, idata0, idata1);
537
idata0 += plane_size;
538
idata1 += plane_size;
539
if (chanmask & 4) (*process_routine)(x, w, h, idata0, idata1);
544
if (chanmask & mask) (*process_routine)(x, w, h, idata0, idata1);
545
idata0 += plane_size;
546
idata1 += plane_size;
554
void pdp_imageproc_dispatch_3buf(void (*process_routine)(void*, u32, u32, s16*, s16 *, s16 *), void *x, u32 chanmask, int packet0, int packet1, int packet2)
558
s16 *idata0, *idata1, *idata2;
559
unsigned int w,h,d,plane_size, mask;
561
/* if packets are not compatible images, return without doing anything */
562
if (!((pdp_packet_image_compat(packet0, packet1))
563
&&(pdp_packet_image_compat(packet0, packet1)))) return;
565
header0 = pdp_packet_header(packet0);
566
image0 = pdp_packet_image_info(packet0);
567
idata0 = pdp_packet_data (packet0);
568
idata1 = pdp_packet_data (packet1);
569
idata2 = pdp_packet_data (packet2);
576
if (image0->chanmask) chanmask = image0->chanmask;
577
image0->chanmask = 0;
579
switch(image0->encoding){
581
if (chanmask & 1)(*process_routine)(x, w, h, idata0, idata1, idata2);
584
if (chanmask & 1)(*process_routine)(x, w, h, idata0, idata1, idata2);
585
idata0 += plane_size;
586
idata1 += plane_size;
587
idata2 += plane_size;
591
if (chanmask & 2)(*process_routine)(x, w, h, idata0, idata1, idata2);
592
idata0 += plane_size;
593
idata1 += plane_size;
594
idata2 += plane_size;
595
if (chanmask & 4)(*process_routine)(x, w, h, idata0, idata1, idata2);
600
if (chanmask & mask) (*process_routine)(x, w, h, idata0, idata1, idata2);
601
idata0 += plane_size;
602
idata1 += plane_size;
603
idata2 += plane_size;