diff options
Diffstat (limited to 'system/image/pdp_imageproc_common.c')
-rw-r--r-- | system/image/pdp_imageproc_common.c | 596 |
1 files changed, 596 insertions, 0 deletions
diff --git a/system/image/pdp_imageproc_common.c b/system/image/pdp_imageproc_common.c new file mode 100644 index 0000000..bc34b79 --- /dev/null +++ b/system/image/pdp_imageproc_common.c @@ -0,0 +1,596 @@ +/* + * Pure Data Packet. common image processing routines. + * Copyright (c) by Tom Schouten <pdp@zzz.kotnet.org> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + + +/* + This file contains common code for (portable) low level image processing objects + pdp_imageproc_* methods + The rest is int pdp_imageproc_<platform>.c + + There are also highlevel dispatcher methods that operate on packets: + pdp_imageproc_dispatch_* methods + +*/ + +#include <stdlib.h> +#include <string.h> +#include <math.h> +#include "pdp.h" + +#define CLAMP16(x) (((x) > 0x7fff) ? 0x7fff : (((x) < -0x7fff) ? -0x7fff : (x))) + +u32 pdp_imageproc_legalwidth(int i) +{ + if (i>1024) return 1024; + if (i>0) return ((((i-1)>>3)+1)<<3); + return 8; + +} + +u32 pdp_imageproc_legalheight(int i) +{ + if (i>1024) return 1024; + if (i>0) return ((((i-1)>>3)+1)<<3); + return 8; +} +u32 pdp_imageproc_legalwidth_round_down(int i) +{ + if (i>1024) return 1024; + if (i>8) return ((i>>3)<<3); + return 8; + +} + +u32 pdp_imageproc_legalheight_round_down(int i) +{ + if (i>1024) return 1024; + if (i>8) return ((i>>3)<<3); + return 8; +} + + + +/* some operations */ + +/* logic operators */ + +void pdp_imageproc_xor_process(void *x, u32 width, u32 height, s16 *image, s16 *image2) +{ + u32 *plane = (u32 *)image; + u32 *plane2 = (u32 *)image2; + int count = (width * height) >> 1; + int i; + + for (i=0; i<count; i++){ + plane[i] ^= plane2[i]; + } +} + +void pdp_imageproc_and_process(void *x, u32 width, u32 height, s16 *image, s16 *image2) +{ + u32 *plane = (u32 *)image; + u32 *plane2 = (u32 *)image2; + int count = (width * height) >> 1; + int i; + + for (i=0; i<count; i++){ + plane[i] &= plane2[i]; + } +} + +void pdp_imageproc_or_process(void *x, u32 width, u32 height, s16 *image, s16 *image2) +{ + u32 *plane = (u32 *)image; + u32 *plane2 = (u32 *)image2; + int count = (width * height) >> 1; + int i; + + for (i=0; i<count; i++){ + plane[i] |= plane2[i]; + } +} + +void pdp_imageproc_not_process(void *x, u32 width, u32 height, s16 *image) +{ + u32 *plane = (u32 *)image; + int count = (width * height) >> 1; + int i; + + for (i=0; i<count; i++){ + plane[i] ^= 0xffffffff; + } +} + +void pdp_imageproc_mask_process(void *x, u32 width, u32 height, s16 *image) +{ + u32 mask = (u32)x; + u32 *plane = (u32 *)image; + int count = (width * height) >> 1; + int i; + + mask = (mask & 0xffff) | (mask << 16); + + for (i=0; i<count; i++){ + plane[i] &= mask; + } +} + +// produce a plasma image +// note: random number generator can be platform specific +// however, it should be seeded. (same seed produces the same result) + +typedef struct +{ + u32 seed; + s32 scale; +} t_plasma; + +static inline s16 _rand_s16(void) +{ + return (s16)(random()<<0); +} + +static inline s16 _new_color(s32 one, s32 two, s32 scale) +{ + return CLAMP16((one >> 1) + (two >> 1) + ((scale * _rand_s16()) >> 16)); + //return (one >> 1) + (two >> 1); +} + +void *pdp_imageproc_plasma_new(void){return pdp_alloc(sizeof(t_plasma));} +void pdp_imageproc_plasma_delete(void *x){pdp_dealloc(x);} +void pdp_imageproc_plasma_setseed(void *x, float seed) +{ + *((float *)x) = seed; +} +void pdp_imageproc_plasma_setturbulence(void *x, float f) +{ + ((t_plasma *)x)->scale = CLAMP16(f * ((float)0x7fff)); +} + +static void _plasma_subdiv(u32 w, u32 h, u32 s, s16 *image, int calc_left, int calc_top, s32 scale) +{ + int w0 = ((w-1)>>1); // width of left segments + int h0 = ((h-1)>>1); // heigth of top segments + int w1 = w - w0; + int h1 = h - h0; + + /* conditions: w0 <= w1, h0 <= h1 */ + + /* original coordinates */ + int topleft = 0; + int topright = w-1; + int bottomleft = s * (h-1); + int bottomright = bottomleft + topright; + + /* new subdivision coordinates */ + int top = w0; + int left = s * h0; + int bottom = bottomleft + w0; + int right = topright + left; + int center = left + top; + + if (w0 && h0){ /* left-right and top-bottom subdivide */ + + /* calculate corner pixel colours */ + if (calc_top) image[top] = _new_color(image[topleft], image[topright], scale); + if (calc_left) image[left] = _new_color(image[topleft], image[bottomleft], scale); + image[right] = _new_color(image[topright], image[bottomright], scale); + image[bottom] = _new_color(image[bottomleft], image[bottomright], scale); + image[center] = (_new_color(image[top], image[bottom], scale) >> 1) + +(_new_color(image[left], image[right], scale) >> 1); + + + /* subdivide (with overlap) */ + _plasma_subdiv(w0+1, h0+1, s, &image[topleft], 1, 1, scale); + _plasma_subdiv(w1, h0+1, s, &image[top], 0, 1, scale); + _plasma_subdiv(w0+1, h1, s, &image[left], 1, 0, scale); + _plasma_subdiv(w1, h1, s, &image[center], 0, 0, scale); + + } + + + else if(h0) { /* top-bottom subdivide */ + + //post("h:%d", h); + + /* calculate corner pixel colours */ + if(calc_left) image[left] = _new_color(image[topleft], image[bottomleft], scale); + image[right] = _new_color(image[topright], image[bottomright], scale); + + /* subdivide (without overlap) */ + _plasma_subdiv(w, h0+1, s, &image[topleft], 1, 0, scale); + _plasma_subdiv(w, h1, s, &image[left], 1, 0, scale); + + } + + else if (w0){ /* left-right subdivide */ + + /* calculate corner pixel colours */ + if (calc_top) image[top] = _new_color(image[topleft], image[topright], scale); + image[bottom] = _new_color(image[bottomleft], image[bottomright],scale); + + /* subdivide with overlap */ + _plasma_subdiv(w0+1, h, s, &image[topleft], 0, 1, scale); + _plasma_subdiv(w1, h, s, &image[top], 0, 1, scale); + + } + +} + +void pdp_imageproc_plasma_process(void *x, u32 width, u32 height, s16 *image) +{ + s32 scale = (((t_plasma *)x)->scale); + srandom (((t_plasma *)x)->seed); + + /* set initial border colours */ + image[0] = _rand_s16(); + image[width-1] = _rand_s16(); + image[width * (height-1)] = _rand_s16(); + image[width * height - 1] = _rand_s16(); + + /* subdivide */ + _plasma_subdiv(width, height, width, image, 1, 1, scale); + + ((t_plasma *)x)->seed = random(); + +} + + + +void pdp_imageproc_zero_process(void *x, u32 width, u32 height, s16 *image) +{ + int bytesize = (width * height) << 1; + memset(image, 0, bytesize); +} + +void pdp_imageproc_constant_process(void *x, u32 width, u32 height, s16 *image) +{ + int i; + u32 value = (u32)x; + u32 *plane = (u32 *)image; + int wordsize = (width * height) >> 1; + value = (value & 0xffff) | (value << 16); + for (i=0; i<wordsize; i++){ + plane[i] = value; + } +} + + +/* other stateless operators */ + +/* some 2x16bit vector ops */ + +/* some bit shuffling to ensure 32 bit accesses + get the sign bit extended as a mask: - : 0xffff +: 0x0000 */ +static inline u32 _sign(s32 invec) +{ + s32 mask_top = invec; + s32 mask_bot = invec; + + mask_top &= 0x80000000; /* isolate top sign bit */ + mask_bot <<= 16; /* shift bottom word to top word */ + mask_bot &= 0x80000000; /* isolate bottom sign bit */ + mask_top >>= 15; /* shift sign bit into top word */ + mask_bot >>= 15; + ((u32)mask_bot) >>=16; /* shift top word into bottom word */ + return mask_top |mask_bot; +} + +/* clear the least significant bit of the top word + to ensure a decoupled vector add */ +static inline void _decouple(s32 *invec) +{ + *invec &= 0xfffeffff; +} + +void pdp_imageproc_abs_process(void *x, u32 width, u32 height, s16 *image) +{ + int i; + s32 *wimage = (s32 *)image; + int wsize = (width * height) >> 1; + for (i=0; i<wsize; i++){ + /* this computes c = (c >= 0) ? (c) : (~c) */ + /* not is used instead of neg to prevent overflow on 0x8000 */ + /* this maps both 0 and -1 to 0 */ + + wimage[i] ^= _sign(wimage[i]); + + } +} + +void pdp_imageproc_zthresh_process(void *x, u32 width, u32 height, s16 *image) +{ + int i; + s32 *wimage = (s32 *)image; + int wsize = (width * height) >> 1; + for (i=0; i<wsize; i++){ + /* this computes c = (c >= 0) ? (c) : (0) */ + wimage[i] &= ~_sign(wimage[i]); + } +} + +/* hard thresholding: x contains a positive unsigned short int */ +void pdp_imageproc_hardthresh_process(void *x, u32 width, u32 height, s16 *image) +{ + int i; + s32 thresh = (s32)x; + s32 sign1, isign2, a; + s32 *wimage = (s32 *)image; + int wsize = (width * height) >> 1; + thresh |= (thresh << 16); + for (i=0; i<wsize; i++){ + a = wimage[i]; + sign1 = _sign(a); + a ^= sign1; /* take abs */ + _decouple(&a); + a -= thresh; /* subtract threshold */ + isign2 = ~ _sign(a); + a &= isign2; /* zero thresh */ + _decouple(&a); + a += thresh & isign2; /* add threshold (if not zero thresholded)*/ + a ^= sign1; + wimage[i] = a; + } +} + +/* soft thresholding: x contains a positive unsigned short int */ +void pdp_imageproc_softthresh_process(void *x, u32 width, u32 height, s16 *image) +{ + int i; + s32 thresh = (s32)x; + s32 sign1, sign2, a; + s32 *wimage = (s32 *)image; + int wsize = (width * height) >> 1; + thresh |= thresh << 16; + for (i=0; i<wsize; i++){ + a = wimage[i]; + sign1 = _sign(a); + a ^= sign1; /* take abs */ + _decouple(&a); + a -= thresh; /* subtract threshold */ + sign2 = _sign(a); + a &= ~ sign2; /* zero thresh */ + _decouple(&a); + //a += thresh; /* add threshold */ + a ^= sign1; + wimage[i] = a; + + } + +} + + +/* turns an image into a positive andmask */ +void pdp_imageproc_ispositive_process(void *x, u32 width, u32 height, s16 *image) +{ + int i; + s32 *wimage = (s32 *)image; + int wsize = (width * height) >> 1; + for (i=0; i<wsize; i++){ + wimage[i] = ~_sign(wimage[i]); + } + +} + +/* get sign */ +void pdp_imageproc_sign_process(void *x, u32 width, u32 height, s16 *image) +{ + int i; + s32 *wimage = (s32 *)image; + int wsize = (width * height) >> 1; + for (i=0; i<wsize; i++){ + wimage[i] = _sign(wimage[i]) ^ 0x7fff7fff; + } + +} + +/* flip left <-> right */ +void pdp_imageproc_flip_lr_process(void *dummy, u32 width, u32 height, s16 *image) +{ + u32 y; + s16 tmp, *l, *r; + for (y=0; y<height; y++){ + l = image; + r = image + width - 1; + while (l < r){ + tmp = *l; + *l = *r; + *r = tmp; + l++; + r--; + } + image += width; + } + +} + +void pdp_llconv_flip_top_bottom(s16 *data, int width, int height, int pixelsize); + +void pdp_imageproc_flip_tb_process(void *dummy, u32 width, u32 height, s16 *image) +{ + pdp_llconv_flip_top_bottom(image, width, height, 2); +} + + +/* image processing dispatcher methods */ +/* if the first packet contains a nonzero channel mask, it will be used instead + of the one supplied as argument to the dispatcher functions. + the packet's channel mask will be reset to 0 */ + +void pdp_imageproc_dispatch_1buf(void (*process_routine)(void*, u32, u32, s16*), void *x, u32 chanmask, int packet0) +{ + t_pdp *header0; + t_image *image0; + s16 *idata0; + unsigned int w,h,d,plane_size,mask; + + /* if packet is not a valid image return without doing anything */ + if (!(pdp_packet_image_isvalid(packet0))) return; + + header0 = pdp_packet_header(packet0); + image0 = pdp_packet_image_info(packet0); + idata0 = pdp_packet_data (packet0); + + w = image0->width; + h = image0->height; + d = image0->depth; + plane_size = w*h; + + if (image0->chanmask) chanmask = image0->chanmask; + image0->chanmask = 0; + + + switch(image0->encoding){ + case PDP_IMAGE_GREY: + if (chanmask & 1) (*process_routine)(x, w, h, idata0); + break; + case PDP_IMAGE_YV12: + if (chanmask & 1) (*process_routine)(x, w, h, idata0); + idata0 += plane_size; + plane_size >>= 2; + w >>= 1; + h >>= 1; + if (chanmask & 2) (*process_routine)(x, w, h, idata0); + idata0 += plane_size; + if (chanmask & 4) (*process_routine)(x, w, h, idata0); + break; + case PDP_IMAGE_MCHP: + mask = 1; + while (d--){ + if (chanmask & mask) (*process_routine)(x, w, h, idata0); + idata0 += plane_size; + mask <<= 1; + } + break; + default: + break; + } +} + + +void pdp_imageproc_dispatch_2buf(void (*process_routine)(void*, u32, u32, s16*, s16 *), void *x, u32 chanmask, int packet0, int packet1) +{ + t_pdp *header0; + t_image *image0; + s16 *idata0, *idata1; + unsigned int w,h,d,plane_size,mask; + + /* if packets are not compatible images, return without doing anything */ + if (!(pdp_packet_image_compat(packet0, packet1))) return; + + header0 = pdp_packet_header(packet0); + image0 = pdp_packet_image_info(packet0); + idata0 = pdp_packet_data (packet0); + idata1 = pdp_packet_data (packet1); + + w = image0->width; + h = image0->height; + d = image0->depth; + plane_size = w*h; + + if (image0->chanmask) chanmask = image0->chanmask; + image0->chanmask = 0; + + switch(image0->encoding){ + case PDP_IMAGE_GREY: + if (chanmask & 1) (*process_routine)(x, w, h, idata0, idata1); + break; + case PDP_IMAGE_YV12: + if (chanmask & 1) (*process_routine)(x, w, h, idata0, idata1); + idata0 += plane_size; + idata1 += plane_size; + plane_size >>= 2; + w >>= 1; + h >>= 1; + if (chanmask & 2) (*process_routine)(x, w, h, idata0, idata1); + idata0 += plane_size; + idata1 += plane_size; + if (chanmask & 4) (*process_routine)(x, w, h, idata0, idata1); + break; + case PDP_IMAGE_MCHP: + mask = 1; + while (d--){ + if (chanmask & mask) (*process_routine)(x, w, h, idata0, idata1); + idata0 += plane_size; + idata1 += plane_size; + mask <<= 1; + } + break; + default: + break; + } +} +void pdp_imageproc_dispatch_3buf(void (*process_routine)(void*, u32, u32, s16*, s16 *, s16 *), void *x, u32 chanmask, int packet0, int packet1, int packet2) +{ + t_pdp *header0; + t_image *image0; + s16 *idata0, *idata1, *idata2; + unsigned int w,h,d,plane_size, mask; + + /* if packets are not compatible images, return without doing anything */ + if (!((pdp_packet_image_compat(packet0, packet1)) + &&(pdp_packet_image_compat(packet0, packet1)))) return; + + header0 = pdp_packet_header(packet0); + image0 = pdp_packet_image_info(packet0); + idata0 = pdp_packet_data (packet0); + idata1 = pdp_packet_data (packet1); + idata2 = pdp_packet_data (packet2); + + w = image0->width; + h = image0->height; + d = image0->depth; + plane_size = w*h; + + if (image0->chanmask) chanmask = image0->chanmask; + image0->chanmask = 0; + + switch(image0->encoding){ + case PDP_IMAGE_GREY: + if (chanmask & 1)(*process_routine)(x, w, h, idata0, idata1, idata2); + break; + case PDP_IMAGE_YV12: + if (chanmask & 1)(*process_routine)(x, w, h, idata0, idata1, idata2); + idata0 += plane_size; + idata1 += plane_size; + idata2 += plane_size; + plane_size >>= 2; + w >>= 1; + h >>= 1; + if (chanmask & 2)(*process_routine)(x, w, h, idata0, idata1, idata2); + idata0 += plane_size; + idata1 += plane_size; + idata2 += plane_size; + if (chanmask & 4)(*process_routine)(x, w, h, idata0, idata1, idata2); + break; + case PDP_IMAGE_MCHP: + mask = 1; + while (d--){ + if (chanmask & mask) (*process_routine)(x, w, h, idata0, idata1, idata2); + idata0 += plane_size; + idata1 += plane_size; + idata2 += plane_size; + mask <<= 1; + } + break; + default: + break; + } +} |