4 * Copyright (C) Georg Martius - June 2007
6 * This file is part of transcode, a video stream processing tool
8 * transcode is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2, or (at your option)
13 * transcode is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with GNU Make; see the file COPYING. If not, write to
20 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
26 #include "transformtype.h"
27 #include "transformtype_operations.h"
28 #include "vidstabdefines.h"
30 /***********************************************************************
31 * helper functions to create and operate with transforms.
32 * all functions are non-destructive
35 /* create an initialized transform*/
36 VSTransform
new_transform(double x
, double y
, double alpha
,
37 double zoom
, double barrel
, double rshutter
, int extra
)
45 t
.rshutter
= rshutter
;
50 /* create a zero initialized transform*/
51 VSTransform
null_transform(void)
53 return new_transform(0, 0, 0, 0, 0, 0, 0);
56 /* adds two transforms */
57 VSTransform
add_transforms(const VSTransform
* t1
, const VSTransform
* t2
)
62 t
.alpha
= t1
->alpha
+ t2
->alpha
;
63 t
.zoom
= t1
->zoom
+ t2
->zoom
;
64 t
.barrel
= t1
->barrel
+ t2
->barrel
;
65 t
.rshutter
= t1
->rshutter
+ t2
->rshutter
;
66 t
.extra
= t1
->extra
|| t2
->extra
;
70 /* like add_transform but with non-pointer signature */
71 VSTransform
add_transforms_(const VSTransform t1
, const VSTransform t2
)
73 return add_transforms(&t1
, &t2
);
76 /* subtracts two transforms */
77 VSTransform
sub_transforms(const VSTransform
* t1
, const VSTransform
* t2
)
82 t
.alpha
= t1
->alpha
- t2
->alpha
;
83 t
.zoom
= t1
->zoom
- t2
->zoom
;
84 t
.barrel
= t1
->barrel
- t2
->barrel
;
85 t
.rshutter
= t1
->rshutter
- t2
->rshutter
;
86 t
.extra
= t1
->extra
|| t2
->extra
;
90 /* multiplies a transforms with a scalar */
91 VSTransform
mult_transform(const VSTransform
* t1
, double f
)
96 t
.alpha
= t1
->alpha
* f
;
97 t
.zoom
= t1
->zoom
* f
;
98 t
.barrel
= t1
->barrel
* f
;
99 t
.rshutter
= t1
->rshutter
* f
;
104 /* like mult_transform but with non-pointer signature */
105 VSTransform
mult_transform_(const VSTransform t1
, double f
)
107 return mult_transform(&t1
,f
);
110 void storeVSTransform(FILE* f
, const VSTransform
* t
){
111 fprintf(f
,"Trans %lf %lf %lf %lf %i\n", t
->x
, t
->y
, t
->alpha
, t
->zoom
, t
->extra
);
115 PreparedTransform
prepare_transform(const VSTransform
* t
, const VSFrameInfo
* fi
){
116 PreparedTransform pt
;
118 double z
= 1.0+t
->zoom
/100.0;
119 pt
.zcos_a
= z
*cos(t
->alpha
); // scaled cos
120 pt
.zsin_a
= z
*sin(t
->alpha
); // scaled sin
121 pt
.c_x
= fi
->width
/ 2;
122 pt
.c_y
= fi
->height
/ 2;
126 Vec
transform_vec(const PreparedTransform
* pt
, const Vec
* v
){
128 transform_vec_double(&x
, &y
, pt
, v
);
133 void transform_vec_double(double* x
, double* y
, const PreparedTransform
* pt
, const Vec
* v
){
134 double rx
= v
->x
- pt
->c_x
;
135 double ry
= v
->y
- pt
->c_y
;
136 *x
= pt
->zcos_a
* rx
+ pt
->zsin_a
* ry
+ pt
->t
->x
+ pt
->c_x
;
137 *y
= -pt
->zsin_a
* rx
+ pt
->zcos_a
* ry
+ pt
->t
->y
+ pt
->c_y
;
140 Vec
sub_vec(Vec v1
, Vec v2
){
141 Vec r
= {v1
.x
- v2
.x
, v1
.y
- v2
.y
};
144 Vec
add_vec(Vec v1
, Vec v2
){
145 Vec r
= {v1
.x
+ v2
.x
, v1
.y
+ v2
.y
};
148 Vec
field_to_vec(Field f
){
153 /* compares a transform with respect to x (for sort function) */
154 int cmp_trans_x(const void *t1
, const void* t2
)
156 double a
= ((VSTransform
*)t1
)->x
;
157 double b
= ((VSTransform
*)t2
)->x
;
158 return a
< b
? -1 : ( a
> b
? 1 : 0 );
161 /* compares a transform with respect to y (for sort function) */
162 int cmp_trans_y(const void *t1
, const void* t2
)
164 double a
= ((VSTransform
*)t1
)->y
;
165 double b
= ((VSTransform
*)t2
)->y
;
166 return a
< b
? -1 : ( a
> b
? 1: 0 );
169 /* static int cmp_trans_alpha(const void *t1, const void* t2){ */
170 /* double a = ((VSTransform*)t1)->alpha; */
171 /* double b = ((VSTransform*)t2)->alpha; */
172 /* return a < b ? -1 : ( a > b ? 1 : 0 ); */
176 /* compares two double values (for sort function)*/
177 int cmp_double(const void *t1
, const void* t2
)
179 double a
= *((double*)t1
);
180 double b
= *((double*)t2
);
181 return a
< b
? -1 : ( a
> b
? 1 : 0 );
184 /* compares two int values (for sort function)*/
185 int cmp_int(const void *t1
, const void* t2
)
189 return a
< b
? -1 : ( a
> b
? 1 : 0 );
193 * median_xy_transform: calulcates the median of an array
194 * of transforms, considering only x and y
197 * transforms: array of transforms.
198 * len: length of array
200 * A new transform with x and y beeing the median of
201 * all transforms. alpha and other fields are 0.
207 VSTransform
median_xy_transform(const VSTransform
* transforms
, int len
)
209 VSTransform
* ts
= vs_malloc(sizeof(VSTransform
) * len
);
210 VSTransform t
= null_transform();
211 memcpy(ts
,transforms
, sizeof(VSTransform
)*len
);
213 qsort(ts
, len
, sizeof(VSTransform
), cmp_trans_x
);
214 t
.x
= len
% 2 == 0 ? ts
[half
].x
: (ts
[half
].x
+ ts
[half
+1].x
)/2;
215 qsort(ts
, len
, sizeof(VSTransform
), cmp_trans_y
);
216 t
.y
= len
% 2 == 0 ? ts
[half
].y
: (ts
[half
].y
+ ts
[half
+1].y
)/2;
222 * cleanmean_xy_transform: calulcates the cleaned mean of an array
223 * of transforms, considering only x and y
226 * transforms: array of transforms.
227 * len: length of array
229 * A new transform with x and y beeing the cleaned mean
230 * (meaning upper and lower pentile are removed) of
231 * all transforms. alpha and other fields are 0.
237 VSTransform
cleanmean_xy_transform(const VSTransform
* transforms
, int len
)
239 VSTransform
* ts
= vs_malloc(sizeof(VSTransform
) * len
);
240 VSTransform t
= null_transform();
241 int i
, cut
= len
/ 5;
242 memcpy(ts
, transforms
, sizeof(VSTransform
) * len
);
243 qsort(ts
,len
, sizeof(VSTransform
), cmp_trans_x
);
244 for (i
= cut
; i
< len
- cut
; i
++){ // all but cutted
247 qsort(ts
, len
, sizeof(VSTransform
), cmp_trans_y
);
248 for (i
= cut
; i
< len
- cut
; i
++){ // all but cutted
252 return mult_transform(&t
, 1.0 / (len
- (2.0 * cut
)));
257 * calulcates the cleaned maximum and minimum of an array of transforms,
258 * considerung only x and y
259 * It cuts off the upper and lower x-th percentil
262 * transforms: array of transforms.
263 * len: length of array
264 * percentil: the x-th percentil to cut off
265 * min: pointer to min (return value)
266 * max: pointer to max (return value)
268 * call by reference in min and max
270 * len>0, 0<=percentil<50
272 * only on min and max
274 void cleanmaxmin_xy_transform(const VSTransform
* transforms
, int len
,
276 VSTransform
* min
, VSTransform
* max
){
277 VSTransform
* ts
= vs_malloc(sizeof(VSTransform
) * len
);
278 int cut
= len
* percentil
/ 100;
279 memcpy(ts
, transforms
, sizeof(VSTransform
) * len
);
280 qsort(ts
,len
, sizeof(VSTransform
), cmp_trans_x
);
282 max
->x
= ts
[len
-cut
-1].x
;
283 qsort(ts
, len
, sizeof(VSTransform
), cmp_trans_y
);
285 max
->y
= ts
[len
-cut
-1].y
;
289 /* calculates the required zoom value to have no borders visible
291 double transform_get_required_zoom(const VSTransform
* transform
, int width
, int height
){
292 return 100.0*(2.0*VS_MAX(fabs(transform
->x
)/width
,fabs(transform
->y
)/height
) // translation part
293 + fabs(sin(transform
->alpha
))); // rotation part
299 * media: median of a double array
302 * ds: array of values
303 * len: length of array
305 * the median value of the array
306 * Preconditions: len>0
307 * Side effects: ds will be sorted!
309 double median(double* ds
, int len
)
312 qsort(ds
,len
, sizeof(double), cmp_double
);
313 return len
% 2 == 0 ? ds
[half
] : (ds
[half
] + ds
[half
+1])/2;
317 /** square of a number */
318 double sqr(double x
){ return x
*x
; }
321 * mean: mean of a double array
324 * ds: array of values
325 * len: length of array
326 * Return value: the mean value of the array
327 * Preconditions: len>0
330 double mean(const double* ds
, int len
)
334 for (i
= 0; i
< len
; i
++)
340 * stddev: standard deviation of a double array
343 * ds: array of values
344 * len: length of array
345 * mean: mean of the array (@see mean())
346 * Return value: the standard deviation value of the array
347 * Preconditions: len>0
350 double stddev(const double* ds
, int len
, double mean
)
354 for (i
= 0; i
< len
; i
++)
355 sum
+= sqr(ds
[i
]-mean
);
356 return sqrt(sum
/ len
);
360 * cleanmean: mean with cutted upper and lower pentile
363 * ds: array of values
364 * len: length of array
365 * minimum: minimal value (after cleaning) if not NULL
366 * maximum: maximal value (after cleaning) if not NULL
368 * the mean value of the array without the upper
369 * and lower pentile (20% each)
370 * and minimum and maximum without the pentiles
371 * Preconditions: len>0
372 * Side effects: ds will be sorted!
374 double cleanmean(double* ds
, int len
, double* minimum
, double* maximum
)
379 qsort(ds
, len
, sizeof(double), cmp_double
);
380 for (i
= cut
; i
< len
- cut
; i
++) { // all but first and last
386 *maximum
= ds
[len
-cut
-1];
387 return sum
/ (len
- (2.0 * cut
));
390 /************************************************/
391 /***************LOCALMOTION**********************/
393 LocalMotion
null_localmotion(){
395 memset(&lm
,0,sizeof(lm
));
399 int* localmotions_getx(const LocalMotions
* localmotions
){
400 int len
= vs_vector_size(localmotions
);
401 int* xs
= vs_malloc(sizeof(int) * len
);
403 for (i
=0; i
<len
; i
++){
404 xs
[i
]=LMGet(localmotions
,i
)->v
.x
;
409 int* localmotions_gety(const LocalMotions
* localmotions
){
410 int len
= vs_vector_size(localmotions
);
411 int* ys
= vs_malloc(sizeof(int) * len
);
413 for (i
=0; i
<len
; i
++){
414 ys
[i
]=LMGet(localmotions
,i
)->v
.y
;
419 LocalMotion
sub_localmotion(const LocalMotion
* lm1
, const LocalMotion
* lm2
){
420 LocalMotion res
= *lm1
;
428 * cleanmean_localmotions: calulcates the cleaned mean of a vector
429 * of local motions considering
432 * localmotions : vs_vector of local motions
434 * A localmotion with vec with x and y being the cleaned mean
435 * (meaning upper and lower pentile are removed) of
436 * all local motions. all other fields are 0.
442 LocalMotion
cleanmean_localmotions(const LocalMotions
* localmotions
)
444 int len
= vs_vector_size(localmotions
);
445 int i
, cut
= len
/ 5;
446 int* xs
= localmotions_getx(localmotions
);
447 int* ys
= localmotions_gety(localmotions
);
448 LocalMotion m
= null_localmotion();
450 qsort(xs
,len
, sizeof(int), cmp_int
);
451 for (i
= cut
; i
< len
- cut
; i
++){ // all but cutted
454 qsort(ys
, len
, sizeof(int), cmp_int
);
455 for (i
= cut
; i
< len
- cut
; i
++){ // all but cutted
460 m
.v
.x
/=(len
- (2.0 * cut
));
461 m
.v
.y
/=(len
- (2.0 * cut
));
465 VSArray
localmotionsGetMatch(const LocalMotions
* localmotions
){
466 VSArray m
= vs_array_new(vs_vector_size(localmotions
));
467 for (int i
=0; i
<m
.len
; i
++){
468 m
.dat
[i
]=LMGet(localmotions
,i
)->match
;
476 * c-file-style: "stroustrup"
477 * c-file-offsets: ((case-label . *) (statement-case-intro . *))
478 * indent-tabs-mode: nil
479 * c-basic-offset: 2 t
482 * vim: expandtab shiftwidth=2: