/*
sharpness.c
This frei0r plugin is a port of Mplayer's unsharp mask filter
original by by Remi Guyomarch <rguyom@pobox.com>
Version 0.1 jul 2010
Copyright (C) 2010 Marko Cebokli http://lea.hamradio.si/~s57uuu
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.
*/
//compile: gcc -c -fPIC -Wall sharpness.c -o sharpness.o
//link: gcc -shared -o sharpness.so sharpness.o
//#include <stdio.h>
#include <frei0r.h>
#include <stdlib.h>
//#include <math.h>
#include <assert.h>
#include <string.h>
#define MIN_MATRIX_SIZE 3
#define MAX_MATRIX_SIZE 63
typedef struct FilterParam {
int msizeX, msizeY;
double amount;
uint32_t *SC[MAX_MATRIX_SIZE-1];
} FilterParam;
//----------------------------------------
//struktura za instanco efekta
typedef struct
{
int h;
int w;
FilterParam fp;
int size,ac;
unsigned char *Rplani,*Gplani,*Bplani,*Rplano,*Gplano,*Bplano;
} inst;
//========================================================
//unsharp() function from Mplayer unsharp filter
//by Remi Guyomarch <rguyom@pobox.com>
/* This code is based on :
An Efficient algorithm for Gaussian blur using finite-state machines
Frederick M. Waltz and John W. V. Miller
SPIE Conf. on Machine Vision Systems for Inspection and Metrology VII
Originally published Boston, Nov 98
*/
void unsharp( uint8_t *dst, uint8_t *src, int dstStride, int srcStride, int width, int height, FilterParam *fp ) {
uint32_t **SC = fp->SC;
uint32_t SR[MAX_MATRIX_SIZE-1], Tmp1, Tmp2;
uint8_t* src2 = src; // avoid gcc warning
int32_t res;
int x, y, z;
int amount = fp->amount * 65536.0;
int stepsX = fp->msizeX/2;
int stepsY = fp->msizeY/2;
int scalebits = (stepsX+stepsY)*2;
int32_t halfscale = 1 << ((stepsX+stepsY)*2-1);
if( !fp->amount ) {
if( src == dst )
return;
if( dstStride == srcStride )
// fast_memcpy( dst, src, srcStride*height );
memcpy( dst, src, srcStride*height );
else
for( y=0; y<height; y++, dst+=dstStride, src+=srcStride )
// fast_memcpy( dst, src, width );
memcpy( dst, src, width );
return;
}
for( y=0; y<2*stepsY; y++ )
memset( SC[y], 0, sizeof(SC[y][0]) * (width+2*stepsX) );
for( y=-stepsY; y<height+stepsY; y++ ) {
if( y < height ) src2 = src;
memset( SR, 0, sizeof(SR[0]) * (2*stepsX-1) );
for( x=-stepsX; x<width+stepsX; x++ ) {
Tmp1 = x<=0 ? src2[0] : x>=width ? src2[width-1] : src2[x];
for( z=0; z<stepsX*2; z+=2 ) {
Tmp2 = SR[z+0] + Tmp1; SR[z+0] = Tmp1;
Tmp1 = SR[z+1] + Tmp2; SR[z+1] = Tmp2;
}
for( z=0; z<stepsY*2; z+=2 ) {
Tmp2 = SC[z+0][x+stepsX] + Tmp1; SC[z+0][x+stepsX] = Tmp1;
Tmp1 = SC[z+1][x+stepsX] + Tmp2; SC[z+1][x+stepsX] = Tmp2;
}
if( x>=stepsX && y>=stepsY ) {
uint8_t* srx = src - stepsY*srcStride + x - stepsX;
uint8_t* dsx = dst - stepsY*dstStride + x - stepsX;
res = (int32_t)*srx + ( ( ( (int32_t)*srx - (int32_t)((Tmp1+halfscale) >> scalebits) ) * amount ) >> 16 );
*dsx = res>255 ? 255 : res<0 ? 0 : (uint8_t)res;
}
}
if( y >= 0 ) {
dst += dstStride;
src += srcStride;
}
}
}
//-----------------------------------------------------
//stretch [0...1] to parameter range [min...max] linear
float map_value_forward(double v, float min, float max)
{
return min+(max-min)*v;
}
//-----------------------------------------------------
//collapse from parameter range [min...max] to [0...1] linear
double map_value_backward(float v, float min, float max)
{
return (v-min)/(max-min);
}
//***********************************************
// OBVEZNE FREI0R FUNKCIJE
//-----------------------------------------------
int f0r_init()
{
return 1;
}
//------------------------------------------------
void f0r_deinit()
{
}
//-----------------------------------------------
void f0r_get_plugin_info(f0r_plugin_info_t* info)
{
info->name="Sharpness";
info->author="Marko Cebokli, Remi Guyomarch";
info->plugin_type=F0R_PLUGIN_TYPE_FILTER;
info->color_model=F0R_COLOR_MODEL_RGBA8888;
info->frei0r_version=FREI0R_MAJOR_VERSION;
info->major_version=0;
info->minor_version=2;
info->num_params=2;
info->explanation="Unsharp masking (port from Mplayer)";
}
//--------------------------------------------------
void f0r_get_param_info(f0r_param_info_t* info, int param_index)
{
switch(param_index)
{
case 0:
info->name = "Amount";
info->type = F0R_PARAM_DOUBLE;
info->explanation = "";
break;
case 1:
info->name = "Size";
info->type = F0R_PARAM_DOUBLE;
info->explanation = "";
break;
}
}
//----------------------------------------------
f0r_instance_t f0r_construct(unsigned int width, unsigned int height)
{
inst *in;
int z;
in=calloc(1,sizeof(inst));
in->w=width;
in->h=height;
in->Rplani=calloc(width*height,sizeof(unsigned char));
in->Gplani=calloc(width*height,sizeof(unsigned char));
in->Bplani=calloc(width*height,sizeof(unsigned char));
in->Rplano=calloc(width*height,sizeof(unsigned char));
in->Gplano=calloc(width*height,sizeof(unsigned char));
in->Bplano=calloc(width*height,sizeof(unsigned char));
//defaults
in->fp.amount=0.0;
in->size=3;
in->fp.msizeX=3;
in->fp.msizeY=3;
in->ac=0;
memset(in->fp.SC,0,sizeof(in->fp.SC));
for( z=0; z<in->fp.msizeY; z++ )
in->fp.SC[z] = calloc(in->w+in->fp.msizeX , sizeof(*(in->fp.SC[z])));
return (f0r_instance_t)in;
}
//---------------------------------------------------
void f0r_destruct(f0r_instance_t instance)
{
inst *in;
int i;
in=(inst*)instance;
free(in->Rplani);
free(in->Gplani);
free(in->Bplani);
free(in->Rplano);
free(in->Gplano);
free(in->Bplano);
for (i=0;i<in->fp.msizeY;i++) free(in->fp.SC[i]);
free(instance);
}
//-----------------------------------------------------
void f0r_set_param_value(f0r_instance_t instance, f0r_param_t parm, int param_index)
{
inst *p;
double tmpf;
int tmpi,chg,z;
p=(inst*)instance;
chg=0;
switch(param_index)
{
case 0:
tmpf=map_value_forward(*((double*)parm), -1.5, 3.5);
if (tmpf!=p->fp.amount) chg=1;
p->fp.amount=tmpf;
break;
case 1:
tmpi=map_value_forward(*((double*)parm), 3.0, 11.0);
if (p->size != tmpi) chg=1;
p->size=tmpi;
break;
}
if (chg==0) return;
for( z=0; z<p->fp.msizeY; z++ )
free(p->fp.SC[z]);
p->fp.msizeX=p->size;
p->fp.msizeY=p->size;
memset(p->fp.SC,0,sizeof(p->fp.SC));
for( z=0; z<p->fp.msizeY; z++ )
p->fp.SC[z] = calloc(p->w+p->fp.msizeX , sizeof(*(p->fp.SC[z])));
}
//--------------------------------------------------
void f0r_get_param_value(f0r_instance_t instance, f0r_param_t param, int param_index)
{
inst *p;
p=(inst*)instance;
switch(param_index)
{
case 0:
*((double*)param)=map_value_backward(p->fp.amount, -1.5, 3.5);
break;
case 1:
*((double*)param)=map_value_backward(p->size, 3.0, 11.0);
break;
}
}
//-------------------------------------------------
void f0r_update(f0r_instance_t instance, double time, const uint32_t* inframe, uint32_t* outframe)
{
inst *in;
int i;
assert(instance);
in=(inst*)instance;
//Frei0r works with packed color, Mplayer with planar color
for (i=0;i<(in->w*in->h);i++) //copy to planar
{
in->Rplani[i]=inframe[i]&255;
in->Gplani[i]=(inframe[i]>>8)&255;
in->Bplani[i]=(inframe[i]>>16)&255;
}
unsharp(in->Rplano, in->Rplani, in->w, in->w, in->w, in->h, &in->fp);
unsharp(in->Gplano, in->Gplani, in->w, in->w, in->w, in->h, &in->fp);
unsharp(in->Bplano, in->Bplani, in->w, in->w, in->w, in->h, &in->fp);
for (i=0;i<(in->w*in->h);i++) //copy to packed, preserve alpha
{
outframe[i]=((uint32_t)in->Rplano[i])|((uint32_t)in->Gplano[i]<<8)|((uint32_t)in->Bplano[i]<<16)|(inframe[i]&0xFF000000);
}
}