X-Git-Url: http://git.cinelerra-gg.org/git/?a=blobdiff_plain;f=cinelerra-5.1%2Fplugins%2Fmotion%2Fmotionscan.C;h=f5d536539cda984fa88be21341ca850ccb6b1e87;hb=166867a58d74619aa11aeb562a994cc364d62231;hp=0685b6562a9f51ebc15b7efb1d9de503b04f6ef3;hpb=7fd85fb66168f6b518c5f2d73e04036e87faa0e1;p=goodguy%2Fcinelerra.git diff --git a/cinelerra-5.1/plugins/motion/motionscan.C b/cinelerra-5.1/plugins/motion/motionscan.C index 0685b656..f5d53653 100644 --- a/cinelerra-5.1/plugins/motion/motionscan.C +++ b/cinelerra-5.1/plugins/motion/motionscan.C @@ -21,7 +21,7 @@ #include "clip.h" //#include "../downsample/downsampleengine.h" -//#include "motion.h" +#include "motion.h" #include "motionscan.h" #include "mutex.h" #include "vframe.h" @@ -78,7 +78,7 @@ void MotionScanUnit::process_package(LoadPackage *package) pkg->block_x2 - pkg->block_x1, pkg->block_y2 - pkg->block_y1, color_model); -// printf("MotionScanUnit::process_package %d search_x=%d search_y=%d diff=%lld\n", +// printf("MotionScanUnit::process_package %d search_x=%d search_y=%d diff=%ld\n", // __LINE__, server->block_x1 - pkg->search_x, server->block_y1 - pkg->search_y, pkg->difference1); server->put_cache(pkg->search_x, pkg->search_y, pkg->difference1); } @@ -129,10 +129,11 @@ void MotionScanUnit::put_cache(int x, int y, int64_t difference) cache_lock->unlock(); } -MotionScan::MotionScan(int total_clients, int total_packages) +MotionScan::MotionScan(MotionMain *plugin, int total_clients, int total_packages) : LoadServer( //1, 1 total_clients, total_packages) { + this->plugin = plugin; test_match = 1; cache_lock = new Mutex("MotionScan::cache_lock"); downsampled_previous = 0; @@ -164,21 +165,37 @@ void MotionScan::init_packages() pkg->dx = pkg->dy = 0; if( !subpixel ) { - pkg->search_x = pkg->scan_x1 + - (pkg->step % x_steps) * (scan_x2 - scan_x1) / x_steps; - pkg->search_y = pkg->scan_y1 + - (pkg->step / x_steps) * (scan_y2 - scan_y1) / y_steps; pkg->sub_x = pkg->sub_y = 0; + int ipkg = pkg->step; + if (ipkg == 0) + { +// First package additionally checks position nearest to the best found so far + pkg->search_x = x_result; + pkg->search_y = y_result; + if (pkg->search_x < pkg->scan_x1) pkg->search_x = pkg->scan_x1; + if (pkg->search_x >= pkg->scan_x2) pkg->search_x = pkg->scan_x2-1; + if (pkg->search_y < pkg->scan_y1) pkg->search_y = pkg->scan_y1; + if (pkg->search_y >= pkg->scan_y2) pkg->search_y = pkg->scan_y2-1; + } + else + { + ipkg --; + pkg->search_x = pkg->scan_x1 + (ipkg % x_steps) * + (scan_x2 - scan_x1) / x_steps; + pkg->search_y = pkg->scan_y1 + (ipkg / x_steps) * + (scan_y2 - scan_y1) / y_steps; + } } else { - pkg->sub_x = pkg->step % (OVERSAMPLE * 2); - pkg->sub_y = pkg->step / (OVERSAMPLE * 2); + pkg->sub_x = pkg->step % x_steps; + pkg->sub_y = pkg->step / x_steps; - if( horizontal_only ) pkg->sub_y = 0; - if( vertical_only ) pkg->sub_x = 0; +// Unidirectional cases already taken into account in x_steps and y_steps +// if( horizontal_only ) pkg->sub_y = 0; +// if( vertical_only ) pkg->sub_x = 0; - pkg->search_x = pkg->scan_x1 + pkg->sub_x / OVERSAMPLE + 1; - pkg->search_y = pkg->scan_y1 + pkg->sub_y / OVERSAMPLE + 1; + pkg->search_x = pkg->scan_x1 + pkg->sub_x / OVERSAMPLE; + pkg->search_y = pkg->scan_y1 + pkg->sub_y / OVERSAMPLE; pkg->sub_x %= OVERSAMPLE; pkg->sub_y %= OVERSAMPLE; @@ -214,7 +231,7 @@ void MotionScan::scan_frame(VFrame *previous_frame, VFrame *current_frame, int horizontal_only, int vertical_only, int source_position, int total_steps, int total_dx, int total_dy, int global_origin_x, int global_origin_y, - int load_ok, int load_dx, int load_dy) + int passno, int load_ok, int load_dx, int load_dy) { this->previous_frame_arg = previous_frame; this->current_frame_arg = current_frame; @@ -238,23 +255,56 @@ void MotionScan::scan_frame(VFrame *previous_frame, VFrame *current_frame, int block_w = w * global_block_w / 100; int block_h = h * global_block_h / 100; +// passno == 0: single pass tracking +// passno == 1: 1st pass of two-pass tracking (skip subpixel) +// passno == 2: 2nd pass of two-pass tracking (reduce search area) +// Save may be needed for 2nd pass + int dx_saved = 0; + int dy_saved = 0; + if (passno == 2) + { + dx_saved = dx_result; + dy_saved = dy_result; + } + // Location of block in previous frame - block_x1 = (int)(w * block_x / 100 - block_w / 2); - block_y1 = (int)(h * block_y / 100 - block_h / 2); - block_x2 = (int)(w * block_x / 100 + block_w / 2); - block_y2 = (int)(h * block_y / 100 + block_h / 2); + double tmp_x1, tmp_y1; + double tmp_x2, tmp_y2; + tmp_x1 = w * block_x / 100 - block_w / 2; + tmp_y1 = h * block_y / 100 - block_h / 2; + tmp_x2 = w * block_x / 100 + block_w / 2; + tmp_y2 = h * block_y / 100 + block_h / 2; + +// Attention, process_buffer feeds previous_frame and current_frame interchanged // Offset to location of previous block. This offset needn't be very accurate -// since it's the offset of the previous image and current image we want. +// since it's the offset on the previous image while current image is moved. +// Nevertheless compute it in floating point and round to int afterwards. if( frame_type == MotionScan::TRACK_PREVIOUS ) { - block_x1 += total_dx / OVERSAMPLE; - block_y1 += total_dy / OVERSAMPLE; - block_x2 += total_dx / OVERSAMPLE; - block_y2 += total_dy / OVERSAMPLE; + tmp_x1 += (double)total_dx / OVERSAMPLE; + tmp_y1 += (double)total_dy / OVERSAMPLE; + tmp_x2 += (double)total_dx / OVERSAMPLE; + tmp_y2 += (double)total_dy / OVERSAMPLE; +// Compensate displacement computed in the 1st pass + if (passno == 2) + { + tmp_x1 -= (double)dx_saved / OVERSAMPLE; + tmp_y1 -= (double)dy_saved / OVERSAMPLE; + tmp_x2 -= (double)dx_saved / OVERSAMPLE; + tmp_y2 -= (double)dy_saved / OVERSAMPLE; + } } - + block_x1 = lrint (tmp_x1); + block_y1 = lrint (tmp_y1); + block_x2 = lrint (tmp_x2); + block_y2 = lrint (tmp_y2); + +// Preinitialize sane translation results + dx_result = 0; + dy_result = 0; skip = 0; +//printf("MotionScan::scan_frame %d frame=%ld passno=%d\n", __LINE__, plugin->get_source_position(), passno); switch( tracking_type ) { // Don't calculate case MotionScan::NO_CALCULATE: @@ -267,19 +317,22 @@ void MotionScan::scan_frame(VFrame *previous_frame, VFrame *current_frame, if( load_ok ) { dx_result = load_dx; dy_result = load_dy; + if (passno == 2) dx_result = dy_result = 0; skip = 1; } break; -// Scan from scratch +// Scan from scratch with sane translation results default: + dx_result = 0; + dy_result = 0; skip = 0; break; } if( !skip && test_match ) { if( previous_frame->data_matches(current_frame) ) { - printf("MotionScan::scan_frame: data matches. skipping.\n"); +// printf("MotionScan::scan_frame: data matches. skipping.\n"); dx_result = dy_result = 0; skip = 1; } @@ -290,13 +343,25 @@ void MotionScan::scan_frame(VFrame *previous_frame, VFrame *current_frame, // Location of block in current frame int origin_offset_x = this->global_origin_x * w / 100; int origin_offset_y = this->global_origin_y * h / 100; - int x_result = block_x1 + origin_offset_x; - int y_result = block_y1 + origin_offset_y; + x_result = block_x1 + origin_offset_x; + y_result = block_y1 + origin_offset_y; + dx_result = 0; + dy_result = 0; //printf("MotionScan::scan_frame 1 %d %d %d %d %d %d %d %d\n", // block_x1 + block_w / 2, block_y1 + block_h / 2, // block_w, block_h, block_x1, block_y1, block_x2, block_y2); + if (passno == 2) + { +// Evtl reduce scan area for refinement pass to gain speed +// For 1st pass subpixel search will be skipped + if (scan_w > 64) scan_w /= 4; + else if (scan_w > 16) scan_w = 16; + if (scan_h > 64) scan_h /= 4; + else if (scan_h > 16) scan_h = 16; + } + while(1) { // Cache needs to be cleared if downsampling is used because the sums of // different downsamplings can't be compared. @@ -306,6 +371,8 @@ void MotionScan::scan_frame(VFrame *previous_frame, VFrame *current_frame, scan_y1 = y_result - scan_h / 2; scan_x2 = x_result + scan_w / 2; scan_y2 = y_result + scan_h / 2; + if (scan_x2 <= scan_x1) scan_x2 = scan_x1 + 1; + if (scan_y2 <= scan_y1) scan_y2 = scan_y1 + 1; // Zero out requested values if( horizontal_only ) { @@ -325,7 +392,7 @@ void MotionScan::scan_frame(VFrame *previous_frame, VFrame *current_frame, // printf("MotionScan::scan_frame 1 %d block_x1=%d block_y1=%d block_x2=%d block_y2=%d\n" // " scan_x1=%d scan_y1=%d scan_x2=%d scan_y2=%d\n" // " x_result=%d y_result=%d\n", __LINE__, block_x1, block_y1, block_x2, block_y2, -// scan_x1, scan_y1, scan_x2, scan_y2, x_result, y_result); +// scan_x1, scan_y1, scan_x2, scan_y2, x_result, y_result); // Give up if invalid coords. if (scan_y2 <= scan_y1 || scan_x2 <= scan_x1 || @@ -336,23 +403,25 @@ void MotionScan::scan_frame(VFrame *previous_frame, VFrame *current_frame, if( subpixel ) { //printf("MotionScan::scan_frame %d %d %d\n", __LINE__, x_result, y_result); -// Scan every subpixel in a 2 pixel * 2 pixel square - total_pixels = (2 * OVERSAMPLE) * (2 * OVERSAMPLE); - +// Scan every subpixel in a scan_w * scan_h pixel square + x_steps = (scan_x2 - scan_x1) * OVERSAMPLE; + y_steps = (scan_y2 - scan_y1) * OVERSAMPLE; + if(horizontal_only) y_steps = 1; + if(vertical_only) x_steps = 1; + if (x_steps < 1) x_steps = 1; + if (y_steps < 1) y_steps = 1; + + total_pixels = x_steps * y_steps; this->total_steps = total_pixels; -// These aren't used in subpixel - this->x_steps = OVERSAMPLE * 2; - this->y_steps = OVERSAMPLE * 2; set_package_count(this->total_steps); process_packages(); // Get least difference - int64_t min_difference = -1; + int64_t min_difference = -1, max_difference = -1, noiselev = -1; + double radius, best_radius; for( int i = 0; i < get_total_packages(); i++ ) { MotionScanPackage *pkg = (MotionScanPackage *)get_package(i); -//printf("MotionScan::scan_frame %d search_x=%d search_y=%d sub_x=%d sub_y=%d diff1=%lld diff2=%lld\n", -//__LINE__, pkg->search_x, pkg->search_y, pkg->sub_x, pkg->sub_y, pkg->difference1, pkg->difference2); if( pkg->difference1 < min_difference || min_difference == -1 ) { min_difference = pkg->difference1; @@ -363,9 +432,13 @@ void MotionScan::scan_frame(VFrame *previous_frame, VFrame *current_frame, // Fill in results dx_result = block_x1 * OVERSAMPLE - x_result; dy_result = block_y1 * OVERSAMPLE - y_result; -//printf("MotionScan::scan_frame %d dx_result=%d dy_result=%d diff=%lld\n", +//printf("MotionScan::scan_frame %d dx_result=%d dy_result=%d diff1=%ld\n", //__LINE__, dx_result, dy_result, min_difference); } + if(pkg->difference1 > max_difference || max_difference == -1) + { + max_difference = pkg->difference1; + } if( pkg->difference2 < min_difference ) { min_difference = pkg->difference2; @@ -375,9 +448,63 @@ void MotionScan::scan_frame(VFrame *previous_frame, VFrame *current_frame, dx_result = block_x1 * OVERSAMPLE - x_result; dy_result = block_y1 * OVERSAMPLE - y_result; -//printf("MotionScan::scan_frame %d dx_result=%d dy_result=%d diff=%lld\n", +//printf("MotionScan::scan_frame %d dx_result=%d dy_result=%d diff2=%ld\n", //__LINE__, dx_result, dy_result, min_difference); } + if(pkg->difference2 > max_difference) + { + max_difference = pkg->difference2; + } +//printf("MotionScan::scan_frame %d pkg=%d search_x=%d search_y=%d sub_x=%d sub_y=%d diff1=%ld diff2=%ld min_diff=%ld max_diff=%ld\n", +//__LINE__, i, pkg->search_x, pkg->search_y, pkg->sub_x, pkg->sub_y, pkg->difference1, pkg->difference2, min_difference, max_difference); + } +// Determine noise level (not active on pass 2) + noiselev = min_difference+(max_difference-min_difference)*plugin->config.noise_level/100; + if (passno == 2) noiselev = min_difference; +//printf("MotionScan::scan_frame min_diff=%ld max_diff=%ld noiselev=%ld\n", min_difference, max_difference, noiselev); + for(int i = 0; i < get_total_packages(); i++) + { + MotionScanPackage *pkg = (MotionScanPackage*)get_package(i); + if(pkg->difference1 <= noiselev) + { +// Below noise level - check subpixel translation radius + radius = hypot( + (double)((block_x1-pkg->search_x)*OVERSAMPLE-pkg->sub_x), + (double)((block_y1-pkg->search_y)*OVERSAMPLE-pkg->sub_y)); + best_radius = hypot((double)dx_result,(double)dy_result); + if(radius < best_radius || + (radius == best_radius && pkg->difference1 < min_difference)) + { +// Below noise level and smaller translation, memorize + min_difference = pkg->difference1; + x_result = pkg->search_x * OVERSAMPLE + pkg->sub_x; + y_result = pkg->search_y * OVERSAMPLE + pkg->sub_y; + dx_result = block_x1 * OVERSAMPLE - x_result; + dy_result = block_y1 * OVERSAMPLE - y_result; +//printf("MotionScan::scan_frame %d diff1 override=%d search_x=%d search_y=%d sub_x=%d sub_y=%d dx_result=%d dy_result=%d diff1=%ld min_diff=%ld\n", +//__LINE__, i, pkg->search_x, pkg->search_y, pkg->sub_x, pkg->sub_y, dx_result, dy_result, pkg->difference1, min_difference); + } + } + if(pkg->difference2 <= noiselev) + { +// Below noise level - check subpixel translation radius + radius = hypot( + (double)((block_x1-pkg->search_x)*OVERSAMPLE+pkg->sub_x), + (double)((block_y1-pkg->search_y)*OVERSAMPLE+pkg->sub_y)); + best_radius = hypot((double)dx_result,(double)dy_result); + if(radius < best_radius || + (radius == best_radius && pkg->difference2 < min_difference)) + { +// Below noise level and smaller translation, memorize + min_difference = pkg->difference2; + x_result = pkg->search_x * OVERSAMPLE - pkg->sub_x; + y_result = pkg->search_y * OVERSAMPLE - pkg->sub_y; + dx_result = block_x1 * OVERSAMPLE - x_result; + dy_result = block_y1 * OVERSAMPLE - y_result; +//printf("MotionScan::scan_frame %d diff2 override=%d search_x=%d search_y=%d sub_x=%d sub_y=%d dx_result=%d dy_result=%d diff2=%ld min_diff=%ld\n", +//__LINE__, i, pkg->search_x, pkg->search_y, pkg->sub_x, pkg->sub_y, dx_result, dy_result, pkg->difference2, min_difference); + } + } } break; @@ -397,6 +524,11 @@ void MotionScan::scan_frame(VFrame *previous_frame, VFrame *current_frame, x_steps = (int)sqrt(this->total_steps); y_steps = (int)sqrt(this->total_steps); } + if(horizontal_only) y_steps = 1; + if(vertical_only) x_steps = 1; + if (x_steps < 1) x_steps = 1; + if (y_steps < 1) y_steps = 1; + this->total_steps = x_steps * y_steps; // Use downsampled images // if( scan_x2 - scan_x1 > x_steps * 4 || @@ -445,37 +577,107 @@ void MotionScan::scan_frame(VFrame *previous_frame, VFrame *current_frame, // printf("MotionScan::scan_frame %d this->total_steps=%d\n", // __LINE__, this->total_steps); - set_package_count(this->total_steps); +// One extra step for the position with zero translation + set_package_count(this->total_steps+1); process_packages(); // Get least difference - int64_t min_difference = -1; + int64_t min_difference = -1, max_difference = -1, noiselev = -1; + double radius, best_radius; for( int i = 0; i < get_total_packages(); i++ ) { MotionScanPackage *pkg = (MotionScanPackage *) get_package(i); -//printf("MotionScan::scan_frame %d search_x=%d search_y=%d sub_x=%d sub_y=%d diff1=%lld diff2=%lld\n", -// __LINE__, pkg->search_x, pkg->search_y, pkg->sub_x, pkg->sub_y, pkg->difference1, pkg->difference2); if (pkg->difference1 < min_difference || min_difference == -1) { min_difference = pkg->difference1; x_result = pkg->search_x; y_result = pkg->search_y; - x_result *= OVERSAMPLE; - y_result *= OVERSAMPLE; -//printf("MotionScan::scan_frame %d x_result=%d y_result=%d diff=%lld\n", -//__LINE__, block_x1 * OVERSAMPLE - x_result, block_y1 * OVERSAMPLE - y_result, pkg->difference1); + } + if(pkg->difference1 > max_difference || max_difference == -1) + { + max_difference = pkg->difference1; + } +//printf("MotionScan::scan_frame %d pkg=%d search_x=%d search_y=%d diff=%ld min_diff=%ld max_diff=%ld\n", +//__LINE__, i, pkg->search_x, pkg->search_y, pkg->difference1, min_difference, max_difference); + } +// Determine noise level (not active on pass 2) + noiselev = min_difference+(max_difference-min_difference)*plugin->config.noise_level/100; + if (passno == 2) noiselev = min_difference; +//printf("MotionScan::scan_frame min_diff=%ld max_diff=%ld noiselev=%ld\n", min_difference, max_difference, noiselev); + for(int i = 0; i < get_total_packages(); i++) + { + MotionScanPackage *pkg = (MotionScanPackage*)get_package(i); +// Already found as the best search, not necessary to memorize + if(x_result == pkg->search_x && y_result == pkg->search_y) continue; +// Above noise level - a definitely bad search, skip + if(pkg->difference1 > noiselev) continue; + radius = hypot((double)(block_x1-pkg->search_x),(double)(block_y1-pkg->search_y)); + best_radius = hypot((double)(block_x1-x_result),(double)(block_y1-y_result)); +// Below noise level but bigger translation, skip + if(radius > best_radius) continue; +// Below noise level and smaller translation, memorize + if(radius < best_radius) + { + min_difference = pkg->difference1; + x_result = pkg->search_x; + y_result = pkg->search_y; +//printf("MotionScan::scan_frame %d search override=%d search_x=%d search_y=%d diff=%ld min_diff=%ld\n", +//__LINE__, i, pkg->search_x, pkg->search_y, pkg->difference1, min_difference); + continue; + } +// Equal translations, memorize search with min difference + if(pkg->difference1 < min_difference) + { + min_difference = pkg->difference1; + x_result = pkg->search_x; + y_result = pkg->search_y; +//printf("MotionScan::scan_frame %d difference override=%d search_x=%d search_y=%d diff=%ld min_diff=%ld\n", +//__LINE__, i, pkg->search_x, pkg->search_y, pkg->difference1, min_difference); + continue; + } + } + int rad_x = 0, rad_y = 0; + for(int i = 0; i < get_total_packages(); i++) + { + MotionScanPackage *pkg = (MotionScanPackage*)get_package(i); +// Above noise level - skip this radius + if(pkg->difference1 > noiselev) continue; +// Below noise level - measure max distance from the best position + if(rad_x < abs(x_result-pkg->search_x)) + { + rad_x = abs(x_result-pkg->search_x); +//printf("MotionScan::scan_frame %d X-radius override=%d search_x=%d radius=%d\n", +//__LINE__, i, pkg->search_x, rad_x); + } + if(rad_y < abs(y_result-pkg->search_y)) + { + rad_y = abs(y_result-pkg->search_y); +//printf("MotionScan::scan_frame %d Y-radius override=%d search_y=%d radius=%d\n", +//__LINE__, i, pkg->search_y, rad_y); } } + x_result *= OVERSAMPLE; + y_result *= OVERSAMPLE; +//printf("MotionScan::scan_frame %d dx_result=%d dy_result=%d diff=%ld\n", +//__LINE__, block_x1 * OVERSAMPLE - x_result, block_y1 * OVERSAMPLE - y_result, min_difference); // If a new search is required, rescale results back to pixels. if( this->total_steps >= total_pixels ) { // Single pixel accuracy reached. Now do exhaustive subpixel search. - if( action_type == MotionScan::STABILIZE || - action_type == MotionScan::TRACK || - action_type == MotionScan::NOTHING ) { +// Subpixel search skipped on the 1st pass of a two-pass search. + if((action_type == MotionScan::STABILIZE || + action_type == MotionScan::TRACK || + action_type == MotionScan::NOTHING) && + passno != 1) + { //printf("MotionScan::scan_frame %d %d %d\n", __LINE__, x_result, y_result); +// Subpixel scan area might be +/- one pixel from the best position + scan_w = 2; + scan_h = 2; +// Evtl expand scan area to +/- two pixels if some samples below noise + if (rad_x > 0) scan_w = 4; + if (rad_y > 0) scan_h = 4; x_result /= OVERSAMPLE; y_result /= OVERSAMPLE; - scan_w = scan_h = 2; subpixel = 1; } // Fill in results and quit @@ -488,13 +690,27 @@ void MotionScan::scan_frame(VFrame *previous_frame, VFrame *current_frame, } // Reduce scan area and try again else { - scan_w = (scan_x2 - scan_x1) / 2; - scan_h = (scan_y2 - scan_y1) / 2; +// Optimum new scan area might be +/- one search step from the best position + scan_w = (scan_x2 - scan_x1) * 2 / x_steps; + scan_h = (scan_y2 - scan_y1) * 2 / y_steps; +// Evtl expand scan area to +/- two search steps if some samples below noise + if (rad_x > 0) scan_w = (scan_x2 - scan_x1) * 4 / x_steps; + if (rad_y > 0) scan_h = (scan_y2 - scan_y1) * 4 / y_steps; +// Evtl expand scan area to include samples below noise level + if (scan_w < rad_x * 2) scan_w = rad_x * 2; + if (scan_h < rad_y * 2) scan_h = rad_y * 2; +// Always reduce scan area at least twice + if (scan_w > (scan_x2 - scan_x1) / 2) scan_w = (scan_x2 - scan_x1) / 2; + if (scan_h > (scan_y2 - scan_y1) / 2) scan_h = (scan_y2 - scan_y1) / 2; +// But retain scan area at least one pixel in size + if (scan_w < 1) scan_w = 1; + if (scan_h < 1) scan_h = 1; x_result /= OVERSAMPLE; y_result /= OVERSAMPLE; } } } +// Negate results as previous_frame and current_frame have been interchanged dx_result = -dx_result; dy_result = -dy_result; } @@ -503,8 +719,14 @@ void MotionScan::scan_frame(VFrame *previous_frame, VFrame *current_frame, if( vertical_only ) dx_result = 0; if( horizontal_only ) dy_result = 0; -//printf("MotionScan::scan_frame %d dx=%.2f dy=%.2f\n", -// __LINE__, (float)this->dx_result / OVERSAMPLE, (float)this->dy_result / OVERSAMPLE); +// printf("MotionScan::scan_frame %d passno=%d saved dx=%.2f dy=%.2f measured dx=%.2f dy=%.2f twopass dx=%.2f dy=%.2f\n", +// __LINE__, passno, +// (float)dx_saved / OVERSAMPLE, +// (float)dy_saved / OVERSAMPLE, +// (float)this->dx_result / OVERSAMPLE, +// (float)this->dy_result / OVERSAMPLE, +// (float)(this->dx_result + dx_saved) / OVERSAMPLE, +// (float)(this->dy_result + dy_saved) / OVERSAMPLE); } int64_t MotionScan::get_cache(int x, int y)