4 * Copyright (C) Georg Martius - June 2007
5 * georg dot martius at web dot de
7 * This file is part of transcode, a video stream processing tool
9 * transcode is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2, or (at your option)
14 * transcode is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with GNU Make; see the file COPYING. If not, write to
21 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
26 * transcode -V -J stabilize=shakiness=5:show=1,preview
27 * -i inp.mpeg -y null,null -o dummy
28 * all parameters are optional
31 #define MOD_NAME "filter_stabilize.so"
32 #define MOD_VERSION "v0.75 (2010-04-07)"
33 #define MOD_CAP "extracts relative transformations of \n\
34 subsequent frames (used for stabilization together with the\n\
35 transform filter in a second pass)"
36 #define MOD_AUTHOR "Georg Martius"
39 - Try OpenCL/Cuda, this should work great
40 - use smoothing on the frames and then use gradient decent!
41 - stepsize could be adapted (maybe to check only one field with large
42 stepsize and use the maximally required for the other fields
45 #define MOD_FEATURES \
46 TC_MODULE_FEATURE_FILTER|TC_MODULE_FEATURE_VIDEO
48 TC_MODULE_FLAG_RECONFIGURABLE | TC_MODULE_FLAG_DELAY
49 #define MAX(a,b) ((a < b) ? (b) : (a))
50 #define MIN(a,b) ((a < b) ? (a) : (b))
51 #include "stabilize.h"
54 #include <framework/mlt_types.h>
57 void addTrans(StabData* sd, Transform sl)
60 sd->transs = tlist_new(0);
62 tlist_append(sd->transs, &sl,sizeof(Transform) );
67 /** initialise measurement fields on the frame.
68 The size of the fields and the maxshift is used to
69 calculate an optimal distribution in the frame.
71 int initFields(StabData* sd)
73 int size = sd->field_size;
74 int rows = MAX(3,(sd->height - sd->maxshift*2)/size-1);
75 int cols = MAX(3,(sd->width - sd->maxshift*2)/size-1);
76 // make sure that the remaining rows have the same length
77 sd->field_num = rows*cols;
78 sd->field_rows = rows;
79 printf("field setup: rows: %i cols: %i Total: %i fields",
80 rows, cols, sd->field_num);
82 if (!(sd->fields = malloc(sizeof(Field) * sd->field_num))) {
83 printf( "malloc failed!\n");
87 // the border is the amount by which the field centers
88 // have to be away from the image boundary
89 // (stepsize is added in case shift is increased through stepsize)
90 int border = size/2 + sd->maxshift + sd->stepsize;
91 int step_x = (sd->width - 2*border)/MAX(cols-1,1);
92 int step_y = (sd->height - 2*border) / MAX(rows-1,1);
93 for (j = 0; j < rows; j++) {
94 for (i = 0; i < cols; i++) {
96 sd->fields[idx].x = border + i*step_x;
97 sd->fields[idx].y = border + j*step_y;
98 sd->fields[idx].size = size;
107 compares the two given images and returns the average absolute difference
108 \param d_x shift in x direction
109 \param d_y shift in y direction
111 double compareImg(unsigned char* I1, unsigned char* I2,
112 int width, int height, int bytesPerPixel, int d_x, int d_y)
115 unsigned char* p1 = NULL;
116 unsigned char* p2 = NULL;
118 int effectWidth = width - abs(d_x);
119 int effectHeight = height - abs(d_y);
121 /* DEBUGGING code to export single frames */
122 /* char buffer[100]; */
123 /* sprintf(buffer, "pic_%02ix%02i_1.ppm", d_x, d_y); */
124 /* FILE *pic1 = fopen(buffer, "w"); */
125 /* sprintf(buffer, "pic_%02ix%02i_2.ppm", d_x, d_y); */
126 /* FILE *pic2 = fopen(buffer, "w"); */
127 /* fprintf(pic1, "P6\n%i %i\n255\n", effectWidth, effectHeight); */
128 /* fprintf(pic2, "P6\n%i %i\n255\n", effectWidth, effectHeight); */
130 for (i = 0; i < effectHeight; i++) {
134 p1 += (i + d_y) * width * bytesPerPixel;
135 p2 += i * width * bytesPerPixel;
137 p1 += i * width * bytesPerPixel;
138 p2 += (i - d_y) * width * bytesPerPixel;
141 p1 += d_x * bytesPerPixel;
143 p2 -= d_x * bytesPerPixel;
145 // TODO: use some mmx or sse stuff here
146 for (j = 0; j < effectWidth * bytesPerPixel; j++) {
147 /* debugging code continued */
148 /* fwrite(p1,1,1,pic1);fwrite(p1,1,1,pic1);fwrite(p1,1,1,pic1);
149 fwrite(p2,1,1,pic2);fwrite(p2,1,1,pic2);fwrite(p2,1,1,pic2);
151 sum += abs((int)*p1 - (int)*p2);
159 return sum/((double) effectWidth * effectHeight * bytesPerPixel);
163 compares a small part of two given images
164 and returns the average absolute difference.
165 Field center, size and shift have to be choosen,
166 so that no clipping is required
168 \param field Field specifies position(center) and size of subimage
169 \param d_x shift in x direction
170 \param d_y shift in y direction
172 double compareSubImg(unsigned char* const I1, unsigned char* const I2,
174 int width, int height, int bytesPerPixel, int d_x, int d_y)
177 unsigned char* p1 = NULL;
178 unsigned char* p2 = NULL;
179 int s2 = field->size / 2;
182 p1=I1 + ((field->x - s2) + (field->y - s2)*width)*bytesPerPixel;
183 p2=I2 + ((field->x - s2 + d_x) + (field->y - s2 + d_y)*width)*bytesPerPixel;
184 // TODO: use some mmx or sse stuff here
185 for (j = 0; j < field->size; j++){
187 for (k = 0; k < field->size * bytesPerPixel; k++) {
191 sum += abs((int)*p1 - (int)*p2);
202 p1 += (width - field->size) * bytesPerPixel;
203 p2 += (width - field->size) * bytesPerPixel;
205 return sum/((double) field->size *field->size* bytesPerPixel);
208 /** \see contrastSubImg called with bytesPerPixel=1*/
209 double contrastSubImgYUV(StabData* sd, const Field* field){
210 return contrastSubImg(sd->curr,field,sd->width,sd->height,1);
214 \see contrastSubImg three times called with bytesPerPixel=3
217 double contrastSubImgRGB(StabData* sd, const Field* field){
218 unsigned char* const I = sd->curr;
219 return ( contrastSubImg(I, field,sd->width,sd->height,3)
220 + contrastSubImg(I+1,field,sd->width,sd->height,3)
221 + contrastSubImg(I+2,field,sd->width,sd->height,3))/3;
225 calculates Michelson-contrast in the given small part of the given image
227 \param I pointer to framebuffer
228 \param field Field specifies position(center) and size of subimage
229 \param width width of frame
230 \param height height of frame
231 \param bytesPerPixel calc contrast for only for first channel
233 double contrastSubImg(unsigned char* const I, const Field* field,
234 int width, int height, int bytesPerPixel)
237 unsigned char* p = NULL;
238 int s2 = field->size / 2;
239 unsigned char mini = 255;
240 unsigned char maxi = 0;
242 p = I + ((field->x - s2) + (field->y - s2)*width)*bytesPerPixel;
243 // TODO: use some mmx or sse stuff here
244 for (j = 0; j < field->size; j++){
245 for (k = 0; k < field->size * bytesPerPixel; k++) {
246 mini = (mini < *p) ? mini : *p;
247 maxi = (maxi > *p) ? maxi : *p;
250 p += (width - field->size) * bytesPerPixel;
252 return (maxi-mini)/(maxi+mini+0.1); // +0.1 to avoid division by 0
255 /** tries to register current frame onto previous frame.
256 This is the most simple algorithm:
257 shift images to all possible positions and calc summed error
258 Shift with minimal error is selected.
260 Transform calcShiftRGBSimple(StabData* sd)
262 printf("calc shoft rgb simple\n");
265 double minerror = 1e20;
266 for (i = -sd->maxshift; i <= sd->maxshift; i++) {
267 for (j = -sd->maxshift; j <= sd->maxshift; j++) {
268 double error = compareImg(sd->curr, sd->prev,
269 sd->width, sd->height, 3, i, j);
270 if (error < minerror) {
277 return new_transform(x, y, 0, 0, 0);
281 /** tries to register current frame onto previous frame.
282 (only the luminance is used)
283 This is the most simple algorithm:
284 shift images to all possible positions and calc summed error
285 Shift with minimal error is selected.
287 Transform calcShiftYUVSimple(StabData* sd)
289 printf("calc shoft yuv\n");
292 unsigned char *Y_c, *Y_p;// , *Cb, *Cr;
296 tc_snprintf(buffer, sizeof(buffer), "f%04i.dat", sd->t);
297 f = fopen(buffer, "w");
298 fprintf(f, "# splot \"%s\"\n", buffer);
301 // we only use the luminance part of the image
303 // Cb_c = sd->curr + sd->width*sd->height;
304 //Cr_c = sd->curr + 5*sd->width*sd->height/4;
306 //Cb_p = sd->prev + sd->width*sd->height;
307 //Cr_p = sd->prev + 5*sd->width*sd->height/4;
309 double minerror = 1e20;
310 for (i = -sd->maxshift; i <= sd->maxshift; i++) {
311 for (j = -sd->maxshift; j <= sd->maxshift; j++) {
312 double error = compareImg(Y_c, Y_p,
313 sd->width, sd->height, 1, i, j);
315 fprintf(f, "%i %i %f\n", i, j, error);
317 if (error < minerror) {
326 tc_log_msg(MOD_NAME, "Minerror: %f\n", minerror);
328 return new_transform(x, y, 0, 0, 0);
333 /* calculates rotation angle for the given transform and
334 * field with respect to the given center-point
336 double calcAngle(StabData* sd, Field* field, Transform* t,
337 int center_x, int center_y)
339 // we better ignore fields that are to close to the rotation center
340 if (abs(field->x - center_x) + abs(field->y - center_y) < sd->maxshift) {
343 // double r = sqrt(field->x*field->x + field->y*field->y);
344 double a1 = atan2(field->y - center_y, field->x - center_x);
345 double a2 = atan2(field->y - center_y + t->y,
346 field->x - center_x + t->x);
347 double diff = a2 - a1;
348 return (diff>M_PI) ? diff - 2*M_PI
349 : ( (diff<-M_PI) ? diff + 2*M_PI : diff);
354 /* calculates the optimal transformation for one field in YUV frames
357 Transform calcFieldTransYUV(StabData* sd, const Field* field, int fieldnum)
359 Transform t = null_transform();
360 unsigned char *Y_c = sd->curr, *Y_p = sd->prev;
361 // we only use the luminance part of the image
364 /* // check contrast in sub image */
365 /* double contr = contrastSubImg(Y_c, field, sd->width, sd->height, 1); */
366 /* if(contr < sd->contrast_threshold) { */
371 // printf("%i %i %f\n", sd->t, fieldnum, contr);
374 snprintf(buffer, sizeof(buffer), "f%04i_%02i.dat", sd->t, fieldnum);
375 f = fopen(buffer, "w");
376 fprintf(f, "# splot \"%s\"\n", buffer);
379 double minerror = 1e10;
381 for (i = -sd->maxshift; i <= sd->maxshift; i += sd->stepsize) {
382 for (j = -sd->maxshift; j <= sd->maxshift; j += sd->stepsize) {
383 error = compareSubImg(Y_c, Y_p, field,
384 sd->width, sd->height, 1, i, j);
386 fprintf(f, "%i %i %f\n", i, j, error);
388 if (error < minerror) {
396 if (sd->stepsize > 1) { // make fine grain check around the best match
397 int r = sd->stepsize - 1;
398 for (i = t.x - r; i <= t.x + r; i += 1) {
399 for (j = -t.y - r; j <= t.y + r; j += 1) {
400 if (i == t.x && j == t.y)
401 continue; //no need to check this since already done
402 error = compareSubImg(Y_c, Y_p, field,
403 sd->width, sd->height, 1, i, j);
405 fprintf(f, "%i %i %f\n", i, j, error);
407 if (error < minerror){
417 printf( "Minerror: %f\n", minerror);
420 if (!sd->allowmax && fabs(t.x) == sd->maxshift) {
422 printf( "maximal x shift ");
426 if (!sd->allowmax && fabs(t.y) == sd->maxshift) {
428 printf("maximal y shift ");
435 /* calculates the optimal transformation for one field in RGB
436 * slower than the YUV version because it uses all three color channels
438 Transform calcFieldTransRGB(StabData* sd, const Field* field, int fieldnum)
440 Transform t = null_transform();
441 unsigned char *I_c = sd->curr, *I_p = sd->prev;
444 double minerror = 1e20;
445 for (i = -sd->maxshift; i <= sd->maxshift; i += 2) {
446 for (j=-sd->maxshift; j <= sd->maxshift; j += 2) {
447 double error = compareSubImg(I_c, I_p, field,
448 sd->width, sd->height, 3, i, j);
449 if (error < minerror) {
456 for (i = t.x - 1; i <= t.x + 1; i += 2) {
457 for (j = -t.y - 1; j <= t.y + 1; j += 2) {
458 double error = compareSubImg(I_c, I_p, field,
459 sd->width, sd->height, 3, i, j);
460 if (error < minerror) {
467 if (!sd->allowmax && fabs(t.x) == sd->maxshift) {
470 if (!sd->allowmax && fabs(t.y) == sd->maxshift) {
476 /* compares contrast_idx structures respect to the contrast
479 int cmp_contrast_idx(const void *ci1, const void* ci2)
481 double a = ((contrast_idx*)ci1)->contrast;
482 double b = ((contrast_idx*)ci2)->contrast;
483 return a < b ? 1 : ( a > b ? -1 : 0 );
486 /* select only the best 'maxfields' fields
487 first calc contrasts then select from each part of the
490 tlist* selectfields(StabData* sd, contrastSubImgFunc contrastfunc)
493 tlist* goodflds = tlist_new(0);
494 contrast_idx *ci = malloc(sizeof(contrast_idx) * sd->field_num);
496 // we split all fields into row+1 segments and take from each segment
498 int numsegms = (sd->field_rows+1);
499 int segmlen = sd->field_num/(sd->field_rows+1)+1;
500 // split the frame list into rows+1 segments
501 contrast_idx *ci_segms = malloc(sizeof(contrast_idx) * sd->field_num);
503 // calculate contrast for each field
504 for (i = 0; i < sd->field_num; i++) {
505 ci[i].contrast = contrastfunc(sd, &sd->fields[i]);
507 if(ci[i].contrast < sd->contrast_threshold) ci[i].contrast = 0;
508 // else printf("%i %lf\n", ci[i].index, ci[i].contrast);
511 memcpy(ci_segms, ci, sizeof(contrast_idx) * sd->field_num);
512 // get best fields from each segment
513 for(i=0; i<numsegms; i++){
514 int startindex = segmlen*i;
515 int endindex = segmlen*(i+1);
516 endindex = endindex > sd->field_num ? sd->field_num : endindex;
517 //printf("Segment: %i: %i-%i\n", i, startindex, endindex);
519 // sort within segment
520 qsort(ci_segms+startindex, endindex-startindex,
521 sizeof(contrast_idx), cmp_contrast_idx);
522 // take maxfields/numsegms
523 for(j=0; j<sd->maxfields/numsegms; j++){
524 if(startindex+j >= endindex) continue;
525 // printf("%i %lf\n", ci_segms[startindex+j].index,
526 // ci_segms[startindex+j].contrast);
527 if(ci_segms[startindex+j].contrast > 0){
528 tlist_append(goodflds, &ci[ci_segms[startindex+j].index],sizeof(contrast_idx));
529 // don't consider them in the later selection process
530 ci_segms[startindex+j].contrast=0;
534 // check whether enough fields are selected
535 // printf("Phase2: %i\n", tc_list_size(goodflds));
536 remaining = sd->maxfields - tlist_size(goodflds);
538 // take the remaining from the leftovers
539 qsort(ci_segms, sd->field_num,
540 sizeof(contrast_idx), cmp_contrast_idx);
541 for(j=0; j < remaining; j++){
542 if(ci_segms[j].contrast > 0){
543 tlist_append(goodflds, &ci_segms[j], sizeof(contrast_idx));
547 // printf("Ende: %i\n", tc_list_size(goodflds));
555 /* tries to register current frame onto previous frame.
557 * check all fields for vertical and horizontal transformation
558 * use minimal difference of all possible positions
559 * discards fields with low contrast
560 * select maxfields field according to their contrast
561 * calculate shift as cleaned mean of all remaining fields
562 * calculate rotation angle of each field in respect to center of fields
563 * after shift removal
564 * calculate rotation angle as cleaned mean of all angles
565 * compensate for possibly off-center rotation
567 Transform calcTransFields(StabData* sd, calcFieldTransFunc fieldfunc,
568 contrastSubImgFunc contrastfunc)
570 Transform* ts = malloc(sizeof(Transform) * sd->field_num);
571 Field** fs = malloc(sizeof(Field*) * sd->field_num);
572 double *angles = malloc(sizeof(double) * sd->field_num);
573 int i, index=0, num_trans;
578 tc_snprintf(buffer, sizeof(buffer), "k%04i.dat", sd->t);
579 f = fopen(buffer, "w");
580 fprintf(f, "# plot \"%s\" w l, \"\" every 2:1:0\n", buffer);
584 tlist* goodflds = selectfields(sd, contrastfunc);
586 // use all "good" fields and calculate optimal match to previous frame
588 while((f = (contrast_idx*)tlist_pop(goodflds,0) ) != 0){
590 t = fieldfunc(sd, &sd->fields[i], i); // e.g. calcFieldTransYUV
592 fprintf(f, "%i %i\n%f %f %i\n \n\n", sd->fields[i].x, sd->fields[i].y,
593 sd->fields[i].x + t.x, sd->fields[i].y + t.y, t.extra);
595 if (t.extra != -1){ // ignore if extra == -1 (unused at the moment)
597 fs[index] = sd->fields+i;
601 tlist_fini(goodflds);
603 t = null_transform();
604 num_trans = index; // amount of transforms we actually have
606 printf( "too low contrast! No field remains.\n \
607 (no translations are detected in frame %i)", sd->t);
613 // calc center point of all remaining fields
614 for (i = 0; i < num_trans; i++) {
615 center_x += fs[i]->x;
616 center_y += fs[i]->y;
618 center_x /= num_trans;
619 center_y /= num_trans;
621 if (sd->show){ // draw fields and transforms into frame.
622 // this has to be done one after another to handle possible overlap
624 for (i = 0; i < num_trans; i++)
625 drawFieldScanArea(sd, fs[i], &ts[i]);
627 for (i = 0; i < num_trans; i++)
628 drawField(sd, fs[i], &ts[i]);
629 for (i = 0; i < num_trans; i++)
630 drawFieldTrans(sd, fs[i], &ts[i]);
632 /* median over all transforms
633 t= median_xy_transform(ts, sd->field_num);*/
635 t = cleanmean_xy_transform(ts, num_trans);
638 for (i = 0; i < num_trans; i++) {
639 ts[i] = sub_transforms(&ts[i], &t);
642 if (sd->field_num < 6) {
643 // the angle calculation is inaccurate for 5 and less fields
646 for (i = 0; i < num_trans; i++) {
647 angles[i] = calcAngle(sd, fs[i], &ts[i], center_x, center_y);
650 t.alpha = -cleanmean(angles, num_trans, &min, &max);
651 if(max-min>sd->maxanglevariation){
653 printf( "too large variation in angle(%f)\n",
658 // compensate for off-center rotation
659 double p_x = (center_x - sd->width/2);
660 double p_y = (center_y - sd->height/2);
661 t.x += (cos(t.alpha)-1)*p_x - sin(t.alpha)*p_y;
662 t.y += sin(t.alpha)*p_x + (cos(t.alpha)-1)*p_y;
670 /** draws the field scanning area */
671 void drawFieldScanArea(StabData* sd, const Field* field, const Transform* t)
673 if (!sd->pixelformat == mlt_image_yuv420p) {
674 printf("kein format\n");
677 drawBox(sd->curr, sd->width, sd->height, 1, field->x, field->y,
678 field->size+2*sd->maxshift, field->size+2*sd->maxshift, 80);
681 /** draws the field */
682 void drawField(StabData* sd, const Field* field, const Transform* t)
684 if (!sd->pixelformat == mlt_image_yuv420p){
685 printf("kein format\n");
688 drawBox(sd->curr, sd->width, sd->height, 1, field->x, field->y,
689 field->size, field->size, t->extra == -1 ? 100 : 40);
692 /** draws the transform data of this field */
693 void drawFieldTrans(StabData* sd, const Field* field, const Transform* t)
695 if (!sd->pixelformat == mlt_image_yuv420p){
696 printf("kein format\n");
699 drawBox(sd->curr, sd->width, sd->height, 1,
700 field->x, field->y, 5, 5, 128); // draw center
701 drawBox(sd->curr, sd->width, sd->height, 1,
702 field->x + t->x, field->y + t->y, 8, 8, 250); // draw translation
706 * draws a box at the given position x,y (center) in the given color
707 (the same for all channels)
709 void drawBox(unsigned char* I, int width, int height, int bytesPerPixel,
710 int x, int y, int sizex, int sizey, unsigned char color){
712 unsigned char* p = NULL;
714 p = I + ((x - sizex/2) + (y - sizey/2)*width)*bytesPerPixel;
715 for (j = 0; j < sizey; j++){
716 for (k = 0; k < sizex * bytesPerPixel; k++) {
720 p += (width - sizex) * bytesPerPixel;
729 static int stabilize_dump_trans(tlist*item, void *userdata)
731 struct iterdata *ID = userdata;
734 Transform* t = (Transform*) item->data;
735 fprintf(ID->f, "%i %6.4lf %6.4lf %8.5lf %6.4lf %i\n",
736 ID->counter, t->x, t->y, t->alpha, t->zoom, t->extra);
739 return 0; /* never give up */
743 /*************************************************************************/
745 /* Module interface routines and data. */
747 /*************************************************************************/
750 * stabilize_init: Initialize this instance of the module. See
751 * tcmodule-data.h for function details.
753 int stabilize_init(StabData* instance)
756 instance = malloc(sizeof(StabData)); // allocation with zero values
757 memset(instance,sizeof(StabData),0);
762 //stab->vob=pixelfmt;
763 /**** Initialise private data structure */
765 //self->userdata = sd;
771 * stabilize_configure: Configure this instance of the module. See
772 * tcmodule-data.h for function details.
774 int stabilize_configure(StabData* instance
775 /*const char *options,
777 /*TCModuleExtraData *xdata[]*/)
779 StabData *sd = instance;
780 /* sd->framesize = sd->vob->im_v_width * MAX_PLANES *
781 sizeof(char) * 2 * sd->vob->im_v_height * 2; */
782 /*TODO sd->framesize = sd->vob->im_v_size; */
783 sd->prev = calloc(1,sd->framesize);
785 printf( "malloc failed");
790 /*sd->width = sd->vob->ex_v_width;
791 sd->height = sd->vob->ex_v_height;
793 sd->hasSeenOneFrame = 0;
797 // done in filter : sd->stepsize = 6;
799 // done in filter :sd->algo = 1;
800 // sd->field_num = 64;
801 // done in filter : sd->accuracy = 4;
802 // done in filter : sd->shakiness = 4;
803 sd->field_size = MIN(sd->width, sd->height)/12;
804 // done in filter : sd->show = 0;
805 // done in filter : sd->contrast_threshold = 0.3;
806 sd->maxanglevariation = 1;
808 /*if (options != NULL) {
809 // for some reason this plugin is called in the old fashion
810 // (not with inspect). Anyway we support both ways of getting help.
811 if(optstr_lookup(options, "help")) {
812 printf(stabilize_help);
816 optstr_get(options, "shakiness", "%d", &sd->shakiness);
817 optstr_get(options, "accuracy", "%d", &sd->accuracy);
818 optstr_get(options, "stepsize", "%d", &sd->stepsize);
819 optstr_get(options, "algo", "%d", &sd->algo);
820 optstr_get(options, "mincontrast","%lf",&sd->contrast_threshold);
821 optstr_get(options, "show", "%d", &sd->show);
823 sd->shakiness = MIN(10,MAX(1,sd->shakiness));
824 sd->accuracy = MAX(sd->shakiness,MIN(15,MAX(1,sd->accuracy)));
826 printf( "Image Stabilization Settings:\n");
827 printf( " shakiness = %d\n", sd->shakiness);
828 printf( " accuracy = %d\n", sd->accuracy);
829 printf( " stepsize = %d\n", sd->stepsize);
830 printf( " algo = %d\n", sd->algo);
831 printf(" mincontrast = %f\n", sd->contrast_threshold);
832 printf( " show = %d\n", sd->show);
835 // shift and size: shakiness 1: height/40; 10: height/4
836 sd->maxshift = MIN(sd->width, sd->height)*sd->shakiness/40;
837 sd->field_size = MIN(sd->width, sd->height)*sd->shakiness/40;
839 printf( "Fieldsize: %i, Maximal translation: %i pixel\n",
840 sd->field_size, sd->maxshift);
842 // initialize measurement fields. field_num is set here.
843 if (!initFields(sd)) {
846 sd->maxfields = (sd->accuracy) * sd->field_num / 15;
847 printf( "Number of used measurement fields: %i out of %i\n",
848 sd->maxfields, sd->field_num);
851 sd->currcopy = malloc(sd->framesize);
852 memset ( sd->currcopy, sd->framesize, 0 );
855 /* load unsharp filter to smooth the frames. This allows larger stepsize.*/
856 char unsharp_param[128];
857 int masksize = MIN(13,sd->stepsize*1.8); // only works up to 13.
858 sprintf(unsharp_param,"luma=-1:luma_matrix=%ix%i:pre=1",
865 * stabilize_filter_video: performs the analysis of subsequent frames
866 * See tcmodule-data.h for function details.
869 int stabilize_filter_video(StabData* instance,
870 unsigned char *frame,mlt_image_format pixelformat)
872 StabData *sd = instance;
873 sd->pixelformat=pixelformat;
875 if(sd->show) // save the buffer to restore at the end for prev
876 memcpy(sd->currcopy, frame, sd->framesize);
877 if (sd->hasSeenOneFrame) {
879 if (pixelformat == mlt_image_rgb24) {
881 addTrans(sd, calcShiftRGBSimple(sd));
882 else if (sd->algo == 1)
883 addTrans(sd, calcTransFields(sd, calcFieldTransRGB,
885 } else if (pixelformat == mlt_image_yuv420p ) {
887 addTrans(sd, calcShiftYUVSimple(sd));
888 else if (sd->algo == 1)
889 addTrans(sd, calcTransFields(sd, calcFieldTransYUV,
892 printf("unsupported Codec: %i\n",
897 sd->hasSeenOneFrame = 1;
898 addTrans(sd, null_transform());
901 if(!sd->show) { // copy current frame to prev for next frame comparison
902 memcpy(sd->prev, frame, sd->framesize);
903 } else { // use the copy because we changed the original frame
904 memcpy(sd->prev, sd->currcopy, sd->framesize);
911 * stabilize_stop: Reset this instance of the module. See tcmodule-data.h
912 * for function details.
915 int stabilize_stop(StabData* instance)
917 StabData *sd = instance;
920 /*struct iterdata ID;
923 // write parameters as comments to file
924 fprintf(sd->f, "# accuracy = %d\n", sd->accuracy);
925 fprintf(sd->f, "# shakiness = %d\n", sd->shakiness);
926 fprintf(sd->f, "# stepsize = %d\n", sd->stepsize);
927 fprintf(sd->f, "# algo = %d\n", sd->algo);
928 fprintf(sd->f, "# mincontrast = %f\n", sd->contrast_threshold);
930 fprintf(sd->f, "# Transforms\n#C FrameNr x y alpha zoom extra\n");
931 // and all transforms
932 tc_list_foreach(sd->transs, stabilize_dump_trans, &ID);
934 tlist* transf=sd->transs;
937 Transform* t=transf->data;
939 printf("%d %f %f %f %f %d\n",num++,t->x,t->y,t->alpha,t->zoom,t->extra);
942 //tc_list_del(sd->transs, 1 );