/* cluster.c * Copyright (C) 2008 binarymillenium * This file is a Frei0r plugin. * * 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. */ #include #include #include #include #include "../frei0r.h" #define MAXNUM 40 struct cluster_center { int x; int y; int max_x; int min_x; int max_y; int min_y; /// old max min vals int omax_x; int omin_x; int omax_y; int omin_y; unsigned char r; unsigned char g; unsigned char b; /// aggregate color and positions float aggr_r; float aggr_g; float aggr_b; float aggr_x; float aggr_y; /// number of pixels in the cluster float numpix; }; typedef struct cluster_instance { unsigned int width; unsigned int height; /// number of clusters, must be smaller than maxnum unsigned int num; float dist_weight; //float color_weight; struct cluster_center clusters[MAXNUM]; int initted; } cluster_instance_t; /* Clamps a int32-range int between 0 and 255 inclusive. */ unsigned char CLAMP0255(int32_t a) { return (unsigned char) ( (((-a) >> 31) & a) // 0 if the number was negative | (255 - a) >> 31); // -1 if the number was greater than 255 } int f0r_init() { return 1; } void f0r_deinit() { /* no initialization required */ } void f0r_get_plugin_info(f0r_plugin_info_t* inverterInfo) { inverterInfo->name = "K-Means Clustering"; inverterInfo->author = "binarymillenium"; inverterInfo->plugin_type = F0R_PLUGIN_TYPE_FILTER; inverterInfo->color_model = F0R_COLOR_MODEL_BGRA8888; inverterInfo->frei0r_version = FREI0R_MAJOR_VERSION; inverterInfo->major_version = 0; inverterInfo->minor_version = 1; inverterInfo->num_params = 2; inverterInfo->explanation = "Clusters of a source image by color and spatial distance"; } void f0r_get_param_info(f0r_param_info_t* info, int param_index) { switch(param_index) { case 0: info->name = "Num"; info->type = F0R_PARAM_DOUBLE; info->explanation = "The number of clusters"; break; case 1: info->name = "Dist weight"; info->type = F0R_PARAM_DOUBLE; info->explanation = "The weight on distance"; break; #if 0 case 2: info->name = "Color weight"; info->type = F0R_PARAM_DOUBLE; info->explanation = "The weight on color"; break; #endif } } f0r_instance_t f0r_construct(unsigned int width, unsigned int height) { cluster_instance_t* inst = (cluster_instance_t*)malloc(sizeof(cluster_instance_t)); inst->width = width; inst->height = height; inst->num = MAXNUM/2; inst->dist_weight = 0.5; //inst->color_weight = 1.0; int k; for (k = 0; k < MAXNUM; k++) { struct cluster_center* cc = &inst->clusters[k]; int x = rand()%inst->width; int y = rand()%inst->height; cc->x = x; cc->y = y; /* const unsigned char* src2 = (unsigned char*)(&inframe[x+inst->width*y]); inst->clusters[k].r = src2[0]; inst->clusters[k].g = src2[1]; inst->clusters[k].b = src2[2]; */ inst->clusters[k].r = rand()%255; inst->clusters[k].g = rand()%255; inst->clusters[k].b = rand()%255; cc->numpix = 0; cc->aggr_x = 0; cc->aggr_y = 0; cc->aggr_r = 0; cc->aggr_g = 0; cc->aggr_b = 0; cc->omax_x = inst->width; cc->omax_y = inst->height; cc->omin_x = 0; cc->omin_y = 0; cc->max_x = 0; cc->max_y = 0; cc->min_x = inst->width; cc->min_y = inst->height; } return (f0r_instance_t)inst; } void f0r_destruct(f0r_instance_t instance) { free(instance); } void f0r_set_param_value(f0r_instance_t instance, f0r_param_t param, int param_index) { assert(instance); cluster_instance_t* inst = (cluster_instance_t*)instance; switch(param_index) { int val; float fval; case 0: /* val is 0-1.0 */ fval = ((*((double*)param) )); val = (int) (fval*MAXNUM); if (val > MAXNUM) val = MAXNUM; if (val < 0) val = 0; if (val != inst->num) { inst->num = val; } break; case 1: /* val is 0-1.0 */ //fval = 2.0 * ((*((double*)param) ) - 0.5); fval = ((*((double*)param) ) ); if (fval != inst->dist_weight) { inst->dist_weight = fval; } break; #if 0 case 2: /* val is 0-1.0 */ //fval = 2.0 * ((*((double*)param) ) - 0.5); fval = ((*((double*)param) ) ); if (fval != inst->color_weight) { inst->color_weight = fval; } break; #endif } } void f0r_get_param_value(f0r_instance_t instance, f0r_param_t param, int param_index) { assert(instance); cluster_instance_t* inst = (cluster_instance_t*)instance; switch(param_index) { case 0: *((double*)param) = (double) ( (inst->num) )/MAXNUM; break; case 1: *((double*)param) = (double) ( (inst->dist_weight)); break; } } float find_dist( int r1, int g1, int b1, int x1, int y1, int r2, int g2, int b2, int x2, int y2, float max_space_dist, float dist_weight) //, float color_weight) { /// make this a define? float max_color_dist = sqrtf(255*255*3); float dr = r1-r2; float dg = g1-g2; float db = b1-b2; float color_dist = sqrtf(dr*dr + dg*dg + db*db)/max_color_dist; float dx = x1-x2; float dy = y1-y2; float space_dist = sqrtf(dx*dx + dy*dy)/max_space_dist; /// add parameter weighting later //return sqrtf(color_weight*color_dist*color_dist + dist_weight*space_dist*space_dist); return sqrtf((1.0-dist_weight)*color_dist*color_dist + dist_weight*space_dist*space_dist); } void f0r_update(f0r_instance_t instance, double time, const uint32_t* inframe, uint32_t* outframe) { assert(instance); cluster_instance_t* inst = (cluster_instance_t*)instance; int x,y,k; float max_space_dist = sqrtf(inst->width*inst->width + inst->height*inst->height); /* if (inst->has_initted) { inst->has_initted = true; } */ for (y=0; y < inst->height; ++y) { for (x=0; x < inst->width; ++x) { const unsigned char* src2 = (unsigned char*)( &inframe[x+inst->width*y]); unsigned char* dst2 = (unsigned char*)(&outframe[x+inst->width*y]); float dist = max_space_dist; int dist_ind = 0; for (k = 0; k < inst->num; k++) { struct cluster_center cc = inst->clusters[k]; if ((x < cc.omax_x*1.3+5) && (x > cc.omin_x*0.7-5) && (y < cc.omax_y*1.3+5) && (y > cc.omin_y*0.7-5)) { float kdist = find_dist(src2[0], src2[1], src2[2], x,y, cc.r, cc.g, cc.b, cc.x, cc.y, max_space_dist, inst->dist_weight); //, inst->color_weight); if (kdist < dist) { dist = kdist; dist_ind = k; } } } struct cluster_center* cc = &inst->clusters[dist_ind]; if (x > cc->max_x) cc->max_x = x; if (x < cc->min_x) cc->min_x = x; if (y > cc->max_y) cc->max_y = y; if (y < cc->min_y) cc->min_y = y; cc->aggr_x += x; cc->aggr_y += y; cc->aggr_r += src2[0]; cc->aggr_g += src2[1]; cc->aggr_b += src2[2]; cc->numpix += 1.0; dst2[0] = cc->r; dst2[1] = cc->g; dst2[2] = cc->b; } } /// update cluster_centers for (k = 0; k < inst->num; k++) { struct cluster_center* cc = &inst->clusters[k]; if (cc->numpix > 0) { cc->x = (int) (cc->aggr_x/cc->numpix); cc->y = (int) (cc->aggr_y/cc->numpix); cc->r = (unsigned char) (cc->aggr_r/cc->numpix); cc->g = (unsigned char) (cc->aggr_g/cc->numpix); cc->b = (unsigned char) (cc->aggr_b/cc->numpix); //printf("%d, %d %d %d\t", k, (unsigned int)cc->r, (unsigned int)cc->g, (unsigned int)cc->b); //printf("%g, %g %g %g\n", cc->numpix, cc->aggr_r, cc->aggr_g, cc->aggr_b); } cc->numpix = 0; cc->aggr_x = 0; cc->aggr_y = 0; cc->aggr_r = 0; cc->aggr_g = 0; cc->aggr_b = 0; cc->omax_x = cc->max_x; cc->omax_y = cc->max_y; cc->omin_x = cc->min_x; cc->omin_y = cc->min_y; cc->max_x = 0; cc->max_y = 0; cc->min_x = inst->width; cc->min_y = inst->height; } //printf("\n"); }