/*
* CINELERRA
- * Copyright (C) 2016 Adam Williams <broadcast at earthling dot net>
- *
+ * Copyright (C) 2012 Adam Williams <broadcast at earthling dot net>
+ *
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
- *
+ *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
+ *
*/
-#include "affine.h"
-#include "bcsignals.h"
#include "clip.h"
+//#include "../downsample/downsampleengine.h"
+//#include "motion.h"
#include "motionscan.h"
#include "mutex.h"
#include "vframe.h"
-
#include <math.h>
-#include <stdlib.h>
-#include <string.h>
// The module which does the actual scanning
-// starting level of detail
-#define STARTING_DOWNSAMPLE 16
-// minimum size in each level of detail
-#define MIN_DOWNSAMPLED_SIZE 16
-// minimum scan range
-#define MIN_DOWNSAMPLED_SCAN 4
-// scan range for subpixel mode
-#define SUBPIXEL_RANGE 4
-
MotionScanPackage::MotionScanPackage()
: LoadPackage()
{
valid = 1;
}
-
-
-
-
-
MotionScanUnit::MotionScanUnit(MotionScan *server)
: LoadClient(server)
{
this->server = server;
+ cache_lock = new Mutex("MotionScanUnit::cache_lock");
}
MotionScanUnit::~MotionScanUnit()
{
+ delete cache_lock;
}
-
-void MotionScanUnit::single_pixel(MotionScanPackage *pkg)
+void MotionScanUnit::process_package(LoadPackage *package)
{
+ MotionScanPackage *pkg = (MotionScanPackage*)package;
//int w = server->current_frame->get_w();
//int h = server->current_frame->get_h();
int color_model = server->current_frame->get_color_model();
int pixel_size = BC_CModels::calculate_pixelsize(color_model);
int row_bytes = server->current_frame->get_bytes_per_line();
-// printf("MotionScanUnit::process_package %d search_x=%d search_y=%d scan_x1=%d scan_y1=%d scan_x2=%d scan_y2=%d x_steps=%d y_steps=%d\n",
-// __LINE__,
-// pkg->search_x,
-// pkg->search_y,
-// pkg->scan_x1,
-// pkg->scan_y1,
-// pkg->scan_x2,
-// pkg->scan_y2,
-// server->x_steps,
-// server->y_steps);
-
+// Single pixel
+ if( !server->subpixel ) {
+// Try cache
+ pkg->difference1 = server->get_cache(pkg->search_x, pkg->search_y);
+ if( pkg->difference1 < 0 ) {
+//printf("MotionScanUnit::process_package 1 search_x=%d search_y=%d"
+// " scan_x1=%d scan_y1=%d scan_x2=%d scan_y2=%d x_steps=%d y_steps=%d\n",
+// pkg->search_x, pkg->search_y, pkg->scan_x1, pkg->scan_y1, pkg->scan_x2, pkg->scan_y2,
+// server->x_steps, server->y_steps);
// Pointers to first pixel in each block
- unsigned char *prev_ptr = server->previous_frame->get_rows()[
- pkg->search_y] +
- pkg->search_x * pixel_size;
- unsigned char *current_ptr = 0;
-
- if(server->do_rotate)
- {
- current_ptr = server->rotated_current[pkg->angle_step]->get_rows()[
- pkg->block_y1] +
- pkg->block_x1 * pixel_size;
- }
- else
- {
- current_ptr = server->current_frame->get_rows()[
- pkg->block_y1] +
- pkg->block_x1 * pixel_size;
- }
-
+ unsigned char *prev_ptr =
+ server->previous_frame->get_rows()[pkg->search_y] +
+ pkg->search_x * pixel_size;
+ unsigned char *current_ptr =
+ server->current_frame->get_rows()[pkg->block_y1] +
+ pkg->block_x1 * pixel_size;
// Scan block
- pkg->difference1 = MotionScan::abs_diff(prev_ptr,
- current_ptr,
- row_bytes,
- pkg->block_x2 - pkg->block_x1,
- pkg->block_y2 - pkg->block_y1,
- color_model);
-
-// printf("MotionScanUnit::process_package %d angle_step=%d diff=%d\n",
-// __LINE__,
-// pkg->angle_step,
-// pkg->difference1);
+ pkg->difference1 = MotionScan::abs_diff(prev_ptr, current_ptr, row_bytes,
+ 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",
// __LINE__, server->block_x1 - pkg->search_x, server->block_y1 - pkg->search_y, pkg->difference1);
-}
-
-void MotionScanUnit::subpixel(MotionScanPackage *pkg)
-{
-//PRINT_TRACE
- //int w = server->current_frame->get_w();
- //int h = server->current_frame->get_h();
- int color_model = server->current_frame->get_color_model();
- int pixel_size = BC_CModels::calculate_pixelsize(color_model);
- int row_bytes = server->current_frame->get_bytes_per_line();
- unsigned char *prev_ptr = server->previous_frame->get_rows()[
- pkg->search_y] +
- pkg->search_x * pixel_size;
-// neglect rotation
- unsigned char *current_ptr = server->current_frame->get_rows()[
- pkg->block_y1] +
- pkg->block_x1 * pixel_size;
+ server->put_cache(pkg->search_x, pkg->search_y, pkg->difference1);
+ }
+ }
+// Sub pixel
+ else {
+ unsigned char *prev_ptr =
+ server->previous_frame->get_rows()[pkg->search_y] +
+ pkg->search_x * pixel_size;
+ unsigned char *current_ptr =
+ server->current_frame->get_rows()[pkg->block_y1] +
+ pkg->block_x1 * pixel_size;
// With subpixel, there are two ways to compare each position, one by shifting
// the previous frame and two by shifting the current frame.
- pkg->difference1 = MotionScan::abs_diff_sub(prev_ptr,
- current_ptr,
- row_bytes,
- pkg->block_x2 - pkg->block_x1,
- pkg->block_y2 - pkg->block_y1,
- color_model,
- pkg->sub_x,
- pkg->sub_y);
- pkg->difference2 = MotionScan::abs_diff_sub(current_ptr,
- prev_ptr,
- row_bytes,
- pkg->block_x2 - pkg->block_x1,
- pkg->block_y2 - pkg->block_y1,
- color_model,
- pkg->sub_x,
- pkg->sub_y);
-// printf("MotionScanUnit::process_package sub_x=%d sub_y=%d search_x=%d search_y=%d diff1=%lld diff2=%lld\n",
-// pkg->sub_x,
-// pkg->sub_y,
-// pkg->search_x,
-// pkg->search_y,
-// pkg->difference1,
-// pkg->difference2);
+ pkg->difference1 = MotionScan::abs_diff_sub(prev_ptr, current_ptr, row_bytes,
+ pkg->block_x2 - pkg->block_x1, pkg->block_y2 - pkg->block_y1,
+ color_model, pkg->sub_x, pkg->sub_y);
+ pkg->difference2 =
+ MotionScan::abs_diff_sub(current_ptr, prev_ptr, row_bytes,
+ pkg->block_x2 - pkg->block_x1, pkg->block_y2 - pkg->block_y1,
+ color_model, pkg->sub_x, pkg->sub_y);
+//printf("MotionScanUnit::process_package sub_x=%d sub_y=%d search_x=%d search_y=%d diff1=%lld diff2=%lld\n",
+// sub_x, sub_y, search_x, search_y, pkg->difference1, pkg->difference2);
+ }
}
-void MotionScanUnit::process_package(LoadPackage *package)
+int64_t MotionScanUnit::get_cache(int x, int y)
{
- MotionScanPackage *pkg = (MotionScanPackage*)package;
-
-
-// Single pixel
- if(!server->subpixel)
- {
- single_pixel(pkg);
- }
- else
-// Sub pixel
- {
- subpixel(pkg);
+ int64_t result = -1;
+ cache_lock->lock("MotionScanUnit::get_cache");
+ for( int i = 0; i < cache.total; i++ ) {
+ MotionScanCache *ptr = cache.values[i];
+ if( ptr->x == x && ptr->y == y ) {
+ result = ptr->difference;
+ break;
+ }
}
-
-
-
-
+ cache_lock->unlock();
+ return result;
}
+void MotionScanUnit::put_cache(int x, int y, int64_t difference)
+{
+ MotionScanCache *ptr = new MotionScanCache(x, y, difference);
+ cache_lock->lock("MotionScanUnit::put_cache");
+ cache.append(ptr);
+ cache_lock->unlock();
+}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-MotionScan::MotionScan(int total_clients,
- int total_packages)
- : LoadServer(
-// DEBUG
-//1, 1
-total_clients, total_packages
-)
+MotionScan::MotionScan(int total_clients, int total_packages)
+ : LoadServer( //1, 1
+ total_clients, total_packages)
{
test_match = 1;
+ cache_lock = new Mutex("MotionScan::cache_lock");
downsampled_previous = 0;
downsampled_current = 0;
- rotated_current = 0;
- rotater = 0;
+// downsample = 0;
}
MotionScan::~MotionScan()
{
+ delete cache_lock;
delete downsampled_previous;
delete downsampled_current;
- if(rotated_current)
- {
- for(int i = 0; i < total_rotated; i++)
- {
- delete rotated_current[i];
- }
-
- delete [] rotated_current;
- }
- delete rotater;
+// delete downsample;
}
-
void MotionScan::init_packages()
{
// Set package coords
-// Total range of positions to scan with downsampling
- int downsampled_scan_x1 = scan_x1 / current_downsample;
- //int downsampled_scan_x2 = scan_x2 / current_downsample;
- int downsampled_scan_y1 = scan_y1 / current_downsample;
- //int downsampled_scan_y2 = scan_y2 / current_downsample;
- int downsampled_block_x1 = block_x1 / current_downsample;
- int downsampled_block_x2 = block_x2 / current_downsample;
- int downsampled_block_y1 = block_y1 / current_downsample;
- int downsampled_block_y2 = block_y2 / current_downsample;
-
-
//printf("MotionScan::init_packages %d %d\n", __LINE__, get_total_packages());
-// printf("MotionScan::init_packages %d current_downsample=%d scan_x1=%d scan_x2=%d block_x1=%d block_x2=%d\n",
-// __LINE__,
-// current_downsample,
-// downsampled_scan_x1,
-// downsampled_scan_x2,
-// downsampled_block_x1,
-// downsampled_block_x2);
-// if(current_downsample == 8 && downsampled_scan_x1 == 47)
-// {
-// downsampled_previous->write_png("/tmp/previous");
-// downsampled_current->write_png("/tmp/current");
-// }
-
- for(int i = 0; i < get_total_packages(); i++)
- {
+ for( int i = 0; i < get_total_packages(); i++ ) {
MotionScanPackage *pkg = (MotionScanPackage*)get_package(i);
- pkg->block_x1 = downsampled_block_x1;
- pkg->block_x2 = downsampled_block_x2;
- pkg->block_y1 = downsampled_block_y1;
- pkg->block_y2 = downsampled_block_y2;
- pkg->difference1 = 0;
- pkg->difference2 = 0;
- pkg->dx = 0;
- pkg->dy = 0;
- pkg->valid = 1;
- pkg->angle_step = 0;
-
- if(!subpixel)
- {
- if(rotation_pass)
- {
- pkg->search_x = scan_x1 / current_downsample;
- pkg->search_y = scan_y1 / current_downsample;
- pkg->angle_step = i;
- }
- else
- {
-
- int current_x_step = (i % x_steps);
- int current_y_step = (i / x_steps);
-
- //printf("MotionScan::init_packages %d i=%d x_step=%d y_step=%d angle_step=%d\n",
- //__LINE__, i, current_x_step, current_y_step, current_angle_step);
- pkg->search_x = downsampled_scan_x1 + current_x_step *
- (scan_x2 - scan_x1) / current_downsample / x_steps;
- pkg->search_y = downsampled_scan_y1 + current_y_step *
- (scan_y2 - scan_y1) / current_downsample / y_steps;
-
- if(do_rotate)
- {
- pkg->angle_step = angle_steps / 2;
- }
- else
- {
- pkg->angle_step = 0;
- }
- }
-
- pkg->sub_x = 0;
- pkg->sub_y = 0;
+ pkg->block_x1 = block_x1; pkg->block_x2 = block_x2;
+ pkg->block_y1 = block_y1; pkg->block_y2 = block_y2;
+ pkg->scan_x1 = scan_x1; pkg->scan_x2 = scan_x2;
+ pkg->scan_y1 = scan_y1; pkg->scan_y2 = scan_y2;
+ pkg->difference1 = 0; pkg->difference2 = 0;
+ pkg->step = i; pkg->valid = 1;
+ 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;
}
- else
- {
- pkg->sub_x = i % (OVERSAMPLE * SUBPIXEL_RANGE);
- pkg->sub_y = i / (OVERSAMPLE * SUBPIXEL_RANGE);
-
-// if(horizontal_only)
-// {
-// pkg->sub_y = 0;
-// }
-//
-// if(vertical_only)
-// {
-// pkg->sub_x = 0;
-// }
-
- pkg->search_x = scan_x1 + pkg->sub_x / OVERSAMPLE + 1;
- pkg->search_y = scan_y1 + pkg->sub_y / OVERSAMPLE + 1;
- pkg->sub_x %= OVERSAMPLE;
- pkg->sub_y %= OVERSAMPLE;
+ else {
+ pkg->sub_x = pkg->step % (OVERSAMPLE * 2);
+ pkg->sub_y = pkg->step / (OVERSAMPLE * 2);
+ 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->sub_x %= OVERSAMPLE;
+ pkg->sub_y %= OVERSAMPLE;
-// printf("MotionScan::init_packages %d i=%d search_x=%d search_y=%d sub_x=%d sub_y=%d\n",
-// __LINE__,
-// i,
-// pkg->search_x,
-// pkg->search_y,
-// pkg->sub_x,
-// pkg->sub_y);
+// printf("MotionScan::init_packages %d i=%d search_x=%d search_y=%d sub_x=%d sub_y=%d\n",
+// __LINE__, i, pkg->search_x, pkg->search_y, pkg->sub_x, pkg->sub_y);
}
// printf("MotionScan::init_packages %d %d,%d %d,%d %d,%d\n",
-// __LINE__,
-// scan_x1,
-// scan_x2,
-// scan_y1,
-// scan_y2,
-// pkg->search_x,
-// pkg->search_y);
+// __LINE__, scan_x1, scan_x2, scan_y1, scan_y2, pkg->search_x, pkg->search_y);
}
}
return new MotionScanPackage;
}
-
void MotionScan::set_test_match(int value)
{
this->test_match = value;
}
-
-
-
-#define DOWNSAMPLE(type, temp_type, components, max) \
-{ \
- temp_type r; \
- temp_type g; \
- temp_type b; \
- temp_type a; \
- type **in_rows = (type**)src->get_rows(); \
- type **out_rows = (type**)dst->get_rows(); \
- \
- for(int i = 0; i < h; i += downsample) \
- { \
- int y1 = MAX(i, 0); \
- int y2 = MIN(i + downsample, h); \
- \
- \
- for(int j = 0; \
- j < w; \
- j += downsample) \
- { \
- int x1 = MAX(j, 0); \
- int x2 = MIN(j + downsample, w); \
- \
- temp_type scale = (x2 - x1) * (y2 - y1); \
- if(x2 > x1 && y2 > y1) \
- { \
- \
-/* Read in values */ \
- r = 0; \
- g = 0; \
- b = 0; \
- if(components == 4) a = 0; \
- \
- for(int k = y1; k < y2; k++) \
- { \
- type *row = in_rows[k] + x1 * components; \
- for(int l = x1; l < x2; l++) \
- { \
- r += *row++; \
- g += *row++; \
- b += *row++; \
- if(components == 4) a += *row++; \
- } \
- } \
- \
-/* Write average */ \
- r /= scale; \
- g /= scale; \
- b /= scale; \
- if(components == 4) a /= scale; \
- \
- type *row = out_rows[y1 / downsample] + \
- x1 / downsample * components; \
- *row++ = r; \
- *row++ = g; \
- *row++ = b; \
- if(components == 4) *row++ = a; \
- } \
- } \
-/*printf("DOWNSAMPLE 3 %d\n", i);*/ \
- } \
-}
-
-
-
-
-void MotionScan::downsample_frame(VFrame *dst,
- VFrame *src,
- int downsample)
-{
- int h = src->get_h();
- int w = src->get_w();
-
-//PRINT_TRACE
-//printf("downsample=%d w=%d h=%d dst=%d %d\n", downsample, w, h, dst->get_w(), dst->get_h());
- switch(src->get_color_model())
- {
- case BC_RGB888:
- DOWNSAMPLE(uint8_t, int64_t, 3, 0xff)
- break;
- case BC_RGB_FLOAT:
- DOWNSAMPLE(float, float, 3, 1.0)
- break;
- case BC_RGBA8888:
- DOWNSAMPLE(uint8_t, int64_t, 4, 0xff)
- break;
- case BC_RGBA_FLOAT:
- DOWNSAMPLE(float, float, 4, 1.0)
- break;
- case BC_YUV888:
- DOWNSAMPLE(uint8_t, int64_t, 3, 0xff)
- break;
- case BC_YUVA8888:
- DOWNSAMPLE(uint8_t, int64_t, 4, 0xff)
- break;
- }
-//PRINT_TRACE
-}
-
-double MotionScan::step_to_angle(int step, double center)
-{
- if(step < angle_steps / 2)
- {
- return center - angle_step * (angle_steps / 2 - step);
- }
- else
- if(step > angle_steps / 2)
- {
- return center + angle_step * (step - angle_steps / 2);
- }
- else
- {
- return center;
- }
-}
-
-#ifdef STDDEV_TEST
-static int compare(const void *p1, const void *p2)
-{
- double value1 = *(double*)p1;
- double value2 = *(double*)p2;
-
-//printf("compare %d value1=%f value2=%f\n", __LINE__, value1, value2);
- return value1 > value2;
-}
-#endif
-
-// reject vectors based on content. It's the reason Goog can't stabilize timelapses.
-//#define STDDEV_TEST
-
-// pixel accurate motion search
-void MotionScan::pixel_search(int &x_result, int &y_result, double &r_result)
-{
-// reduce level of detail until enough steps
- while(current_downsample > 1 &&
- ((block_x2 - block_x1) / current_downsample < MIN_DOWNSAMPLED_SIZE ||
- (block_y2 - block_y1) / current_downsample < MIN_DOWNSAMPLED_SIZE
- ||
- (scan_x2 - scan_x1) / current_downsample < MIN_DOWNSAMPLED_SCAN ||
- (scan_y2 - scan_y1) / current_downsample < MIN_DOWNSAMPLED_SCAN
- ))
- {
- current_downsample /= 2;
- }
-
-
-
-// create downsampled images.
-// Need to keep entire frame to search for rotation.
- int downsampled_prev_w = previous_frame_arg->get_w() / current_downsample;
- int downsampled_prev_h = previous_frame_arg->get_h() / current_downsample;
- int downsampled_current_w = current_frame_arg->get_w() / current_downsample;
- int downsampled_current_h = current_frame_arg->get_h() / current_downsample;
-
-// printf("MotionScan::pixel_search %d current_downsample=%d current_frame_arg->get_w()=%d downsampled_current_w=%d\n",
-// __LINE__,
-// current_downsample,
-// current_frame_arg->get_w(),
-// downsampled_current_w);
-
- x_steps = (scan_x2 - scan_x1) / current_downsample;
- y_steps = (scan_y2 - scan_y1) / current_downsample;
-
-// in rads
- double test_angle1 = atan2((double)downsampled_current_h / 2 - 1, (double)downsampled_current_w / 2);
- double test_angle2 = atan2((double)downsampled_current_h / 2, (double)downsampled_current_w / 2 - 1);
-
-// in deg
- angle_step = 360.0f * fabs(test_angle1 - test_angle2) / 2 / M_PI;
-
-// printf("MotionScan::pixel_search %d test_angle1=%f test_angle2=%f angle_step=%f\n",
-// __LINE__,
-// 360.0f * test_angle1 / 2 / M_PI,
-// 360.0f * test_angle2 / 2 / M_PI,
-// angle_step);
-
-
- if(do_rotate && angle_step < rotation_range)
- {
- angle_steps = 1 + (int)((scan_angle2 - scan_angle1) / angle_step + 0.5);
- }
- else
- {
- angle_steps = 1;
- }
-
-
- if(current_downsample > 1)
- {
- if(!downsampled_previous ||
- downsampled_previous->get_w() != downsampled_prev_w ||
- downsampled_previous->get_h() != downsampled_prev_h)
- {
- delete downsampled_previous;
- downsampled_previous = new VFrame();
- downsampled_previous->set_use_shm(0);
- downsampled_previous->reallocate(0,
- -1,
- 0,
- 0,
- 0,
- downsampled_prev_w + 1,
- downsampled_prev_h + 1,
- previous_frame_arg->get_color_model(),
- -1);
- }
-
- if(!downsampled_current ||
- downsampled_current->get_w() != downsampled_current_w ||
- downsampled_current->get_h() != downsampled_current_h)
- {
- delete downsampled_current;
- downsampled_current = new VFrame();
- downsampled_current->set_use_shm(0);
- downsampled_current->reallocate(0,
- -1,
- 0,
- 0,
- 0,
- downsampled_current_w + 1,
- downsampled_current_h + 1,
- current_frame_arg->get_color_model(),
- -1);
- }
-
-
- downsample_frame(downsampled_previous,
- previous_frame_arg,
- current_downsample);
- downsample_frame(downsampled_current,
- current_frame_arg,
- current_downsample);
- previous_frame = downsampled_previous;
- current_frame = downsampled_current;
-
- }
- else
- {
- previous_frame = previous_frame_arg;
- current_frame = current_frame_arg;
- }
-
-
-
-// printf("MotionScan::pixel_search %d x_steps=%d y_steps=%d angle_steps=%d total_steps=%d\n",
-// __LINE__,
-// x_steps,
-// y_steps,
-// angle_steps,
-// total_steps);
-
-
-
-// test variance of constant macroblock
- int color_model = current_frame->get_color_model();
- int pixel_size = BC_CModels::calculate_pixelsize(color_model);
- int row_bytes = current_frame->get_bytes_per_line();
- int block_w = block_x2 - block_x1;
- int block_h = block_y2 - block_y1;
-
- unsigned char *current_ptr =
- current_frame->get_rows()[block_y1 / current_downsample] +
- (block_x1 / current_downsample) * pixel_size;
- unsigned char *previous_ptr =
- previous_frame->get_rows()[scan_y1 / current_downsample] +
- (scan_x1 / current_downsample) * pixel_size;
-
-
-
-// test detail in prev & current frame
- double range1 = calculate_range(current_ptr,
- row_bytes,
- block_w / current_downsample,
- block_h / current_downsample,
- color_model);
-
- if(range1 < 1)
- {
-printf("MotionScan::pixel_search %d range fail range1=%f\n", __LINE__, range1);
- failed = 1;
- return;
- }
-
- double range2 = calculate_range(previous_ptr,
- row_bytes,
- block_w / current_downsample,
- block_h / current_downsample,
- color_model);
-
- if(range2 < 1)
- {
-printf("MotionScan::pixel_search %d range fail range2=%f\n", __LINE__, range2);
- failed = 1;
- return;
- }
-
-
-// create rotated images
- if(rotated_current &&
- (total_rotated != angle_steps ||
- rotated_current[0]->get_w() != downsampled_current_w ||
- rotated_current[0]->get_h() != downsampled_current_h))
- {
- for(int i = 0; i < total_rotated; i++)
- {
- delete rotated_current[i];
- }
-
- delete [] rotated_current;
- rotated_current = 0;
- total_rotated = 0;
- }
-
- if(do_rotate)
- {
- total_rotated = angle_steps;
-
-
- if(!rotated_current)
- {
- rotated_current = new VFrame*[total_rotated];
- bzero(rotated_current, sizeof(VFrame*) * total_rotated);
- }
-
-// printf("MotionScan::pixel_search %d total_rotated=%d w=%d h=%d block_w=%d block_h=%d\n",
-// __LINE__,
-// total_rotated,
-// downsampled_current_w,
-// downsampled_current_h,
-// (block_x2 - block_x1) / current_downsample,
-// (block_y2 - block_y1) / current_downsample);
- for(int i = 0; i < angle_steps; i++)
- {
-
-// printf("MotionScan::pixel_search %d w=%d h=%d x=%d y=%d angle=%f\n",
-// __LINE__,
-// downsampled_current_w,
-// downsampled_current_h,
-// (block_x1 + block_x2) / 2 / current_downsample,
-// (block_y1 + block_y2) / 2 / current_downsample,
-// step_to_angle(i, r_result));
-
-// printf("MotionScan::pixel_search %d i=%d rotated_current[i]=%p\n",
-// __LINE__,
-// i,
-// rotated_current[i]);
- if(!rotated_current[i])
- {
- rotated_current[i] = new VFrame();
- rotated_current[i]->set_use_shm(0);
- rotated_current[i]->reallocate(0,
- -1,
- 0,
- 0,
- 0,
- downsampled_current_w + 1,
- downsampled_current_h + 1,
- current_frame_arg->get_color_model(),
- -1);
-//printf("MotionScan::pixel_search %d\n", __LINE__);
- }
-
-
- if(!rotater)
- {
- rotater = new AffineEngine(get_total_clients(),
- get_total_clients());
- }
-
-// get smallest viewport size required for the angle
- double diag = hypot((block_x2 - block_x1) / current_downsample,
- (block_y2 - block_y1) / current_downsample);
- double angle1 = atan2(block_y2 - block_y1, block_x2 - block_x1) +
- TO_RAD(step_to_angle(i, r_result));
- double angle2 = -atan2(block_y2 - block_y1, block_x2 - block_x1) +
- TO_RAD(step_to_angle(i, r_result));
- double max_horiz = MAX(abs(diag * cos(angle1)), abs(diag * cos(angle2)));
- double max_vert = MAX(abs(diag * sin(angle1)), abs(diag * sin(angle2)));
- int center_x = (block_x1 + block_x2) / 2 / current_downsample;
- int center_y = (block_y1 + block_y2) / 2 / current_downsample;
- int x1 = center_x - max_horiz / 2;
- int y1 = center_y - max_vert / 2;
- int x2 = x1 + max_horiz;
- int y2 = y1 + max_vert;
- CLAMP(x1, 0, downsampled_current_w - 1);
- CLAMP(y1, 0, downsampled_current_h - 1);
- CLAMP(x2, 0, downsampled_current_w - 1);
- CLAMP(y2, 0, downsampled_current_h - 1);
-
-//printf("MotionScan::pixel_search %d %f %f %d %d\n",
-//__LINE__, TO_DEG(angle1), TO_DEG(angle2), (int)max_horiz, (int)max_vert);
- rotater->set_in_viewport(x1,
- y1,
- x2 - x1,
- y2 - y1);
- rotater->set_out_viewport(x1,
- y1,
- x2 - x1,
- y2 - y1);
-
-// rotater->set_in_viewport(0,
-// 0,
-// downsampled_current_w,
-// downsampled_current_h);
-// rotater->set_out_viewport(0,
-// 0,
-// downsampled_current_w,
-// downsampled_current_h);
-
- rotater->set_in_pivot(center_x, center_y);
- rotater->set_out_pivot(center_x, center_y);
-
- rotater->rotate(rotated_current[i],
- current_frame,
- step_to_angle(i, r_result));
-
-// rotated_current[i]->draw_rect(block_x1 / current_downsample,
-// block_y1 / current_downsample,
-// block_x2 / current_downsample,
-// block_y2 / current_downsample);
-// char string[BCTEXTLEN];
-// sprintf(string, "/tmp/rotated%d", i);
-// rotated_current[i]->write_png(string);
-//downsampled_previous->write_png("/tmp/previous");
-//printf("MotionScan::pixel_search %d\n", __LINE__);
- }
- }
-
-
-
-
-
-
-// printf("MotionScan::pixel_search %d block x=%d y=%d w=%d h=%d\n",
-// __LINE__,
-// block_x1 / current_downsample,
-// block_y1 / current_downsample,
-// block_w / current_downsample,
-// block_h / current_downsample);
-
-
-
-
-
-
-
-//exit(1);
-// Test only translation of the middle rotated frame
- rotation_pass = 0;
- total_steps = x_steps * y_steps;
- set_package_count(total_steps);
- process_packages();
-
-
-
-
-
-
-// Get least difference
- int64_t min_difference = -1;
-#ifdef STDDEV_TEST
- double stddev_table[get_total_packages()];
-#endif
- for(int i = 0; i < get_total_packages(); i++)
- {
- MotionScanPackage *pkg = (MotionScanPackage*)get_package(i);
-
-#ifdef STDDEV_TEST
- double stddev = sqrt(pkg->difference1) /
- (block_w / current_downsample) /
- (block_h / current_downsample) /
- 3;
-// printf("MotionScan::pixel_search %d current_downsample=%d search_x=%d search_y=%d diff1=%f\n",
-// __LINE__,
-// current_downsample,
-// pkg->search_x,
-// pkg->search_y,
-// sqrt(pkg->difference1) / block_w / current_downsample / block_h / 3 /* / variance */);
-
-// printf("MotionScan::pixel_search %d range1=%f stddev=%f\n",
-// __LINE__,
-// range1,
-// stddev);
-
- stddev_table[i] = stddev;
-#endif // STDDEV_TEST
-
- if(pkg->difference1 < min_difference || i == 0)
- {
- min_difference = pkg->difference1;
- x_result = pkg->search_x * current_downsample * OVERSAMPLE;
- y_result = pkg->search_y * current_downsample * OVERSAMPLE;
-
-// printf("MotionScan::pixel_search %d x_result=%d y_result=%d angle_step=%d diff=%lld\n",
-// __LINE__,
-// block_x1 * OVERSAMPLE - x_result,
-// block_y1 * OVERSAMPLE - y_result,
-// pkg->angle_step,
-// pkg->difference1);
-
- }
- }
-
-
-#ifdef STDDEV_TEST
- qsort(stddev_table, get_total_packages(), sizeof(double), compare);
-
-
-// reject motion vector if not similar enough
-// if(stddev_table[0] > 0.2)
-// {
-// if(debug)
-// {
-// printf("MotionScan::pixel_search %d stddev fail min_stddev=%f\n",
-// __LINE__,
-// stddev_table[0]);
-// }
-// failed = 1;
-// return;
-// }
-
-if(debug)
-{
- printf("MotionScan::pixel_search %d\n", __LINE__);
- for(int i = 0; i < get_total_packages(); i++)
- {
- printf("%f\n", stddev_table[i]);
- }
-}
-
-// reject motion vector if not a sigmoid curve
-// TODO: use linear interpolation
- int steps = 2;
- int step = get_total_packages() / steps;
- double curve[steps];
- for(int i = 0; i < steps; i++)
- {
- int start = get_total_packages() * i / steps;
- int end = get_total_packages() * (i + 1) / steps;
- end = MIN(end, get_total_packages() - 1);
- curve[i] = stddev_table[end] - stddev_table[start];
- }
-
-
-// if(curve[0] < (curve[1] * 1.01) ||
-// curve[2] < (curve[1] * 1.01) ||
-// curve[0] < (curve[2] * 0.75))
-// if(curve[0] < curve[1])
-// {
-// if(debug)
-// {
-// printf("MotionScan::pixel_search %d curve fail %f %f\n",
-// __LINE__,
-// curve[0],
-// curve[1]);
-// }
-// failed = 1;
-// return;
-// }
-
-if(debug)
-{
-printf("MotionScan::pixel_search %d curve=%f %f ranges=%f %f min_stddev=%f\n",
-__LINE__,
-curve[0],
-curve[1],
-range1,
-range2,
-stddev_table[0]);
-}
-#endif // STDDEV_TEST
-
-
-
-
-
- if(do_rotate)
- {
- rotation_pass = 1;;
- total_steps = angle_steps;
- scan_x1 = x_result / OVERSAMPLE;
- scan_y1 = y_result / OVERSAMPLE;
- set_package_count(total_steps);
- process_packages();
-
-
-
- min_difference = -1;
- double prev_r_result = r_result;
- for(int i = 0; i < get_total_packages(); i++)
- {
- MotionScanPackage *pkg = (MotionScanPackage*)get_package(i);
-
-// printf("MotionScan::pixel_search %d search_x=%d search_y=%d angle_step=%d sub_x=%d sub_y=%d diff1=%lld diff2=%lld\n",
-// __LINE__,
-// pkg->search_x,
-// pkg->search_y,
-// pkg->search_angle_step,
-// pkg->sub_x,
-// pkg->sub_y,
-// pkg->difference1,
-// pkg->difference2);
- if(pkg->difference1 < min_difference || i == 0)
- {
- min_difference = pkg->difference1;
- r_result = step_to_angle(i, prev_r_result);
-
- // printf("MotionScan::pixel_search %d x_result=%d y_result=%d angle_step=%d diff=%lld\n",
- // __LINE__,
- // block_x1 * OVERSAMPLE - x_result,
- // block_y1 * OVERSAMPLE - y_result,
- // pkg->angle_step,
- // pkg->difference1);
- }
- }
- }
-
-
-// printf("MotionScan::scan_frame %d current_downsample=%d x_result=%f y_result=%f r_result=%f\n",
-// __LINE__,
-// current_downsample,
-// (float)x_result / OVERSAMPLE,
-// (float)y_result / OVERSAMPLE,
-// r_result);
-
-}
-
-
-// subpixel motion search
-void MotionScan::subpixel_search(int &x_result, int &y_result)
-{
- rotation_pass = 0;
- previous_frame = previous_frame_arg;
- current_frame = current_frame_arg;
-
-//printf("MotionScan::scan_frame %d %d %d\n", __LINE__, x_result, y_result);
-// Scan every subpixel in a SUBPIXEL_RANGE * SUBPIXEL_RANGE square
- total_steps = (SUBPIXEL_RANGE * OVERSAMPLE) * (SUBPIXEL_RANGE * OVERSAMPLE);
-
-// These aren't used in subpixel
- x_steps = OVERSAMPLE * SUBPIXEL_RANGE;
- y_steps = OVERSAMPLE * SUBPIXEL_RANGE;
- angle_steps = 1;
-
- set_package_count(this->total_steps);
- process_packages();
-
-// Get least difference
- int64_t min_difference = -1;
- 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;
-
-// The sub coords are 1 pixel up & left of the block coords
- x_result = pkg->search_x * OVERSAMPLE + pkg->sub_x;
- y_result = pkg->search_y * OVERSAMPLE + pkg->sub_y;
-
-
-// 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",
-//__LINE__, dx_result, dy_result, min_difference);
- }
-
- if(pkg->difference2 < min_difference)
- {
- 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 dx_result=%d dy_result=%d diff=%lld\n",
-//__LINE__, dx_result, dy_result, min_difference);
- }
- }
-}
-
-
-void MotionScan::scan_frame(VFrame *previous_frame,
- VFrame *current_frame,
- int global_range_w,
- int global_range_h,
- int global_block_w,
- int global_block_h,
- int block_x,
- int block_y,
- int frame_type,
- int tracking_type,
- int action_type,
- int horizontal_only,
- int vertical_only,
- int source_position,
- int total_dx,
- int total_dy,
- int global_origin_x,
- int global_origin_y,
- int do_motion,
- int do_rotate,
- double rotation_center,
- double rotation_range)
+void MotionScan::scan_frame(VFrame *previous_frame, VFrame *current_frame,
+ int global_range_w, int global_range_h,
+ int global_block_w, int global_block_h,
+ double block_x, double block_y, int frame_type,
+ int tracking_type, int action_type,
+ 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)
{
this->previous_frame_arg = previous_frame;
this->current_frame_arg = current_frame;
this->current_frame = current_frame_arg;
this->global_origin_x = global_origin_x;
this->global_origin_y = global_origin_y;
- this->action_type = action_type;
- this->do_motion = do_motion;
- this->do_rotate = do_rotate;
- this->rotation_center = rotation_center;
- this->rotation_range = rotation_range;
-
-//printf("MotionScan::scan_frame %d\n", __LINE__);
- dx_result = 0;
- dy_result = 0;
- dr_result = 0;
- failed = 0;
-
subpixel = 0;
-// starting level of detail
-// TODO: base it on a table of resolutions
- current_downsample = STARTING_DOWNSAMPLE;
- angle_step = 0;
+
+ cache.remove_all_objects();
// Single macroblock
int w = current_frame->get_w();
int h = current_frame->get_h();
// Initial search parameters
- scan_w = global_range_w;
- scan_h = global_range_h;
-
- int block_w = global_block_w;
- int block_h = global_block_h;
-
-// printf("MotionScan::scan_frame %d %d %d %d %d %d %d %d %d\n",
-// __LINE__,
-// global_range_w,
-// global_range_h,
-// global_block_w,
-// global_block_h,
-// scan_w,
-// scan_h,
-// block_w,
-// block_h);
+ int scan_w = w * global_range_w / 100;
+ int scan_h = h * global_range_h / 100;
+ int block_w = w * global_block_w / 100;
+ int block_h = h * global_block_h / 100;
// Location of block in previous frame
- block_x1 = (int)(block_x - block_w / 2);
- block_y1 = (int)(block_y - block_h / 2);
- block_x2 = (int)(block_x + block_w / 2);
- block_y2 = (int)(block_y + block_h / 2);
+ 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);
// 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.
- if(frame_type == MotionScan::TRACK_PREVIOUS)
- {
+ if( frame_type == MotionScan::TRACK_PREVIOUS ) {
block_x1 += total_dx / OVERSAMPLE;
block_y1 += total_dy / OVERSAMPLE;
block_x2 += total_dx / OVERSAMPLE;
skip = 0;
- switch(tracking_type)
- {
+ switch( tracking_type ) {
// Don't calculate
- case MotionScan::NO_CALCULATE:
- dx_result = 0;
- dy_result = 0;
- dr_result = rotation_center;
+ case MotionScan::NO_CALCULATE:
+ dx_result = dy_result = 0;
+ skip = 1;
+ break;
+
+ case MotionScan::LOAD:
+ case MotionScan::SAVE:
+ if( load_ok ) {
+ dx_result = load_dx;
+ dy_result = load_dy;
skip = 1;
- break;
-
- case MotionScan::LOAD:
- {
-// Load result from disk
- char string[BCTEXTLEN];
-
- skip = 1;
- if(do_motion)
- {
- sprintf(string, "%s%06d",
- MOTION_FILE,
- source_position);
-//printf("MotionScan::scan_frame %d %s\n", __LINE__, string);
- FILE *input = fopen(string, "r");
- if(input)
- {
- int temp = fscanf(input,
- "%d %d",
- &dx_result,
- &dy_result);
- if( temp != 2 )
- printf("MotionScan::scan_frame %d %s\n", __LINE__, string);
-// HACK
-//dx_result *= 2;
-//dy_result *= 2;
-//printf("MotionScan::scan_frame %d %d %d\n", __LINE__, dx_result, dy_result);
- fclose(input);
- }
- else
- {
- skip = 0;
- }
- }
-
- if(do_rotate)
- {
- sprintf(string,
- "%s%06d",
- ROTATION_FILE,
- source_position);
- FILE *input = fopen(string, "r");
- if(input)
- {
- int temp = fscanf(input, "%f", &dr_result);
- if( temp != 1 )
- printf("MotionScan::scan_frame %d %s\n", __LINE__, string);
-// DEBUG
-//dr_result += 0.25;
- fclose(input);
- }
- else
- {
- skip = 0;
- }
- }
- break;
}
+ break;
// Scan from scratch
- default:
- skip = 0;
- break;
+ default:
+ skip = 0;
+ break;
}
-
-
- if(!skip && test_match)
- {
- if(previous_frame->data_matches(current_frame))
- {
-printf("MotionScan::scan_frame: data matches. skipping.\n");
- dx_result = 0;
- dy_result = 0;
- dr_result = rotation_center;
+ if( !skip && test_match ) {
+ if( previous_frame->data_matches(current_frame) ) {
+ printf("MotionScan::scan_frame: data matches. skipping.\n");
+ dx_result = dy_result = 0;
skip = 1;
}
}
-
-
// Perform scan
- if(!skip)
- {
+ if( !skip ) {
+//printf("MotionScan::scan_frame %d\n", __LINE__);
// Location of block in current frame
- int origin_offset_x = this->global_origin_x;
- int origin_offset_y = this->global_origin_y;
+ 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;
- double r_result = rotation_center;
-
-// 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);
-
- while(!failed)
- {
+
+//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);
+
+ while(1) {
+// Cache needs to be cleared if downsampling is used because the sums of
+// different downsamplings can't be compared.
+// Subpixel never uses the cache.
+// cache.remove_all_objects();
scan_x1 = x_result - scan_w / 2;
scan_y1 = y_result - scan_h / 2;
scan_x2 = x_result + scan_w / 2;
scan_y2 = y_result + scan_h / 2;
- scan_angle1 = r_result - rotation_range;
- scan_angle2 = r_result + rotation_range;
-
-
// Zero out requested values
-// if(horizontal_only)
-// {
-// scan_y1 = block_y1;
-// scan_y2 = block_y1 + 1;
-// }
-// if(vertical_only)
-// {
-// scan_x1 = block_x1;
-// scan_x2 = block_x1 + 1;
-// }
-
-// printf("MotionScan::scan_frame %d block_x1=%d block_y1=%d block_x2=%d block_y2=%d scan_x1=%d scan_y1=%d scan_x2=%d scan_y2=%d\n",
-// __LINE__,
-// block_x1,
-// block_y1,
-// block_x2,
-// block_y2,
-// scan_x1,
-// scan_y1,
-// scan_x2,
-// scan_y2);
-
-
+ if( horizontal_only ) {
+ scan_y1 = block_y1;
+ scan_y2 = block_y1 + 1;
+ }
+ if( vertical_only ) {
+ scan_x1 = block_x1;
+ scan_x2 = block_x1 + 1;
+ }
+//printf("MotionScan::scan_frame 1 %d %d %d %d %d %d %d %d\n",
+// block_x1, block_y1, block_x2, block_y2, scan_x1, scan_y1, scan_x2, scan_y2);
// Clamp the block coords before the scan so we get useful scan coords.
- clamp_scan(w,
- h,
- &block_x1,
- &block_y1,
- &block_x2,
- &block_y2,
- &scan_x1,
- &scan_y1,
- &scan_x2,
- &scan_y2,
- 0);
-
-
-// printf("MotionScan::scan_frame %d block_x1=%d block_y1=%d block_x2=%d block_y2=%d scan_x1=%d scan_y1=%d scan_x2=%d scan_y2=%d 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);
-//if(y_result == 88) exit(0);
-
+ clamp_scan(w, h, &block_x1, &block_y1, &block_x2,
+ &block_y2, &scan_x1, &scan_y1, &scan_x2,
+ &scan_y2, 0);
+// 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);
// Give up if invalid coords.
- if(scan_y2 <= scan_y1 ||
- scan_x2 <= scan_x1 ||
- block_x2 <= block_x1 ||
- block_y2 <= block_y1)
- {
+ if (scan_y2 <= scan_y1 || scan_x2 <= scan_x1 ||
+ block_x2 <= block_x1 || block_y2 <= block_y1 )
break;
- }
// For subpixel, the top row and left column are skipped
- if(subpixel)
- {
+ 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);
+
+ 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;
+ 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;
+
+// The sub coords are 1 pixel up & left of the block coords
+ x_result = pkg->search_x * OVERSAMPLE + pkg->sub_x;
+ y_result = pkg->search_y * OVERSAMPLE + pkg->sub_y;
+// 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",
+//__LINE__, dx_result, dy_result, min_difference);
+ }
+
+ if( pkg->difference2 < min_difference ) {
+ min_difference = pkg->difference2;
- subpixel_search(x_result, y_result);
-// printf("MotionScan::scan_frame %d x_result=%d y_result=%d\n",
-// __LINE__,
-// x_result / OVERSAMPLE,
-// y_result / OVERSAMPLE);
+ 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 dx_result=%d dy_result=%d diff=%lld\n",
+//__LINE__, dx_result, dy_result, min_difference);
+ }
+ }
break;
}
- else
// Single pixel
- {
- pixel_search(x_result, y_result, r_result);
-//printf("MotionScan::scan_frame %d x_result=%d y_result=%d\n", __LINE__, x_result / OVERSAMPLE, y_result / OVERSAMPLE);
-
- if(failed)
- {
- dr_result = 0;
- dx_result = 0;
- dy_result = 0;
+ else {
+ total_pixels =
+ (scan_x2 - scan_x1) * (scan_y2 - scan_y1);
+ this->total_steps =
+ MIN(total_steps, total_pixels);
+
+ if( this->total_steps == total_pixels ) {
+ x_steps = scan_x2 - scan_x1;
+ y_steps = scan_y2 - scan_y1;
+ }
+ else {
+ x_steps = (int)sqrt(this->total_steps);
+ y_steps = (int)sqrt(this->total_steps);
}
- else
- if(current_downsample <= 1)
- {
- // Single pixel accuracy reached. Now do exhaustive subpixel search.
- if(action_type == MotionScan::STABILIZE ||
+
+// Use downsampled images
+// if( scan_x2 - scan_x1 > x_steps * 4 ||
+// scan_y2 - scan_y1 > y_steps * 4 )
+// {
+// printf("MotionScan::scan_frame %d total_pixels=%d total_steps=%d x_steps=%d y_steps=%d x y steps=%d\n",
+// __LINE__,
+// total_pixels,
+// total_steps,
+// x_steps,
+// y_steps,
+// x_steps * y_steps);
+//
+// if( !downsampled_previous ||
+// !downsampled_previous->equivalent(previous_frame_arg) )
+// {
+// delete downsampled_previous;
+// downsampled_previous = new VFrame(*previous_frame_arg);
+// }
+//
+// if( !downsampled_current ||
+// !downsampled_current->equivalent(current_frame_arg) )
+// {
+// delete downsampled_current;
+// downsampled_current = new VFrame(*current_frame_arg);
+// }
+//
+//
+// if( !downsample )
+// downsample = new DownSampleServer(get_total_clients(),
+// get_total_clients());
+// downsample->process_frame(downsampled_previous,
+// previous_frame_arg, 1, 1, 1, 1,
+// (scan_y2 - scan_y1) / y_steps,
+// (scan_x2 - scan_x1) / x_steps,
+// 0, 0);
+// downsample->process_frame(downsampled_current,
+// current_frame_arg, 1, 1, 1, 1,
+// (scan_y2 - scan_y1) / y_steps,
+// (scan_x2 - scan_x1) / x_steps,
+// 0, 0);
+// this->previous_frame = downsampled_previous;
+// this->current_frame = downsampled_current;
+// }
+
+// printf("MotionScan::scan_frame %d this->total_steps=%d\n",
+// __LINE__, this->total_steps);
+
+ set_package_count(this->total_steps);
+ process_packages();
+
+// Get least difference
+ int64_t min_difference = -1;
+ 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 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)
- {
+ action_type == MotionScan::NOTHING ) {
+//printf("MotionScan::scan_frame %d %d %d\n", __LINE__, x_result, y_result);
x_result /= OVERSAMPLE;
y_result /= OVERSAMPLE;
-//printf("MotionScan::scan_frame %d x_result=%d y_result=%d\n", __LINE__, x_result, y_result);
- scan_w = SUBPIXEL_RANGE;
- scan_h = SUBPIXEL_RANGE;
-// Final R result
- dr_result = rotation_center - r_result;
+ scan_w = scan_h = 2;
subpixel = 1;
}
- else
- {
// Fill in results and quit
+ else {
dx_result = block_x1 * OVERSAMPLE - x_result;
dy_result = block_y1 * OVERSAMPLE - y_result;
- dr_result = rotation_center - r_result;
+//printf("MotionScan::scan_frame %d %d %d\n", __LINE__, dx_result, dy_result);
break;
}
}
- else
// Reduce scan area and try again
- {
-// scan_w = (scan_x2 - scan_x1) / 2;
-// scan_h = (scan_y2 - scan_y1) / 2;
-// need slightly more than 2x downsampling factor
-
- if(current_downsample * 3 < scan_w &&
- current_downsample * 3 < scan_h)
- {
- scan_w = current_downsample * 3;
- scan_h = current_downsample * 3;
- }
-
- if(angle_step * 1.5 < rotation_range)
- {
- rotation_range = angle_step * 1.5;
- }
-//printf("MotionScan::scan_frame %d %f %f\n", __LINE__, angle_step, rotation_range);
-
- current_downsample /= 2;
-
-// convert back to pixels
+ else {
+ scan_w = (scan_x2 - scan_x1) / 2;
+ scan_h = (scan_y2 - scan_y1) / 2;
x_result /= OVERSAMPLE;
y_result /= OVERSAMPLE;
-// debug
-//exit(1);
}
-
- }
- }
-
- dx_result *= -1;
- dy_result *= -1;
- dr_result *= -1;
- }
-// printf("MotionScan::scan_frame %d dx=%f dy=%f dr=%f\n",
-// __LINE__,
-// (float)dx_result / OVERSAMPLE,
-// (float)dy_result / OVERSAMPLE,
-// dr_result);
-
-
-
-
-// Write results
- if(!skip && tracking_type == MotionScan::SAVE)
- {
- char string[BCTEXTLEN];
-
-
- if(do_motion)
- {
- sprintf(string,
- "%s%06d",
- MOTION_FILE,
- source_position);
- FILE *output = fopen(string, "w");
- if(output)
- {
- fprintf(output,
- "%d %d\n",
- dx_result,
- dy_result);
- fclose(output);
- }
- else
- {
- printf("MotionScan::scan_frame %d: save motion failed\n", __LINE__);
- }
- }
-
- if(do_rotate)
- {
- sprintf(string,
- "%s%06d",
- ROTATION_FILE,
- source_position);
- FILE *output = fopen(string, "w");
- if(output)
- {
- fprintf(output, "%f\n", dr_result);
- fclose(output);
- }
- else
- {
- printf("MotionScan::scan_frame %d save rotation failed\n", __LINE__);
}
}
+ dx_result = -dx_result;
+ dy_result = -dy_result;
}
+//printf("MotionScan::scan_frame %d\n", __LINE__);
+ if( vertical_only ) dx_result = 0;
+ if( horizontal_only ) dy_result = 0;
- if(vertical_only) dx_result = 0;
- if(horizontal_only) dy_result = 0;
-
-// printf("MotionScan::scan_frame %d dx=%d dy=%d\n",
-// __LINE__,
-// this->dx_result,
-// this->dy_result);
+//printf("MotionScan::scan_frame %d dx=%.2f dy=%.2f\n",
+// __LINE__, (float)this->dx_result / OVERSAMPLE, (float)this->dy_result / OVERSAMPLE);
}
+int64_t MotionScan::get_cache(int x, int y)
+{
+ int64_t result = -1;
+ cache_lock->lock("MotionScan::get_cache");
+ for( int i = 0; i < cache.total; i++ ) {
+ MotionScanCache *ptr = cache.values[i];
+ if( ptr->x == x && ptr->y == y ) {
+ result = ptr->difference;
+ break;
+ }
+ }
+ cache_lock->unlock();
+ return result;
+}
+void MotionScan::put_cache(int x, int y, int64_t difference)
+{
+ MotionScanCache *ptr = new MotionScanCache(x, y, difference);
+ cache_lock->lock("MotionScan::put_cache");
+ cache.append(ptr);
+ cache_lock->unlock();
+}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-#define ABS_DIFF(type, temp_type, multiplier, components) \
-{ \
+#define ABS_DIFF(model, type, temp_type, multiplier, components) case model: { \
temp_type result_temp = 0; \
- for(int i = 0; i < h; i++) \
- { \
+ for( int i = 0; i < h; i++ ) { \
type *prev_row = (type*)prev_ptr; \
type *current_row = (type*)current_ptr; \
- for(int j = 0; j < w; j++) \
- { \
- for(int k = 0; k < 3; k++) \
- { \
+ for( int j = 0; j < w; j++ ) { \
+ for( int k = 0; k < 3; k++ ) { \
temp_type difference; \
difference = *prev_row++ - *current_row++; \
- difference *= difference; \
- result_temp += difference; \
+ if( difference < 0 ) \
+ result_temp -= difference; \
+ else \
+ result_temp += difference; \
} \
- if(components == 4) \
- { \
+ if( components == 4 ) { \
prev_row++; \
current_row++; \
} \
current_ptr += row_bytes; \
} \
result = (int64_t)(result_temp * multiplier); \
-}
+} break
int64_t MotionScan::abs_diff(unsigned char *prev_ptr,
- unsigned char *current_ptr,
- int row_bytes,
- int w,
- int h,
- int color_model)
+ unsigned char *current_ptr, int row_bytes, int w,
+ int h, int color_model)
{
int64_t result = 0;
- switch(color_model)
- {
- case BC_RGB888:
- ABS_DIFF(unsigned char, int64_t, 1, 3)
- break;
- case BC_RGBA8888:
- ABS_DIFF(unsigned char, int64_t, 1, 4)
- break;
- case BC_RGB_FLOAT:
- ABS_DIFF(float, double, 0x10000, 3)
- break;
- case BC_RGBA_FLOAT:
- ABS_DIFF(float, double, 0x10000, 4)
- break;
- case BC_YUV888:
- ABS_DIFF(unsigned char, int64_t, 1, 3)
- break;
- case BC_YUVA8888:
- ABS_DIFF(unsigned char, int64_t, 1, 4)
- break;
+ switch( color_model ) {
+ ABS_DIFF(BC_RGB888, unsigned char, int64_t, 1, 3);
+ ABS_DIFF(BC_RGBA8888, unsigned char, int64_t, 1, 4);
+ ABS_DIFF(BC_RGB_FLOAT, float, double, 0x10000, 3);
+ ABS_DIFF(BC_RGBA_FLOAT, float, double, 0x10000, 4);
+ ABS_DIFF(BC_YUV888, unsigned char, int64_t, 1, 3);
+ ABS_DIFF(BC_YUVA8888, unsigned char, int64_t, 1, 4);
+ ABS_DIFF(BC_YUV161616, uint16_t, int64_t, 1, 3);
+ ABS_DIFF(BC_YUVA16161616, uint16_t, int64_t, 1, 4);
}
return result;
}
-
-
-#define ABS_DIFF_SUB(type, temp_type, multiplier, components) \
-{ \
+#define ABS_DIFF_SUB(model, type, temp_type, multiplier, components) case model: { \
temp_type result_temp = 0; \
temp_type y2_fraction = sub_y * 0x100 / OVERSAMPLE; \
temp_type y1_fraction = 0x100 - y2_fraction; \
temp_type x2_fraction = sub_x * 0x100 / OVERSAMPLE; \
temp_type x1_fraction = 0x100 - x2_fraction; \
- for(int i = 0; i < h_sub; i++) \
- { \
+ for( int i = 0; i < h_sub; i++ ) { \
type *prev_row1 = (type*)prev_ptr; \
type *prev_row2 = (type*)prev_ptr + components; \
type *prev_row3 = (type*)(prev_ptr + row_bytes); \
type *prev_row4 = (type*)(prev_ptr + row_bytes) + components; \
type *current_row = (type*)current_ptr; \
- for(int j = 0; j < w_sub; j++) \
- { \
+ for( int j = 0; j < w_sub; j++ ) { \
/* Scan each component */ \
- for(int k = 0; k < 3; k++) \
- { \
+ for( int k = 0; k < 3; k++ ) { \
temp_type difference; \
temp_type prev_value = \
(*prev_row1++ * x1_fraction * y1_fraction + \
0x100 / 0x100; \
temp_type current_value = *current_row++; \
difference = prev_value - current_value; \
- difference *= difference; \
- result_temp += difference; \
+ if( difference < 0 ) \
+ result_temp -= difference; \
+ else \
+ result_temp += difference; \
} \
\
/* skip alpha */ \
- if(components == 4) \
- { \
+ if( components == 4 ) { \
prev_row1++; \
prev_row2++; \
prev_row3++; \
current_ptr += row_bytes; \
} \
result = (int64_t)(result_temp * multiplier); \
-}
-
-
-
+} break
int64_t MotionScan::abs_diff_sub(unsigned char *prev_ptr,
- unsigned char *current_ptr,
- int row_bytes,
- int w,
- int h,
- int color_model,
- int sub_x,
- int sub_y)
+ unsigned char *current_ptr, int row_bytes,
+ int w, int h, int color_model, int sub_x,
+ int sub_y)
{
int h_sub = h - 1;
int w_sub = w - 1;
int64_t result = 0;
- switch(color_model)
- {
- case BC_RGB888:
- ABS_DIFF_SUB(unsigned char, int64_t, 1, 3)
- break;
- case BC_RGBA8888:
- ABS_DIFF_SUB(unsigned char, int64_t, 1, 4)
- break;
- case BC_RGB_FLOAT:
- ABS_DIFF_SUB(float, double, 0x10000, 3)
- break;
- case BC_RGBA_FLOAT:
- ABS_DIFF_SUB(float, double, 0x10000, 4)
- break;
- case BC_YUV888:
- ABS_DIFF_SUB(unsigned char, int64_t, 1, 3)
- break;
- case BC_YUVA8888:
- ABS_DIFF_SUB(unsigned char, int64_t, 1, 4)
- break;
- }
- return result;
-}
-
-
-#if 0
-#define VARIANCE(type, temp_type, multiplier, components) \
-{ \
- temp_type average[3] = { 0 }; \
- temp_type variance[3] = { 0 }; \
- \
- for(int i = 0; i < h; i++) \
- { \
- type *row = (type*)current_ptr + i * row_bytes; \
- for(int j = 0; j < w; j++) \
- { \
- for(int k = 0; k < 3; k++) \
- { \
- average[k] += row[k]; \
- } \
- row += components; \
- } \
- } \
- for(int k = 0; k < 3; k++) \
- { \
- average[k] /= w * h; \
- } \
- \
- for(int i = 0; i < h; i++) \
- { \
- type *row = (type*)current_ptr + i * row_bytes; \
- for(int j = 0; j < w; j++) \
- { \
- for(int k = 0; k < 3; k++) \
- { \
- variance[k] += SQR(row[k] - average[k]); \
- } \
- row += components; \
- } \
- } \
- result = (double)multiplier * \
- sqrt((variance[0] + variance[1] + variance[2]) / w / h / 3); \
-}
-
-double MotionScan::calculate_variance(unsigned char *current_ptr,
- int row_bytes,
- int w,
- int h,
- int color_model)
-{
- double result = 0;
-
- switch(color_model)
- {
- case BC_RGB888:
- VARIANCE(unsigned char, int, 1, 3)
- break;
- case BC_RGBA8888:
- VARIANCE(unsigned char, int, 1, 4)
- break;
- case BC_RGB_FLOAT:
- VARIANCE(float, double, 255, 3)
- break;
- case BC_RGBA_FLOAT:
- VARIANCE(float, double, 255, 4)
- break;
- case BC_YUV888:
- VARIANCE(unsigned char, int, 1, 3)
- break;
- case BC_YUVA8888:
- VARIANCE(unsigned char, int, 1, 4)
- break;
+ switch( color_model ) {
+ ABS_DIFF_SUB(BC_RGB888, unsigned char, int64_t, 1, 3);
+ ABS_DIFF_SUB(BC_RGBA8888, unsigned char, int64_t, 1, 4);
+ ABS_DIFF_SUB(BC_RGB_FLOAT, float, double, 0x10000, 3);
+ ABS_DIFF_SUB(BC_RGBA_FLOAT, float, double, 0x10000, 4);
+ ABS_DIFF_SUB(BC_YUV888, unsigned char, int64_t, 1, 3);
+ ABS_DIFF_SUB(BC_YUVA8888, unsigned char, int64_t, 1, 4);
+ ABS_DIFF_SUB(BC_YUV161616, uint16_t, int64_t, 1, 3);
+ ABS_DIFF_SUB(BC_YUVA16161616, uint16_t, int64_t, 1, 4);
}
-
-
return result;
}
-#endif // 0
-
-
-
-
-#define RANGE(type, temp_type, multiplier, components) \
-{ \
- temp_type min[3]; \
- temp_type max[3]; \
- min[0] = 0x7fff; \
- min[1] = 0x7fff; \
- min[2] = 0x7fff; \
- max[0] = 0; \
- max[1] = 0; \
- max[2] = 0; \
- \
- for(int i = 0; i < h; i++) \
- { \
- type *row = (type*)current_ptr + i * row_bytes; \
- for(int j = 0; j < w; j++) \
- { \
- for(int k = 0; k < 3; k++) \
- { \
- if(row[k] > max[k]) max[k] = row[k]; \
- if(row[k] < min[k]) min[k] = row[k]; \
- } \
- row += components; \
- } \
- } \
- \
- for(int k = 0; k < 3; k++) \
- { \
- /* printf("MotionScan::calculate_range %d k=%d max=%d min=%d\n", __LINE__, k, max[k], min[k]); */ \
- if(max[k] - min[k] > result) result = max[k] - min[k]; \
- } \
- \
-}
-double MotionScan::calculate_range(unsigned char *current_ptr,
- int row_bytes,
- int w,
- int h,
- int color_model)
+MotionScanCache::MotionScanCache(int x, int y, int64_t difference)
{
- double result = 0;
-
- switch(color_model)
- {
- case BC_RGB888:
- RANGE(unsigned char, int, 1, 3)
- break;
- case BC_RGBA8888:
- RANGE(unsigned char, int, 1, 4)
- break;
- case BC_RGB_FLOAT:
- RANGE(float, float, 255, 3)
- break;
- case BC_RGBA_FLOAT:
- RANGE(float, float, 255, 4)
- break;
- case BC_YUV888:
- RANGE(unsigned char, int, 1, 3)
- break;
- case BC_YUVA8888:
- RANGE(unsigned char, int, 1, 4)
- break;
- }
-
-
- return result;
+ this->x = x;
+ this->y = y;
+ this->difference = difference;
}
-
-//#define CLAMP_BLOCK
-
-// this truncates the scan area but not the macroblock unless the macro is defined
-void MotionScan::clamp_scan(int w,
- int h,
- int *block_x1,
- int *block_y1,
- int *block_x2,
- int *block_y2,
- int *scan_x1,
- int *scan_y1,
- int *scan_x2,
- int *scan_y2,
- int use_absolute)
+void MotionScan::clamp_scan(int w, int h,
+ int *block_x1, int *block_y1, int *block_x2,
+ int *block_y2, int *scan_x1, int *scan_y1,
+ int *scan_x2, int *scan_y2, int use_absolute)
{
-// printf("MotionMain::clamp_scan 1 w=%d h=%d block=%d %d %d %d scan=%d %d %d %d absolute=%d\n",
-// w,
-// h,
-// *block_x1,
-// *block_y1,
-// *block_x2,
-// *block_y2,
-// *scan_x1,
-// *scan_y1,
-// *scan_x2,
-// *scan_y2,
+//printf("MotionMain::clamp_scan 1 w=%d h=%d block=%d %d %d %d scan=%d %d %d %d absolute=%d\n",
+// w, h, *block_x1, *block_y1, *block_x2, *block_y2, *scan_x1, *scan_y1, *scan_x2, *scan_y2,
// use_absolute);
- if(use_absolute)
- {
+ if( use_absolute ) {
// Limit size of scan area
// Used for drawing vectors
// scan is always out of range before block.
- if(*scan_x1 < 0)
- {
-#ifdef CLAMP_BLOCK
- int difference = -*scan_x1;
- *block_x1 += difference;
-#endif
+ if( *scan_x1 < 0 ) {
+// int difference = -*scan_x1;
+// *block_x1 += difference;
*scan_x1 = 0;
}
- if(*scan_y1 < 0)
- {
-#ifdef CLAMP_BLOCK
- int difference = -*scan_y1;
- *block_y1 += difference;
-#endif
+ if( *scan_y1 < 0 ) {
+// int difference = -*scan_y1;
+// *block_y1 += difference;
*scan_y1 = 0;
}
- if(*scan_x2 > w)
- {
+ if( *scan_x2 > w ) {
int difference = *scan_x2 - w;
-#ifdef CLAMP_BLOCK
- *block_x2 -= difference;
-#endif
+// *block_x2 -= difference;
*scan_x2 -= difference;
}
- if(*scan_y2 > h)
- {
+ if( *scan_y2 > h ) {
int difference = *scan_y2 - h;
-#ifdef CLAMP_BLOCK
- *block_y2 -= difference;
-#endif
+// *block_y2 -= difference;
*scan_y2 -= difference;
}
CLAMP(*scan_x2, 0, w);
CLAMP(*scan_y2, 0, h);
}
- else
- {
+ else {
// Limit range of upper left block coordinates
// Used for motion tracking
- if(*scan_x1 < 0)
- {
+ if( *scan_x1 < 0 ) {
int difference = -*scan_x1;
-#ifdef CLAMP_BLOCK
- *block_x1 += difference;
-#endif
+// *block_x1 += difference;
*scan_x2 += difference;
*scan_x1 = 0;
}
- if(*scan_y1 < 0)
- {
+ if( *scan_y1 < 0 ) {
int difference = -*scan_y1;
-#ifdef CLAMP_BLOCK
- *block_y1 += difference;
-#endif
+// *block_y1 += difference;
*scan_y2 += difference;
*scan_y1 = 0;
}
- if(*scan_x2 - *block_x1 + *block_x2 > w)
- {
+ if( *scan_x2 - *block_x1 + *block_x2 > w ) {
int difference = *scan_x2 - *block_x1 + *block_x2 - w;
*scan_x2 -= difference;
-#ifdef CLAMP_BLOCK
- *block_x2 -= difference;
-#endif
+// *block_x2 -= difference;
}
- if(*scan_y2 - *block_y1 + *block_y2 > h)
- {
+ if( *scan_y2 - *block_y1 + *block_y2 > h ) {
int difference = *scan_y2 - *block_y1 + *block_y2 - h;
*scan_y2 -= difference;
-#ifdef CLAMP_BLOCK
- *block_y2 -= difference;
-#endif
+// *block_y2 -= difference;
}
-
-// CLAMP(*scan_x1, 0, w - (*block_x2 - *block_x1));
-// CLAMP(*scan_y1, 0, h - (*block_y2 - *block_y1));
-// CLAMP(*scan_x2, 0, w - (*block_x2 - *block_x1));
-// CLAMP(*scan_y2, 0, h - (*block_y2 - *block_y1));
+// CLAMP(*scan_x1, 0, w - (*block_x2 - *block_x1));
+// CLAMP(*scan_y1, 0, h - (*block_y2 - *block_y1));
+// CLAMP(*scan_x2, 0, w - (*block_x2 - *block_x1));
+// CLAMP(*scan_y2, 0, h - (*block_y2 - *block_y1));
}
// Sanity checks which break the calculation but should never happen if the
CLAMP(*block_y1, 0, h);
CLAMP(*block_y2, 0, h);
-// printf("MotionMain::clamp_scan 2 w=%d h=%d block=%d %d %d %d scan=%d %d %d %d absolute=%d\n",
-// w,
-// h,
-// *block_x1,
-// *block_y1,
-// *block_x2,
-// *block_y2,
-// *scan_x1,
-// *scan_y1,
-// *scan_x2,
-// *scan_y2,
+//printf("MotionMain::clamp_scan 2 w=%d h=%d block=%d %d %d %d scan=%d %d %d %d absolute=%d\n",
+// w, h, *block_x1, *block_y1, *block_x2, *block_y2, *scan_x1, *scan_y1, *scan_x2, *scan_y2,
// use_absolute);
}
-
-
-