]> git.sesse.net Git - mlt/blob - src/modules/videostab/transform.c
Avoid unnecessary compilation when running "./configure; make; make install" multiple...
[mlt] / src / modules / videostab / transform.c
1 /*
2  *  transform.c
3  *
4  *  Copyright (C) Georg Martius - June 2007
5  *
6  *  This file is part of transcode, a video stream processing tool
7  *      
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)
11  *  any later version.
12  *   
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.
17  *   
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. 
21  *
22  */
23
24 #ifdef HAVE_CONFIG_H
25 # include "config.h"
26 #endif
27 #include <stdlib.h>
28 #include <string.h>
29 #include <math.h>
30 #include "transform.h"
31
32 /***********************************************************************
33  * helper functions to create and operate with transforms.
34  * all functions are non-destructive
35  */
36
37 /* create an initialized transform*/
38 Transform new_transform(double x, double y, double alpha, 
39                         double zoom, int extra)
40
41     Transform t;
42     t.x     = x;
43     t.y     = y;
44     t.alpha = alpha;
45     t.zoom  = zoom;
46     t.extra = extra;
47     return t;
48 }
49
50 /* create a zero initialized transform*/
51 Transform null_transform(void)
52
53     return new_transform(0, 0, 0, 0, 0);
54 }
55
56 /* adds two transforms */
57 Transform add_transforms(const Transform* t1, const Transform* t2)
58 {
59     Transform t;
60     t.x     = t1->x + t2->x;
61     t.y     = t1->y + t2->y;
62     t.alpha = t1->alpha + t2->alpha;
63     t.zoom  = t1->zoom + t2->zoom;
64     t.extra = 0;
65     return t;
66 }
67
68 /* like add_transform but with non-pointer signature */
69 Transform add_transforms_(const Transform t1, const Transform t2)
70 {
71     return add_transforms(&t1, &t2);
72 }
73
74 /* subtracts two transforms */
75 Transform sub_transforms(const Transform* t1, const Transform* t2)
76 {
77     Transform t;
78     t.x     = t1->x - t2->x;
79     t.y     = t1->y - t2->y;
80     t.alpha = t1->alpha - t2->alpha;
81     t.zoom  = t1->zoom - t2->zoom;
82     t.extra = 0;
83     return t;
84 }
85
86 /* multiplies a transforms with a scalar */
87 Transform mult_transform(const Transform* t1, double f)
88 {
89     Transform t;
90     t.x     = t1->x * f;
91     t.y     = t1->y * f;
92     t.alpha = t1->alpha * f;
93     t.zoom  = t1->zoom * f;
94     t.extra = 0;
95     return t;
96 }
97
98 /* like mult_transform but with non-pointer signature */
99 Transform mult_transform_(const Transform t1, double f)
100 {
101     return mult_transform(&t1,f);
102 }
103
104 /* compares a transform with respect to x (for sort function) */
105 int cmp_trans_x(const void *t1, const void* t2)
106 {
107     double a = ((Transform*)t1)->x;
108     double b = ((Transform*)t2)->x;
109     return a < b ? -1 : ( a > b ? 1 : 0 );
110 }
111
112 /* compares a transform with respect to y (for sort function) */
113 int cmp_trans_y(const void *t1, const void* t2)
114 {
115     double a = ((Transform*)t1)->y;
116     double b = ((Transform*)t2)->y;
117     return a < b ? -1 : ( a > b ? 1: 0 );
118 }
119
120 /* static int cmp_trans_alpha(const void *t1, const void* t2){ */
121 /*   double a = ((Transform*)t1)->alpha; */
122 /*   double b = ((Transform*)t2)->alpha; */
123 /*   return a < b ? -1 : ( a > b ? 1 : 0 ); */
124 /* } */
125
126
127 /* compares two double values (for sort function)*/
128 int cmp_double(const void *t1, const void* t2)
129 {
130     double a = *((double*)t1);
131     double b = *((double*)t2);
132     return a < b ? -1 : ( a > b ? 1 : 0 );
133 }
134
135 /**
136  * median_xy_transform: calulcates the median of an array 
137  * of transforms, considering only x and y
138  *
139  * Parameters:
140  *    transforms: array of transforms.
141  *           len: length  of array
142  * Return value:
143  *     A new transform with x and y beeing the median of 
144  *     all transforms. alpha and other fields are 0.
145  * Preconditions:
146  *     len>0
147  * Side effects:
148  *     None
149  */
150 Transform median_xy_transform(const Transform* transforms, int len)
151 {
152     Transform* ts = malloc(sizeof(Transform) * len);
153     Transform t;
154     memcpy(ts,transforms, sizeof(Transform)*len ); 
155     int half = len/2;
156     qsort(ts, len, sizeof(Transform), cmp_trans_x);
157     t.x = len % 2 == 0 ? ts[half].x : (ts[half].x + ts[half+1].x)/2;
158     qsort(ts, len, sizeof(Transform), cmp_trans_y);
159     t.y = len % 2 == 0 ? ts[half].y : (ts[half].y + ts[half+1].y)/2;
160     t.alpha = 0;
161     t.zoom = 0;
162     t.extra = 0;
163     free(ts);
164     return t;
165 }
166
167 /**
168  * cleanmean_xy_transform: calulcates the cleaned mean of an array 
169  * of transforms, considering only x and y
170  *
171  * Parameters:
172  *    transforms: array of transforms.
173  *           len: length  of array
174  * Return value:
175  *     A new transform with x and y beeing the cleaned mean 
176  *     (meaning upper and lower pentile are removed) of 
177  *     all transforms. alpha and other fields are 0.
178  * Preconditions:
179  *     len>0
180  * Side effects:
181  *     None
182  */
183 Transform cleanmean_xy_transform(const Transform* transforms, int len)
184 {
185     Transform* ts = malloc(sizeof(Transform) * len);
186     Transform t = null_transform();
187     int i, cut = len / 5;
188     memcpy(ts, transforms, sizeof(Transform) * len); 
189     qsort(ts,len, sizeof(Transform), cmp_trans_x);
190     for (i = cut; i < len - cut; i++){ // all but cutted
191         t.x += ts[i].x;
192     }
193     qsort(ts, len, sizeof(Transform), cmp_trans_y);
194     for (i = cut; i < len - cut; i++){ // all but cutted
195         t.y += ts[i].y;
196     }
197     free(ts);
198     return mult_transform(&t, 1.0 / (len - (2.0 * cut)));
199 }
200
201
202 /** 
203  * calulcates the cleaned maximum and minimum of an array of transforms,
204  * considerung only x and y
205  * It cuts off the upper and lower x-th percentil
206  *
207  * Parameters:
208  *    transforms: array of transforms.
209  *           len: length  of array
210  *     percentil: the x-th percentil to cut off
211  *           min: pointer to min (return value)
212  *           max: pointer to max (return value)
213  * Return value:
214  *     call by reference in min and max
215  * Preconditions:
216  *     len>0, 0<=percentil<50
217  * Side effects:
218  *     only on min and max
219  */
220 void cleanmaxmin_xy_transform(const Transform* transforms, int len, 
221                               int percentil, 
222                               Transform* min, Transform* max){
223     Transform* ts = malloc(sizeof(Transform) * len);
224     int cut = len * percentil / 100;
225     memcpy(ts, transforms, sizeof(Transform) * len); 
226     qsort(ts,len, sizeof(Transform), cmp_trans_x);
227     min->x = ts[cut].x;
228     max->x = ts[len-cut-1].x;
229     qsort(ts, len, sizeof(Transform), cmp_trans_y);
230     min->y = ts[cut].y;
231     max->y = ts[len-cut-1].y;
232     free(ts);
233 }
234
235
236 /**
237  * media: median of a double array
238  *
239  * Parameters:
240  *            ds: array of values
241  *           len: length  of array
242  * Return value:
243  *     the median value of the array
244  * Preconditions: len>0
245  * Side effects:  ds will be sorted!
246  */
247 double median(double* ds, int len)
248 {
249     int half=len/2;
250     qsort(ds,len, sizeof(double), cmp_double);
251     return len % 2 == 0 ? ds[half] : (ds[half] + ds[half+1])/2;
252 }
253
254 /**
255  * mean: mean of a double array 
256  *
257  * Parameters:
258  *            ds: array of values
259  *           len: length  of array
260  * Return value: the mean value of the array
261  * Preconditions: len>0
262  * Side effects:  None
263  */
264 double mean(const double* ds, int len)
265 {
266     double sum=0;
267     int i = 0;
268     for (i = 0; i < len; i++)
269         sum += ds[i];
270     return sum / len;
271 }
272
273 /**
274  * cleanmean: mean with cutted upper and lower pentile 
275  *
276  * Parameters:
277  *            ds: array of values
278  *           len: length  of array
279  *           len: length of array
280  *       minimum: minimal value (after cleaning) if not NULL
281  *       maximum: maximal value (after cleaning) if not NULL
282  * Return value:
283  *     the mean value of the array without the upper 
284  *     and lower pentile (20% each)
285  *     and lower pentile (20% each) 
286  *     and minimum and maximum without the pentiles
287  * Preconditions: len>0
288  * Side effects:  ds will be sorted!
289  */
290 double cleanmean(double* ds, int len, double* minimum, double* maximum)
291 {
292     int cut    = len / 5;
293     double sum = 0;
294     int i      = 0;
295     qsort(ds, len, sizeof(double), cmp_double);
296     for (i = cut; i < len - cut; i++) { // all but first and last
297         sum += ds[i];
298     }
299     if (minimum)
300         *minimum = ds[cut];
301     if (maximum)
302         *maximum = ds[len-cut-1];
303     return sum / (len - (2.0 * cut));
304 }
305
306
307 /*
308  * Local variables:
309  *   c-file-style: "stroustrup"
310  *   c-file-offsets: ((case-label . *) (statement-case-intro . *))
311  *   indent-tabs-mode: nil
312  * End:
313  *
314  * vim: expandtab shiftwidth=4:
315  */