Transform simpleMotionsToTransform(TransformData* td, const LocalMotions* motions){ int center_x = 0; int center_y = 0; Transform t = null_transform(); if(motions==0) return t; int num_motions=vs_vector_size(motions); double *angles = (double*) vs_malloc(sizeof(double) * num_motions); LocalMotion meanmotion; int i; if(num_motions < 1) return t; // calc center point of all remaining fields for (i = 0; i < num_motions; i++) { center_x += LMGet(motions,i)->f.x; center_y += LMGet(motions,i)->f.y; } center_x /= num_motions; center_y /= num_motions; // cleaned mean meanmotion = cleanmean_localmotions(motions); // figure out angle if (num_motions < 6) { // the angle calculation is inaccurate for 5 and less fields t.alpha = 0; } else { for (i = 0; i < num_motions; i++) { // substract avg and calc angle LocalMotion m = sub_localmotion(LMGet(motions,i),&meanmotion); angles[i] = calcAngle(&m, center_x, center_y); } double min, max; t.alpha = -cleanmean(angles, num_motions, &min, &max); if (max - min > td->maxAngleVariation) { t.alpha = 0; vs_log_info(td->modName, "too large variation in angle(%f)\n", max-min); } } vs_free(angles); // compensate for off-center rotation double p_x = (center_x - td->fiSrc.width / 2); double p_y = (center_y - td->fiSrc.height / 2); t.x = meanmotion.v.x + (cos(t.alpha) - 1) * p_x - sin(t.alpha) * p_y; t.y = meanmotion.v.y + sin(t.alpha) * p_x + (cos(t.alpha) - 1) * p_y; return t; }
/* tries to register current frame onto previous frame. * Algorithm: * discards fields with low contrast * select maxfields fields according to their contrast * check theses fields for vertical and horizontal transformation * use minimal difference of all possible positions * calculate shift as cleaned mean of all remaining fields * calculate rotation angle of each field in respect to center of fields * after shift removal * calculate rotation angle as cleaned mean of all angles * compensate for possibly off-center rotation */ Transform calcTransFields(MotionDetect* md, calcFieldTransFunc fieldfunc, contrastSubImgFunc contrastfunc) { Transform* ts = (Transform*) ds_malloc(sizeof(Transform) * md->fieldNum); Field** fs = (Field**) ds_malloc(sizeof(Field*) * md->fieldNum); double *angles = (double*) ds_malloc(sizeof(double) * md->fieldNum); int i, index = 0, num_trans; Transform t; #ifdef STABVERBOSE FILE *file = NULL; char buffer[32]; ds_snprintf(buffer, sizeof(buffer), "k%04i.dat", md->frameNum); file = fopen(buffer, "w"); fprintf(file, "# plot \"%s\" w l, \"\" every 2:1:0\n", buffer); #endif DSVector goodflds = selectfields(md, contrastfunc); // use all "good" fields and calculate optimal match to previous frame #ifdef USE_OMP #pragma omp parallel for shared(goodflds, md, ts, fs) // does not bring speedup #endif for(index=0; index < ds_vector_size(&goodflds); index++){ int i = ((contrast_idx*)ds_vector_get(&goodflds,index))->index; t = fieldfunc(md, &md->fields[i], i); // e.g. calcFieldTransYUV #ifdef STABVERBOSE fprintf(file, "%i %i\n%f %f %i\n \n\n", md->fields[i].x, md->fields[i].y, md->fields[i].x + t.x, md->fields[i].y + t.y, t.extra); #endif if (t.extra != -1) { // ignore if extra == -1 (unused at the moment) ts[index] = t; fs[index] = md->fields + i; } } t = null_transform(); num_trans = ds_vector_size(&goodflds); // amount of transforms we actually have ds_vector_del(&goodflds); if (num_trans < 1) { ds_log_warn(md->modName, "too low contrast! No field remains.\n" "(no translations are detected in frame %i)", md->frameNum); return t; } int center_x = 0; int center_y = 0; // calc center point of all remaining fields for (i = 0; i < num_trans; i++) { center_x += fs[i]->x; center_y += fs[i]->y; } center_x /= num_trans; center_y /= num_trans; if (md->show) { // draw fields and transforms into frame. // this has to be done one after another to handle possible overlap if (md->show > 1) { for (i = 0; i < num_trans; i++) drawFieldScanArea(md, fs[i], &ts[i]); } for (i = 0; i < num_trans; i++) drawField(md, fs[i], &ts[i]); for (i = 0; i < num_trans; i++) drawFieldTrans(md, fs[i], &ts[i]); } /* median over all transforms t= median_xy_transform(ts, md->field_num);*/ // cleaned mean t = cleanmean_xy_transform(ts, num_trans); // substract avg for (i = 0; i < num_trans; i++) { ts[i] = sub_transforms(&ts[i], &t); } // figure out angle if (md->fieldNum < 6) { // the angle calculation is inaccurate for 5 and less fields t.alpha = 0; } else { for (i = 0; i < num_trans; i++) { angles[i] = calcAngle(md, fs[i], &ts[i], center_x, center_y); } double min, max; t.alpha = -cleanmean(angles, num_trans, &min, &max); if (max - min > md->maxAngleVariation) { t.alpha = 0; ds_log_info(md->modName, "too large variation in angle(%f)\n", max-min); } } // compensate for off-center rotation double p_x = (center_x - md->fi.width / 2); double p_y = (center_y - md->fi.height / 2); t.x += (cos(t.alpha) - 1) * p_x - sin(t.alpha) * p_y; t.y += sin(t.alpha) * p_x + (cos(t.alpha) - 1) * p_y; #ifdef STABVERBOSE fclose(file); #endif return t; }