/* Description: This program is a plugin for the Blender sequence editor. It applies an unsharp mask to one strip. Author: Andrew McCargar (andrew@outsideworld.org) Website: http://www.outsideworld.org/projects/blender_plugins.html code used from the Gimp unsharp filter: * http://www.steppe.com/~winston/gimp/unsharp.html * * Copyright (C) 1999 Winston Chang * * * * 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. Last Modified: Thus Dec 23 23:41:35 EST 2009 */ #include "math.h" #include "plugin.h" char name[24]= "Unsharp mask"; /* structure for buttons, * butcode name default min max 0 */ VarStruct varstr[]= { LABEL, "Unsharp mask", 0.0, 0.0, 0.0, "", NUMSLI|FLO, "Radius ", 5.0, 0.0, 20.0, "Size of the edges to be enhanced", NUMSLI|FLO, "Amount ", 0.5, 0.0, 1.0, "magnatude of edge contrast", NUMSLI|INT, "Threshold ", 0.0, 0.0, 255.0, "minimum brightness change that will be sharpened", TOG|INT, "Y filter", 1.0, 0.0, 1.0, "filter along y as well as x axis (slower but better)", }; /* The cast struct is for input in the main doit function Varstr and Cast must have the same variables in the same order */ typedef struct Cast { int dummy; /* because of the 'label' button */ float radius; float amount; int threshold; int yfilter; } Cast; /* cfra: the current frame */ float cfra; void plugin_seq_doit(Cast *, float, float, int, int, ImBuf *, ImBuf *, ImBuf *, ImBuf *); int plugin_seq_getversion(void) { return B_PLUGIN_VERSION; } void plugin_but_changed(int but) { } void plugin_init() { } void plugin_getinfo(PluginInfo *info) { info->name= name; info->nvars= sizeof(varstr)/sizeof(VarStruct); info->cfra= &cfra; info->varstr= varstr; info->init= plugin_init; info->seq_doit= (SeqDoit) plugin_seq_doit; info->callback= plugin_but_changed; } /* local function prototypes */ static inline void blur_line (double* ctable, double* cmatrix, int cmatrix_length, char* cur_col, char* dest_col, int y, long bytes); static double* gen_lookup_table(double* cmatrix, int cmatrix_length); static int gen_convolve_matrix(double radius, double** cmatrix_p); static inline int round2int(double i); void merge_bufs(char *source, char *dest, float amount, int threshold, int height, int width); /* end of local function prototypes */ void plugin_seq_doit(Cast *cast, float facf0, float facf1, int width, int height, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *outbuf, ImBuf *use) { char *in1= (char *)ibuf1->rect; char *out= (char *)outbuf->rect; int length = (width * 4); char *cur_row = (char *) malloc (length); char *dest_row = (char *) malloc (length); char *cur_col = (char *) malloc (height); char *dest_col = (char *) malloc (height); int x, y; /* counter variables */ double *cmatrix = NULL; int cmatrix_length; double *ctable; /* generate convolution matrix and make sure it's smaller than each dimension */ cmatrix_length = gen_convolve_matrix(cast->radius, &cmatrix); /* generate lookup table */ ctable = gen_lookup_table(cmatrix, cmatrix_length); /* blur the rows */ for (y=0;yyfilter) { for (x=0;xrect, (char *)outbuf->rect, (cast->amount * facf0), cast->threshold, height, width); /* free the memory we took */ free(cur_row); free(dest_row); free(cur_col); free(dest_col); free(cmatrix); free(ctable); } static inline void blur_line (double* ctable, double* cmatrix, int cmatrix_length, char* cur_col, char* dest_col, int y, long bytes) { double scale; double sum; int i=0, j=0; int row; int cmatrix_middle = cmatrix_length/2; double *cmatrix_p; char *cur_col_p; char *cur_col_p1; char *dest_col_p; double *ctable_p; /* this first block is the same as the non-optimized version -- * it is only used for very small pictures, so speed isn't a * big concern. */ if (cmatrix_length > y) { for (row = 0; row < y ; row++) { scale=0; /* find the scale factor */ for (j = 0; j < y ; j++) { /* if the index is in bounds, add it to the scale counter */ if ((j + cmatrix_length/2 - row >= 0) && (j + cmatrix_length/2 - row < cmatrix_length)) scale += cmatrix[j + cmatrix_length/2 - row]; } for (i = 0; i= row - cmatrix_length/2) && (j <= row + cmatrix_length/2) ) sum += cur_col[j*bytes + i] * cmatrix[j]; } dest_col[row*bytes + i] = (char)round2int(sum / scale); } } } else { /* for the edge condition, we only use available info and scale to one */ for (row = 0; row < cmatrix_middle; row++) { /* find scale factor */ scale=0; for (j = cmatrix_middle - row; j0; j--) { sum += *(ctable_p + *cur_col_p1); cur_col_p1 += bytes; ctable_p += 256; } cur_col_p++; *(dest_col_p++) = round2int(sum); } } /* for the edge condition , we only use available info, and scale to one */ for ( ; row < y; row++) { /* find scale factor */ scale=0; for (j = 0; j< y-row + cmatrix_middle; j++) scale += cmatrix[j]; for (i = 0; i 255) *dest++ = 255; else *dest++ = value; } *dest++ = *source++; /*copy over the alpha channel */ } } }