1 /* defish0r.c
2 
3  * Copyright (C) 2010 Marko Cebokli   http://lea.hamradio.si/~s57uuu
4  * This file is a Frei0r plugin.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  */
20 
21 
22 
23 //compile:	gcc -Wall -std=c99 -c -fPIC defish0r.c -o defish0r.o
24 
25 //link: gcc -lm -shared -o defish0r.so defish0r.o
26 
27 //skaliranje za center=1 se ne dela!!!!
28 
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <math.h>
32 
33 #include <frei0r.h>
34 
35 #include "interp.h"
36 
37 
38 double PI=3.14159265358979;
39 
40 //---------------------------------------------------------
41 //	r = 0...1    izhod = 0...maxr
42 //ta funkcija da popacenje v odvisnosti od r
fish(int n,float r,float f)43 float fish(int n, float r, float f)
44 {
45 	float rr,ff;
46 
47 	//printf("ff=%f\n",ff);
48 	switch (n)
49 	{
50 	case 0:		//equidistant
51 		ff=f*2.0/PI;
52 		rr=tanf(r/ff);
53 		break;
54 	case 1:		//ortographic
55 		ff=r/f;
56 		if (ff>1.0)
57 			rr=-1.0;
58 		else
59 			rr=tanf(asinf(ff));
60 		break;
61 	case 2:		//equiarea
62 		ff=r/2.0/f;
63 		if (ff>1.0)
64 			rr=-1.0;
65 		else
66 			rr=tanf(2.0*asinf(r/2.0/f));
67 		break;
68 	case 3:		//stereographic
69 		ff=f*2.0/PI;
70 		rr=tanf(2.0*atanf(r/2.0/ff));
71 		break;
72 	default:
73 		//		printf("Neznana fishitvena funkcija %d\n",n);
74 		break;
75 	}
76 	return rr;
77 }
78 
79 //---------------------------------------------------------
80 //ta funkcija da popacenje v odvisnosti od r
81 //	r = 0...1    izhod = 0...1
defish(int n,float r,float f,float mr)82 float defish(int n, float r, float f, float mr)
83 {
84 	float rr;
85 
86 	switch (n)
87 	{
88 	case 0:		//equidistant
89 		rr=f*2.0/PI*atanf(r*mr);
90 		break;
91 	case 1:		//ortographic
92 		rr=f*sinf(atanf(r*mr));
93 		break;
94 	case 2:		//equiarea
95 		rr=2.0*f*sinf(atanf(r*mr)/2.0);
96 		break;
97 	case 3:		//stereographic
98 		rr=f*4.0/PI*tanf(atanf(r*mr)/2.0);
99 		break;
100 	default:
101 		//		printf("Neznana fishitvena funkcija %d\n",n);
102 		break;
103 	}
104 	return rr;
105 }
106 
107 #if defined(_MSC_VER)
108 #define hypotf _hypotf
109 #endif
110 
111 //----------------------------------------------------------------
112 //nafila array map s polozaji pikslov
113 //locena funkcija, da jo poklicem samo enkrat na zacetku,
114 //array map[] potem uporablja funkcija remap()
115 //tako ni treba za vsak frame znova racunat teh sinusov itd...
116 //wi,hi,wo ho = input.output image width/height
117 //n = 0..3	function select
118 //f = focal ratio (amount of distortion)
119 //scal = scaling factor
120 //pari, paro = pixel aspect ratio (input / output)
121 //dx, dy   offset on input (for non-cosited chroma subsampling)
fishmap(int wi,int hi,int wo,int ho,int n,float f,float scal,float pari,float paro,float dx,float dy,float * map)122 void fishmap(int wi, int hi, int wo, int ho, int n, float f, float scal, float pari, float paro, float dx, float dy, float *map)
123 {
124 	float rmax,maxr,r,kot,x,y,imax;
125 	int i,j,ww,wi2,hi2,wo2,ho2;
126 	float ii,jj,sc;
127 
128 	rmax=hypotf(ho/2.0,wo/2.0*paro);
129 	maxr=fish(n,1.0,f);
130 	imax=hypotf(hi/2.0,wi/2.0*pari);
131 	sc=imax/maxr;
132 
133 	//printf("Fishmap: F=%5.2f  Rmax= %7.2f  Maxr=%6.2f  sc=%6.2f  scal=%6.2f\n",f,rmax,maxr,sc,scal);
134 
135 	wi2=wi/2; hi2=hi/2; wo2=wo/2; ho2=ho/2;
136 	for (i=0;i<ho;i++)
137 	{
138 		ii=i-ho2;
139 		for (j=0;j<wo;j++)
140 		{
141 			jj=(j-wo2)*paro;
142 			r=hypotf(ii,jj);
143 			kot=atan2f(ii,jj);
144 			r=fish(n,r/rmax*scal,f)*sc;
145 			ww=2*(wo*i+j);
146 			if (r<0.0)
147 			{
148 				map[ww]=-1;
149 				map[ww+1]=-1;
150 			}
151 			else
152 			{
153 				x=wi2+r*cosf(kot)/pari;
154 				y=hi2+r*sinf(kot);
155 				if ((x>0)&(x<(wi-1))&(y>0)&(y<(hi-1)))
156 				{
157 					map[ww]=x+dx;
158 					map[ww+1]=y+dy;
159 				}
160 				else
161 				{
162 					map[ww]=-1;
163 					map[ww+1]=-1;
164 				}
165 			}
166 		}
167 	}
168 
169 }
170 
171 //----------------------------------------------------------------
172 //nafila array map s polozaji pikslov
173 //locena funkcija, da jo poklicem samo enkrat na zacetku,
174 //array map[] potem uporablja funkcija remap()
175 //tako ni treba za vsak frame znova racunat teh sinusov itd...
176 //wi,hi,wo ho = input.output image width/height
177 //n = 0..3	function select
178 //f = focal ratio (amount of distortion)
179 //scal = scaling factor
180 //pari,paro = pixel aspect ratio (input / output)
181 //dx, dy   offset on input (for non-cosited chroma subsampling)
defishmap(int wi,int hi,int wo,int ho,int n,float f,float scal,float pari,float paro,float dx,float dy,float * map)182 void defishmap(int wi, int hi, int wo, int ho, int n, float f, float scal, float pari, float paro, float dx, float dy, float *map)
183 {
184 	float rmax,maxr,r,kot,x,y,imax;
185 	int i,j,ww,wi2,hi2,wo2,ho2;
186 	float ii,jj,sc;
187 
188 	rmax=hypotf(ho/2.0,wo/2.0*paro);
189 	maxr=fish(n,1.0,f);
190 	imax=hypotf(hi/2.0,wi/2.0*pari);
191 	sc=imax/maxr;
192 
193 	//printf("Defishmap: F=%f  rmax= %f  Maxr=%f   sc=%6.2f  scal=%6.2f\n",f,rmax,maxr,sc,scal);
194 
195 	wi2=wi/2; hi2=hi/2; wo2=wo/2; ho2=ho/2;
196 	for (i=0;i<ho;i++)
197 	{
198 		ii=i-ho2;
199 		for (j=0;j<wo;j++)
200 		{
201 			jj=(j-wo2)*paro;	//aspect....
202 			r=hypotf(ii,jj)/scal;
203 			kot=atan2f(ii,jj);
204 			ww=2*(wo*i+j);
205 			r=defish(n,r/sc,f,1.0)*rmax;
206 			if (r<0.0)
207 			{
208 				map[ww]=-1;
209 				map[ww+1]=-1;
210 			}
211 			else
212 			{
213 				x=wi2+r*cosf(kot)/pari;
214 				y=hi2+r*sinf(kot);
215 				if ((x>0)&(x<(wi-1))&(y>0)&(y<(hi-1)))
216 				{
217 					map[ww]=x;
218 					map[ww+1]=y;
219 				}
220 				else
221 				{
222 					map[ww]=-1;
223 					map[ww+1]=-1;
224 				}
225 			}
226 		}
227 	}
228 }
229 
230 //=====================================================
231 //kao instanca frei0r
232 //w,h:	image dimensions in pixels
233 //f:	focal ratio
234 //dir:	0=defish  1=fish
235 //type:	0..3	equidistant, ortographic, equiarea, stereographic
236 //scal:	0..3	image to fill, keep center scale, image to fit, manu
237 //intp: 0..6	type of interpolator
238 //aspt:	0..4	aspect type square, PAL, NTSC, HDV, manual
239 //par:	pixel aspect ratio
240 typedef struct
241 {
242 	int w;
243 	int h;
244 	float f;
245 	int dir;
246 	int type;
247 	int scal;
248 	int intp;
249 	float mscale;
250 	int aspt;
251 	float mpar;
252 	float par;
253 	float *map;
254 	interpp interpol;
255 } param;
256 
257 
258 
259 //-------------------------------------------------------
set_intp(param p)260 interpp set_intp(param p)
261 {
262 	switch (p.intp)	//katero interpolacijo bo uporabil
263 	{
264 		//	case -1:return interpNNpr_b;	//nearest neighbor+print
265 	case 0:	return interpNN_b32;	//nearest neighbor
266 	case 1: return interpBL_b32;	//bilinear
267 	case 2:	return interpBC_b32;	//bicubic smooth
268 	case 3:	return interpBC2_b32;	//bicibic sharp
269 	case 4:	return interpSP4_b32;	//spline 4x4
270 	case 5:	return interpSP6_b32;	//spline 6x6
271 	case 6: return interpSC16_b32;	//lanczos 8x8
272 	default: return NULL;
273 	}
274 }
275 
276 //--------------------------------------------------------
make_map(param p)277 void make_map(param p)
278 {
279 	float rmax,maxr,imax,fscal,dscal;
280 
281 	rmax=hypotf(p.h/2.0,p.w/2.0*p.par);
282 	maxr=fish(p.type,1.0,p.f);
283 	imax=hypotf(p.h/2.0,p.w/2.0*p.par);
284 
285 	if (p.dir==0)		//defish
286     {
287 		switch (p.scal)
288 		{
289 		case 0:		//fill
290 			dscal=maxr*p.h/2.0/rmax/fish(p.type,p.h/2.0/rmax,p.f);
291 			break;
292 		case 1:		//keep
293 			dscal=maxr*p.f;
294 			if ((p.type==0)||(p.type==3)) dscal=dscal/PI*2.0;break;
295 		case 2:		//fit
296 			dscal=1.0; break;
297 		case 3:		//manual
298 			dscal=p.mscale; break;
299 		}
300 		defishmap(p.w ,p.h ,p.w ,p.h, p.type, p.f, dscal, p.par, p.par, 0.0, 0.0,  p.map);
301     }
302 	else		//fish
303     {
304 		switch (p.scal)
305 		{
306 		case 0:		//fill
307 			fscal=1.0;break;
308 		case 1:		//keep
309 			fscal=maxr*p.f;
310 			if ((p.type==0)||(p.type==3)) fscal=fscal/PI*2.0;
311 			break;
312 		case 2:		//fit
313 			fscal=2.0*defish(p.type,p.h/2.0*maxr/imax,p.f,1.0)/p.h*rmax;
314 			break;
315 		case 3:		//manual
316 			fscal=1.0/p.mscale; break;
317 		}
318 		fishmap(p.w, p.h, p.w ,p.h, p.type, p.f, fscal, p.par, p.par, 0.0, 0.0,  p.map);
319     }
320 
321 }
322 
323 //*********************************************************
324 // OBVEZNE FREI0R FUNKCIJE
325 
326 //-----------------------------------------------
f0r_init()327 int f0r_init()
328 {
329 	return 1;
330 }
331 
332 //------------------------------------------------
f0r_deinit()333 void f0r_deinit()
334 {
335 }
336 
337 //-----------------------------------------------
f0r_get_plugin_info(f0r_plugin_info_t * info)338 void f0r_get_plugin_info(f0r_plugin_info_t* info)
339 {
340 
341 	info->name="Defish0r";
342 	info->author="Marko Cebokli";
343 	info->plugin_type=F0R_PLUGIN_TYPE_FILTER;
344 	info->color_model=F0R_COLOR_MODEL_RGBA8888;
345 	info->frei0r_version=FREI0R_MAJOR_VERSION;
346 	info->major_version=0;
347 	info->minor_version=3;
348 	info->num_params=8;
349 	info->explanation="Non rectilinear lens mappings";
350 }
351 
352 //--------------------------------------------------
f0r_get_param_info(f0r_param_info_t * info,int param_index)353 void f0r_get_param_info(f0r_param_info_t* info, int param_index)
354 {
355 	switch(param_index)
356 	{
357 	case 0:
358 		info->name = "Amount";
359 		info->type = F0R_PARAM_DOUBLE;
360 		info->explanation = "Focal Ratio";
361 		break;
362 	case 1:
363 		info->name = "DeFish";
364 		info->type = F0R_PARAM_BOOL;
365 		info->explanation = "Fish or Defish";
366 		break;
367 	case 2:
368 		info->name = "Type";
369 		info->type = F0R_PARAM_DOUBLE;
370 		info->explanation = "Mapping function";
371 		break;
372 	case 3:
373 		info->name = "Scaling";
374 		info->type = F0R_PARAM_DOUBLE;
375 		info->explanation = "Scaling method";
376 		break;
377 	case 4:
378 		info->name = "Manual Scale";
379 		info->type = F0R_PARAM_DOUBLE;
380 		info->explanation = "Manual Scale";
381 		break;
382 	case 5:
383 		info->name = "Interpolator";
384 		info->type = F0R_PARAM_DOUBLE;
385 		info->explanation = "Quality of interpolation";
386 		break;
387 	case 6:
388 		info->name = "Aspect type";
389 		info->type = F0R_PARAM_DOUBLE;
390 		info->explanation = "Pixel aspect ratio presets";
391 		break;
392 	case 7:
393 		info->name = "Manual Aspect";
394 		info->type = F0R_PARAM_DOUBLE;
395 		info->explanation = "Manual Pixel Aspect ratio";
396 		break;
397 	}
398 
399 }
400 
401 //--------------------------------------------------------
402 //kao constructor za frei0r
f0r_construct(unsigned int width,unsigned int height)403 f0r_instance_t  f0r_construct(unsigned int width, unsigned int height)
404 {
405 	param *p;
406 
407 	p=(param*)calloc(1, sizeof(param));
408 
409 	p->w=width;
410 	p->h=height;
411 	p->f=20.0;		//defaults (not used??)
412 	p->dir=1;
413 	p->type=2;
414 	p->scal=2;
415 	p->intp=1;
416 	p->mscale=1.0;
417 	p->aspt=0;		//square pixels
418 	p->par=1.0;		//square pixels
419 	p->mpar=1.0;
420 
421 	p->map=(float*)calloc(1, sizeof(float)*(p->w*p->h*2+2));
422 	p->interpol=set_intp(*p);
423 
424 	make_map(*p);
425 
426 	//printf("Construct, w=%d h=%d\n",width,height);
427 
428 	return (f0r_instance_t)p;
429 }
430 
431 //---------------------------------------------------
f0r_destruct(f0r_instance_t instance)432 void f0r_destruct(f0r_instance_t instance)
433 {
434 	param *p;
435 	p=(param*)instance;
436 
437 	free(p->map);
438 	free(instance);
439 }
440 
441 //----------------------------------------------------
442 //not used in frei0r plugin
change_param(param * p,int w,int h,float f,int dir,int type,int scal,int intp)443 void change_param(param *p, int w, int h, float f, int dir, int type, int scal, int intp)
444 {
445 	p->f=f;
446 	p->dir=dir;
447 	p->type=type;
448 	p->scal=scal;
449 	p->intp=intp;
450 
451 	if ((w!=p->w)||(h!=p->h))
452 	{
453 		free(p->map);
454 		p->map=(float*)calloc(1, sizeof(float)*(w*h*2+2));
455 		p->w=w;
456 		p->h=h;
457 	}
458 
459 	p->interpol=set_intp(*p);
460 	make_map(*p);
461 }
462 
463 //-----------------------------------------------------
print_param(param p)464 void print_param(param p)
465 		//not used in frei0r plugin
466 {
467 	printf("Param: w=%d h=%d f=%f dir=%d",p.w, p.h, p.f, p.dir);
468 	printf(" type=%d scal=%d intp=%d",p.type, p.scal, p.intp);
469 	printf(" mscale=%f par=%f mpar=%f\n",p.mscale, p.par, p.mpar);
470 }
471 
472 //------------------------------------------------------
473 //computes x to the power p
474 //only for positive x
pwr(float x,float p)475 float pwr(float x, float p)
476 {
477 	if (x<=0) return 0;
478 	//printf("exp(%f)=%f\n",x,expf(p*logf(x)));
479 	return expf(p*logf(x));
480 }
481 
482 //-----------------------------------------------------
483 //stretch [0...1] to parameter range [min...max] logarithmic
484 //min and max must be positive!
map_value_forward_log(double v,float min,float max)485 float map_value_forward_log(double v, float min, float max)
486 {
487 	float sr,k;
488 
489 	sr=sqrtf(min*max);
490 	k=2.0*log(max/sr);
491 	return sr*expf(k*(v-0.5));
492 }
493 
494 //-----------------------------------------------------
495 //collapse from parameter range [min...max] to [0...1] logarithmic
496 //min and max must be positive!
map_value_backward_log(float v,float min,float max)497 double map_value_backward_log(float v, float min, float max)
498 {
499 	float sr,k;
500 
501 	sr=sqrtf(min*max);
502 	k=2.0*log(max/sr);
503 	return logf(v/sr)/k+0.5;
504 }
505 
506 //-----------------------------------------------------
507 //stretch [0...1] to parameter range [min...max] linear
map_value_forward(double v,float min,float max)508 float map_value_forward(double v, float min, float max)
509 {
510 	return min+(max-min)*v;
511 }
512 
513 //-----------------------------------------------------
514 //collapse from parameter range [min...max] to [0...1] linear
map_value_backward(float v,float min,float max)515 double map_value_backward(float v, float min, float max)
516 {
517 	return (v-min)/(max-min);
518 }
519 
520 //-----------------------------------------------------
521 //smisele vrednosti za parameter f:  (za fish)
522 // tip 0: (0.3) 1.001...10;    tip 1: 1.000...10
523 // tip 2: (0.5) 0.75...10.0    tip 3: (0.1) 0.78...10
524 //za defish:
525 // tip 0: 0.1...10             tip 1: 1.0...10
526 // tip 2: 0.5...10             tip 3: (0.1) 0.5...10
f0r_set_param_value(f0r_instance_t instance,f0r_param_t parm,int param_index)527 void f0r_set_param_value(f0r_instance_t instance, f0r_param_t parm, int param_index)
528 {
529 	param *p;
530 	int chg,tmpi;
531 	float tmpf;
532 
533 	p=(param*)instance;
534 
535 	//printf("set parm: index=%d, value=%f\n",param_index,*(float*)parm);
536 	chg=0;
537 	switch(param_index)
538 	{
539 	case 0:	//f
540 		tmpf=pwr(*((double*)parm),1.0/5.0);
541 		//    tmpf=map_value_forward(*((double*)parm), 10.0, 0.1);
542 		tmpf=map_value_forward(tmpf, 20.0, 0.1);
543 		if (p->f != tmpf) chg=1;
544 		p->f=tmpf;
545 		break;
546 	case 1:	//fish
547 		tmpi=map_value_forward(*((double*)parm), 1.0, 0.0);//BOOL!!
548 		if (p->dir != tmpi) chg=1;
549 		p->dir=tmpi;
550 		break;
551 	case 2:	//type
552 		tmpi=map_value_forward(*((double*)parm), 0.0, 3.999);
553 		if (p->type != tmpi) chg=1;
554 		p->type=tmpi;
555 		break;
556 	case 3:	//scaling
557 		tmpi=map_value_forward(*((double*)parm), 0.0, 3.999);
558 		if (p->scal != tmpi) chg=1;
559 		p->scal=tmpi;
560 		break;
561 	case 4:	//manual scale
562 		tmpf=map_value_forward_log(*((double*)parm), 0.01, 100.0);
563 		if (p->mscale != tmpf) chg=1;
564 		p->mscale=tmpf;
565 		break;
566 	case 5:	//interpolator
567 		tmpi=map_value_forward(*((double*)parm), 0.0, 6.999);
568 		if (p->intp != tmpi) chg=1;
569 		p->intp=tmpi;
570 		break;
571 	case 6:	//aspect type
572 		tmpi=map_value_forward(*((double*)parm), 0.0, 4.999);
573 		if (p->aspt != tmpi) chg=1;
574 		p->aspt=tmpi;
575 		break;
576 	case 7:	//manual aspect
577 		tmpf=map_value_forward_log(*((double*)parm), 0.5, 2.0);
578 		if (p->mpar != tmpf) chg=1;
579 		p->mpar=tmpf;
580 		break;
581 	}
582 
583 	if (chg!=0)
584 	{
585 		switch (p->aspt)	//pixel aspect ratio
586 		{
587 		case 0: p->par=1.000;break;		//square pixels
588 		case 1: p->par=1.067;break;		//PAL DV
589 		case 2: p->par=0.889;break;		//NTSC DV
590 		case 3: p->par=1.333;break;		//HDV
591 		case 4: p->par=p->mpar;break;	//manual
592 		}
593 		p->interpol=set_intp(*p);
594 		make_map(*p);
595 	}
596 
597 	//print_param(*p);
598 }
599 
600 //--------------------------------------------------
f0r_get_param_value(f0r_instance_t instance,f0r_param_t parm,int param_index)601 void f0r_get_param_value(f0r_instance_t instance, f0r_param_t parm, int param_index)
602 {
603 	param *p;
604 	float tmpf;
605 
606 	p=(param*)instance;
607 
608 	switch(param_index)
609 	{
610 	case 0:	//f
611 		//    *((double*)parm)=map_value_backward(p->f, 10.0, 0.1);
612 		tmpf=map_value_backward(p->f, 20.0, 0.1);
613 		*((double*)parm)=pwr(tmpf, 5.0);
614 		break;
615 	case 1:	//fish
616 		*((double*)parm)=map_value_backward(p->dir, 1.0, 0.0); //BOOL!!
617 		break;
618 	case 2:	//type
619 		*((double*)parm)=map_value_backward(p->type, 0.0, 3.0);
620 		break;
621 	case 3:	//scaling
622 		*((double*)parm)=map_value_backward(p->scal, 0.0, 3.0);
623 		break;
624 	case 4:	//manual scale
625 		*((double*)parm)=map_value_backward_log(p->mscale, 0.01, 100.0);
626 		break;
627 	case 5:	//interpolator
628 		*((double*)parm)=map_value_backward(p->intp, 0.0, 6.0);
629 		break;
630 	case 6:	//aspect type
631 		*((double*)parm)=map_value_backward(p->aspt, 0.0, 4.999);
632 		break;
633 	case 7:	//manual aspect
634 		*((double*)parm)=map_value_backward_log(p->mpar, 0.5, 2.0);
635 		break;
636 	}
637 }
638 
639 //-------------------------------------------------
f0r_update(f0r_instance_t instance,double time,const uint32_t * inframe,uint32_t * outframe)640 void f0r_update(f0r_instance_t instance, double time, const uint32_t* inframe, uint32_t* outframe)
641 {
642 	param *p;
643 
644 	p=(param*)instance;
645 
646 	remap32(p->w, p->h, p->w, p->h, (unsigned char*) inframe, (unsigned char*) outframe, p->map, 0, p->interpol);
647 
648 }
649