Home | History | Annotate | Download | only in dbreg
      1 /*
      2  * Copyright (C) 2011 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 // $Id: dbreg.cpp,v 1.31 2011/06/17 14:04:32 mbansal Exp $
     18 #include "dbreg.h"
     19 #include <string.h>
     20 #include <stdio.h>
     21 
     22 
     23 #if PROFILE
     24 #endif
     25 
     26 //#include <iostream>
     27 
     28 db_FrameToReferenceRegistration::db_FrameToReferenceRegistration() :
     29   m_initialized(false),m_nr_matches(0),m_over_allocation(256),m_nr_bins(20),m_max_cost_pix(30), m_quarter_resolution(false)
     30 {
     31   m_reference_image = NULL;
     32   m_aligned_ins_image = NULL;
     33 
     34   m_quarter_res_image = NULL;
     35   m_horz_smooth_subsample_image = NULL;
     36 
     37   m_x_corners_ref = NULL;
     38   m_y_corners_ref = NULL;
     39 
     40   m_x_corners_ins = NULL;
     41   m_y_corners_ins = NULL;
     42 
     43   m_match_index_ref = NULL;
     44   m_match_index_ins = NULL;
     45 
     46   m_inlier_indices = NULL;
     47 
     48   m_num_inlier_indices = 0;
     49 
     50   m_temp_double = NULL;
     51   m_temp_int = NULL;
     52 
     53   m_corners_ref = NULL;
     54   m_corners_ins = NULL;
     55 
     56   m_sq_cost = NULL;
     57   m_cost_histogram = NULL;
     58 
     59   profile_string = NULL;
     60 
     61   db_Identity3x3(m_K);
     62   db_Identity3x3(m_H_ref_to_ins);
     63   db_Identity3x3(m_H_dref_to_ref);
     64 
     65   m_sq_cost_computed = false;
     66   m_reference_set = false;
     67 
     68   m_reference_update_period = 0;
     69   m_nr_frames_processed = 0;
     70 
     71   return;
     72 }
     73 
     74 db_FrameToReferenceRegistration::~db_FrameToReferenceRegistration()
     75 {
     76   Clean();
     77 }
     78 
     79 void db_FrameToReferenceRegistration::Clean()
     80 {
     81   if ( m_reference_image )
     82     db_FreeImage_u(m_reference_image,m_im_height);
     83 
     84   if ( m_aligned_ins_image )
     85     db_FreeImage_u(m_aligned_ins_image,m_im_height);
     86 
     87   if ( m_quarter_res_image )
     88   {
     89     db_FreeImage_u(m_quarter_res_image, m_im_height);
     90   }
     91 
     92   if ( m_horz_smooth_subsample_image )
     93   {
     94     db_FreeImage_u(m_horz_smooth_subsample_image, m_im_height*2);
     95   }
     96 
     97   delete [] m_x_corners_ref;
     98   delete [] m_y_corners_ref;
     99 
    100   delete [] m_x_corners_ins;
    101   delete [] m_y_corners_ins;
    102 
    103   delete [] m_match_index_ref;
    104   delete [] m_match_index_ins;
    105 
    106   delete [] m_temp_double;
    107   delete [] m_temp_int;
    108 
    109   delete [] m_corners_ref;
    110   delete [] m_corners_ins;
    111 
    112   delete [] m_sq_cost;
    113   delete [] m_cost_histogram;
    114 
    115   delete [] m_inlier_indices;
    116 
    117   if(profile_string)
    118     delete [] profile_string;
    119 
    120   m_reference_image = NULL;
    121   m_aligned_ins_image = NULL;
    122 
    123   m_quarter_res_image = NULL;
    124   m_horz_smooth_subsample_image = NULL;
    125 
    126   m_x_corners_ref = NULL;
    127   m_y_corners_ref = NULL;
    128 
    129   m_x_corners_ins = NULL;
    130   m_y_corners_ins = NULL;
    131 
    132   m_match_index_ref = NULL;
    133   m_match_index_ins = NULL;
    134 
    135   m_inlier_indices = NULL;
    136 
    137   m_temp_double = NULL;
    138   m_temp_int = NULL;
    139 
    140   m_corners_ref = NULL;
    141   m_corners_ins = NULL;
    142 
    143   m_sq_cost = NULL;
    144   m_cost_histogram = NULL;
    145 }
    146 
    147 void db_FrameToReferenceRegistration::Init(int width, int height,
    148                        int    homography_type,
    149                        int    max_iterations,
    150                        bool   linear_polish,
    151                        bool   quarter_resolution,
    152                        double scale,
    153                        unsigned int reference_update_period,
    154                        bool   do_motion_smoothing,
    155                        double motion_smoothing_gain,
    156                        int    nr_samples,
    157                        int    chunk_size,
    158                        int    cd_target_nr_corners,
    159                        double cm_max_disparity,
    160                            bool   cm_use_smaller_matching_window,
    161                        int    cd_nr_horz_blocks,
    162                        int    cd_nr_vert_blocks
    163                        )
    164 {
    165   Clean();
    166 
    167   m_reference_update_period = reference_update_period;
    168   m_nr_frames_processed = 0;
    169 
    170   m_do_motion_smoothing = do_motion_smoothing;
    171   m_motion_smoothing_gain = motion_smoothing_gain;
    172 
    173   m_stab_smoother.setSmoothingFactor(m_motion_smoothing_gain);
    174 
    175   m_quarter_resolution = quarter_resolution;
    176 
    177   profile_string = new char[10240];
    178 
    179   if (m_quarter_resolution == true)
    180   {
    181     width = width/2;
    182     height = height/2;
    183 
    184     m_horz_smooth_subsample_image = db_AllocImage_u(width,height*2,m_over_allocation);
    185     m_quarter_res_image = db_AllocImage_u(width,height,m_over_allocation);
    186   }
    187 
    188   m_im_width = width;
    189   m_im_height = height;
    190 
    191   double temp[9];
    192   db_Approx3DCalMat(m_K,temp,m_im_width,m_im_height);
    193 
    194   m_homography_type = homography_type;
    195   m_max_iterations = max_iterations;
    196   m_scale = 2/(m_K[0]+m_K[4]);
    197   m_nr_samples = nr_samples;
    198   m_chunk_size = chunk_size;
    199 
    200   double outlier_t1 = 5.0;
    201 
    202   m_outlier_t2 = outlier_t1*outlier_t1;//*m_scale*m_scale;
    203 
    204   m_current_is_reference = false;
    205 
    206   m_linear_polish = linear_polish;
    207 
    208   m_reference_image = db_AllocImage_u(m_im_width,m_im_height,m_over_allocation);
    209   m_aligned_ins_image = db_AllocImage_u(m_im_width,m_im_height,m_over_allocation);
    210 
    211   // initialize feature detection and matching:
    212   //m_max_nr_corners = m_cd.Init(m_im_width,m_im_height,cd_target_nr_corners,cd_nr_horz_blocks,cd_nr_vert_blocks,0.0,0.0);
    213   m_max_nr_corners = m_cd.Init(m_im_width,m_im_height,cd_target_nr_corners,cd_nr_horz_blocks,cd_nr_vert_blocks,DB_DEFAULT_ABS_CORNER_THRESHOLD/500.0,0.0);
    214 
    215     int use_21 = 0;
    216   m_max_nr_matches = m_cm.Init(m_im_width,m_im_height,cm_max_disparity,m_max_nr_corners,DB_DEFAULT_NO_DISPARITY,cm_use_smaller_matching_window,use_21);
    217 
    218   // allocate space for corner feature locations for reference and inspection images:
    219   m_x_corners_ref = new double [m_max_nr_corners];
    220   m_y_corners_ref = new double [m_max_nr_corners];
    221 
    222   m_x_corners_ins = new double [m_max_nr_corners];
    223   m_y_corners_ins = new double [m_max_nr_corners];
    224 
    225   // allocate space for match indices:
    226   m_match_index_ref = new int [m_max_nr_matches];
    227   m_match_index_ins = new int [m_max_nr_matches];
    228 
    229   m_temp_double = new double [12*DB_DEFAULT_NR_SAMPLES+10*m_max_nr_matches];
    230   m_temp_int = new int [db_maxi(DB_DEFAULT_NR_SAMPLES,m_max_nr_matches)];
    231 
    232   // allocate space for homogenous image points:
    233   m_corners_ref = new double [3*m_max_nr_corners];
    234   m_corners_ins = new double [3*m_max_nr_corners];
    235 
    236   // allocate cost array and histogram:
    237   m_sq_cost = new double [m_max_nr_matches];
    238   m_cost_histogram = new int [m_nr_bins];
    239 
    240   // reserve array:
    241   //m_inlier_indices.reserve(m_max_nr_matches);
    242   m_inlier_indices = new int[m_max_nr_matches];
    243 
    244   m_initialized = true;
    245 
    246   m_max_inlier_count = 0;
    247 }
    248 
    249 
    250 #define MB 0
    251 // Save the reference image, detect features and update the dref-to-ref transformation
    252 int db_FrameToReferenceRegistration::UpdateReference(const unsigned char * const * im, bool subsample, bool detect_corners)
    253 {
    254   double temp[9];
    255   db_Multiply3x3_3x3(temp,m_H_dref_to_ref,m_H_ref_to_ins);
    256   db_Copy9(m_H_dref_to_ref,temp);
    257 
    258   const unsigned char * const * imptr = im;
    259 
    260   if (m_quarter_resolution && subsample)
    261   {
    262     GenerateQuarterResImage(im);
    263     imptr = m_quarter_res_image;
    264   }
    265 
    266   // save the reference image, detect features and quit
    267   db_CopyImage_u(m_reference_image,imptr,m_im_width,m_im_height,m_over_allocation);
    268 
    269   if(detect_corners)
    270   {
    271     #if MB
    272     m_cd.DetectCorners(imptr, m_x_corners_ref,m_y_corners_ref,&m_nr_corners_ref);
    273     int nr = 0;
    274     for(int k=0; k<m_nr_corners_ref; k++)
    275     {
    276         if(m_x_corners_ref[k]>m_im_width/3)
    277         {
    278             m_x_corners_ref[nr] = m_x_corners_ref[k];
    279             m_y_corners_ref[nr] = m_y_corners_ref[k];
    280             nr++;
    281         }
    282 
    283     }
    284     m_nr_corners_ref = nr;
    285     #else
    286     m_cd.DetectCorners(imptr, m_x_corners_ref,m_y_corners_ref,&m_nr_corners_ref);
    287     #endif
    288   }
    289   else
    290   {
    291     m_nr_corners_ref = m_nr_corners_ins;
    292 
    293     for(int k=0; k<m_nr_corners_ins; k++)
    294     {
    295         m_x_corners_ref[k] = m_x_corners_ins[k];
    296         m_y_corners_ref[k] = m_y_corners_ins[k];
    297     }
    298 
    299   }
    300 
    301   db_Identity3x3(m_H_ref_to_ins);
    302 
    303   m_max_inlier_count = 0;   // Reset to 0 as no inliers seen until now
    304   m_sq_cost_computed = false;
    305   m_reference_set = true;
    306   m_current_is_reference = true;
    307   return 1;
    308 }
    309 
    310 void db_FrameToReferenceRegistration::Get_H_dref_to_ref(double H[9])
    311 {
    312   db_Copy9(H,m_H_dref_to_ref);
    313 }
    314 
    315 void db_FrameToReferenceRegistration::Get_H_dref_to_ins(double H[9])
    316 {
    317   db_Multiply3x3_3x3(H,m_H_dref_to_ref,m_H_ref_to_ins);
    318 }
    319 
    320 void db_FrameToReferenceRegistration::Set_H_dref_to_ins(double H[9])
    321 {
    322     double H_ins_to_ref[9];
    323 
    324     db_Identity3x3(H_ins_to_ref);   // Ensure it has proper values
    325     db_InvertAffineTransform(H_ins_to_ref,m_H_ref_to_ins);  // Invert to get ins to ref
    326     db_Multiply3x3_3x3(m_H_dref_to_ref,H,H_ins_to_ref); // Update dref to ref using the input H from dref to ins
    327 }
    328 
    329 
    330 void db_FrameToReferenceRegistration::ResetDisplayReference()
    331 {
    332   db_Identity3x3(m_H_dref_to_ref);
    333 }
    334 
    335 bool db_FrameToReferenceRegistration::NeedReferenceUpdate()
    336 {
    337   // If less than 50% of the starting number of inliers left, then its time to update the reference.
    338   if(m_max_inlier_count>0 && float(m_num_inlier_indices)/float(m_max_inlier_count)<0.5)
    339     return true;
    340   else
    341     return false;
    342 }
    343 
    344 int db_FrameToReferenceRegistration::AddFrame(const unsigned char * const * im, double H[9],bool force_reference,bool prewarp)
    345 {
    346   m_current_is_reference = false;
    347   if(!m_reference_set || force_reference)
    348     {
    349       db_Identity3x3(m_H_ref_to_ins);
    350       db_Copy9(H,m_H_ref_to_ins);
    351 
    352       UpdateReference(im,true,true);
    353       return 0;
    354     }
    355 
    356   const unsigned char * const * imptr = im;
    357 
    358   if (m_quarter_resolution)
    359   {
    360     if (m_quarter_res_image)
    361     {
    362       GenerateQuarterResImage(im);
    363     }
    364 
    365     imptr = (const unsigned char * const* )m_quarter_res_image;
    366   }
    367 
    368   double H_last[9];
    369   db_Copy9(H_last,m_H_ref_to_ins);
    370   db_Identity3x3(m_H_ref_to_ins);
    371 
    372   m_sq_cost_computed = false;
    373 
    374   // detect corners on inspection image and match to reference image features:s
    375 
    376   // @jke - Adding code to time the functions.  TODO: Remove after test
    377 #if PROFILE
    378   double iTimer1, iTimer2;
    379   char str[255];
    380   strcpy(profile_string,"\n");
    381   sprintf(str,"[%dx%d] %p\n",m_im_width,m_im_height,im);
    382   strcat(profile_string, str);
    383 #endif
    384 
    385   // @jke - Adding code to time the functions.  TODO: Remove after test
    386 #if PROFILE
    387   iTimer1 = now_ms();
    388 #endif
    389   m_cd.DetectCorners(imptr, m_x_corners_ins,m_y_corners_ins,&m_nr_corners_ins);
    390   // @jke - Adding code to time the functions.  TODO: Remove after test
    391 # if PROFILE
    392   iTimer2 = now_ms();
    393   double elapsedTimeCorner = iTimer2 - iTimer1;
    394   sprintf(str,"Corner Detection [%d corners] = %g ms\n",m_nr_corners_ins, elapsedTimeCorner);
    395   strcat(profile_string, str);
    396 #endif
    397 
    398   // @jke - Adding code to time the functions.  TODO: Remove after test
    399 #if PROFILE
    400   iTimer1 = now_ms();
    401 #endif
    402     if(prewarp)
    403   m_cm.Match(m_reference_image,imptr,m_x_corners_ref,m_y_corners_ref,m_nr_corners_ref,
    404          m_x_corners_ins,m_y_corners_ins,m_nr_corners_ins,
    405          m_match_index_ref,m_match_index_ins,&m_nr_matches,H,0);
    406     else
    407   m_cm.Match(m_reference_image,imptr,m_x_corners_ref,m_y_corners_ref,m_nr_corners_ref,
    408          m_x_corners_ins,m_y_corners_ins,m_nr_corners_ins,
    409          m_match_index_ref,m_match_index_ins,&m_nr_matches);
    410   // @jke - Adding code to time the functions.  TODO: Remove after test
    411 # if PROFILE
    412   iTimer2 = now_ms();
    413   double elapsedTimeMatch = iTimer2 - iTimer1;
    414   sprintf(str,"Matching [%d] = %g ms\n",m_nr_matches,elapsedTimeMatch);
    415   strcat(profile_string, str);
    416 #endif
    417 
    418 
    419   // copy out matching features:
    420   for ( int i = 0; i < m_nr_matches; ++i )
    421     {
    422       int offset = 3*i;
    423       m_corners_ref[offset  ] = m_x_corners_ref[m_match_index_ref[i]];
    424       m_corners_ref[offset+1] = m_y_corners_ref[m_match_index_ref[i]];
    425       m_corners_ref[offset+2] = 1.0;
    426 
    427       m_corners_ins[offset  ] = m_x_corners_ins[m_match_index_ins[i]];
    428       m_corners_ins[offset+1] = m_y_corners_ins[m_match_index_ins[i]];
    429       m_corners_ins[offset+2] = 1.0;
    430     }
    431 
    432   // @jke - Adding code to time the functions.  TODO: Remove after test
    433 #if PROFILE
    434   iTimer1 = now_ms();
    435 #endif
    436   // perform the alignment:
    437   db_RobImageHomography(m_H_ref_to_ins, m_corners_ref, m_corners_ins, m_nr_matches, m_K, m_K, m_temp_double, m_temp_int,
    438             m_homography_type,NULL,m_max_iterations,m_max_nr_matches,m_scale,
    439             m_nr_samples, m_chunk_size);
    440   // @jke - Adding code to time the functions.  TODO: Remove after test
    441 # if PROFILE
    442   iTimer2 = now_ms();
    443   double elapsedTimeHomography = iTimer2 - iTimer1;
    444   sprintf(str,"Homography = %g ms\n",elapsedTimeHomography);
    445   strcat(profile_string, str);
    446 #endif
    447 
    448 
    449   SetOutlierThreshold();
    450 
    451   // Compute the inliers for the db compute m_H_ref_to_ins
    452   ComputeInliers(m_H_ref_to_ins);
    453 
    454   // Update the max inlier count
    455   m_max_inlier_count = (m_max_inlier_count > m_num_inlier_indices)?m_max_inlier_count:m_num_inlier_indices;
    456 
    457   // Fit a least-squares model to just the inliers and put it in m_H_ref_to_ins
    458   if(m_linear_polish)
    459     Polish(m_inlier_indices, m_num_inlier_indices);
    460 
    461   if (m_quarter_resolution)
    462   {
    463     m_H_ref_to_ins[2] *= 2.0;
    464     m_H_ref_to_ins[5] *= 2.0;
    465   }
    466 
    467 #if PROFILE
    468   sprintf(str,"#Inliers = %d \n",m_num_inlier_indices);
    469   strcat(profile_string, str);
    470 #endif
    471 /*
    472   ///// CHECK IF CURRENT TRANSFORMATION GOOD OR BAD ////
    473   ///// IF BAD, then update reference to the last correctly aligned inspection frame;
    474   if(m_num_inlier_indices<5)//0.9*m_nr_matches || m_nr_matches < 20)
    475   {
    476     db_Copy9(m_H_ref_to_ins,H_last);
    477     UpdateReference(imptr,false);
    478 //  UpdateReference(m_aligned_ins_image,false);
    479   }
    480   else
    481   {
    482   ///// IF GOOD, then update the last correctly aligned inspection frame to be this;
    483   //db_CopyImage_u(m_aligned_ins_image,imptr,m_im_width,m_im_height,m_over_allocation);
    484 */
    485   if(m_do_motion_smoothing)
    486     SmoothMotion();
    487 
    488    // Disable debug printing
    489    // db_PrintDoubleMatrix(m_H_ref_to_ins,3,3);
    490 
    491   db_Copy9(H, m_H_ref_to_ins);
    492 
    493   m_nr_frames_processed++;
    494 {
    495   if ( (m_nr_frames_processed % m_reference_update_period) == 0 )
    496   {
    497     //UpdateReference(imptr,false, false);
    498 
    499     #if MB
    500     UpdateReference(imptr,false, true);
    501     #else
    502     UpdateReference(imptr,false, false);
    503     #endif
    504   }
    505 
    506 
    507   }
    508 
    509 
    510 
    511   return 1;
    512 }
    513 
    514 //void db_FrameToReferenceRegistration::ComputeInliers(double H[9],std::vector<int> &inlier_indices)
    515 void db_FrameToReferenceRegistration::ComputeInliers(double H[9])
    516 {
    517   double totnummatches = m_nr_matches;
    518   int inliercount=0;
    519 
    520   m_num_inlier_indices = 0;
    521 //  inlier_indices.clear();
    522 
    523   for(int c=0; c < totnummatches; c++ )
    524     {
    525       if (m_sq_cost[c] <= m_outlier_t2)
    526     {
    527       m_inlier_indices[inliercount] = c;
    528       inliercount++;
    529     }
    530     }
    531 
    532   m_num_inlier_indices = inliercount;
    533   double frac=inliercount/totnummatches;
    534 }
    535 
    536 //void db_FrameToReferenceRegistration::Polish(std::vector<int> &inlier_indices)
    537 void db_FrameToReferenceRegistration::Polish(int *inlier_indices, int &num_inlier_indices)
    538 {
    539   db_Zero(m_polish_C,36);
    540   db_Zero(m_polish_D,6);
    541   for (int i=0;i<num_inlier_indices;i++)
    542     {
    543       int j = 3*inlier_indices[i];
    544       m_polish_C[0]+=m_corners_ref[j]*m_corners_ref[j];
    545       m_polish_C[1]+=m_corners_ref[j]*m_corners_ref[j+1];
    546       m_polish_C[2]+=m_corners_ref[j];
    547       m_polish_C[7]+=m_corners_ref[j+1]*m_corners_ref[j+1];
    548       m_polish_C[8]+=m_corners_ref[j+1];
    549       m_polish_C[14]+=1;
    550       m_polish_D[0]+=m_corners_ref[j]*m_corners_ins[j];
    551       m_polish_D[1]+=m_corners_ref[j+1]*m_corners_ins[j];
    552       m_polish_D[2]+=m_corners_ins[j];
    553       m_polish_D[3]+=m_corners_ref[j]*m_corners_ins[j+1];
    554       m_polish_D[4]+=m_corners_ref[j+1]*m_corners_ins[j+1];
    555       m_polish_D[5]+=m_corners_ins[j+1];
    556     }
    557 
    558   double a=db_maxd(m_polish_C[0],m_polish_C[7]);
    559   m_polish_C[0]/=a; m_polish_C[1]/=a;   m_polish_C[2]/=a;
    560   m_polish_C[7]/=a; m_polish_C[8]/=a; m_polish_C[14]/=a;
    561 
    562   m_polish_D[0]/=a; m_polish_D[1]/=a;   m_polish_D[2]/=a;
    563   m_polish_D[3]/=a; m_polish_D[4]/=a;   m_polish_D[5]/=a;
    564 
    565 
    566   m_polish_C[6]=m_polish_C[1];
    567   m_polish_C[12]=m_polish_C[2];
    568   m_polish_C[13]=m_polish_C[8];
    569 
    570   m_polish_C[21]=m_polish_C[0]; m_polish_C[22]=m_polish_C[1]; m_polish_C[23]=m_polish_C[2];
    571   m_polish_C[28]=m_polish_C[7]; m_polish_C[29]=m_polish_C[8];
    572   m_polish_C[35]=m_polish_C[14];
    573 
    574 
    575   double d[6];
    576   db_CholeskyDecomp6x6(m_polish_C,d);
    577   db_CholeskyBacksub6x6(m_H_ref_to_ins,m_polish_C,d,m_polish_D);
    578 }
    579 
    580 void db_FrameToReferenceRegistration::EstimateSecondaryModel(double H[9])
    581 {
    582   /*      if ( m_current_is_reference )
    583       {
    584       db_Identity3x3(H);
    585       return;
    586       }
    587   */
    588 
    589   // select the outliers of the current model:
    590   SelectOutliers();
    591 
    592   // perform the alignment:
    593   db_RobImageHomography(m_H_ref_to_ins, m_corners_ref, m_corners_ins, m_nr_matches, m_K, m_K, m_temp_double, m_temp_int,
    594             m_homography_type,NULL,m_max_iterations,m_max_nr_matches,m_scale,
    595             m_nr_samples, m_chunk_size);
    596 
    597   db_Copy9(H,m_H_ref_to_ins);
    598 }
    599 
    600 void db_FrameToReferenceRegistration::ComputeCostArray()
    601 {
    602   if ( m_sq_cost_computed ) return;
    603 
    604   for( int c=0, k=0 ;c < m_nr_matches; c++, k=k+3)
    605     {
    606       m_sq_cost[c] = SquaredInhomogenousHomographyError(m_corners_ins+k,m_H_ref_to_ins,m_corners_ref+k);
    607     }
    608 
    609   m_sq_cost_computed = true;
    610 }
    611 
    612 void db_FrameToReferenceRegistration::SelectOutliers()
    613 {
    614   int nr_outliers=0;
    615 
    616   ComputeCostArray();
    617 
    618   for(int c=0, k=0 ;c<m_nr_matches;c++,k=k+3)
    619     {
    620       if (m_sq_cost[c] > m_outlier_t2)
    621     {
    622       int offset = 3*nr_outliers++;
    623       db_Copy3(m_corners_ref+offset,m_corners_ref+k);
    624       db_Copy3(m_corners_ins+offset,m_corners_ins+k);
    625     }
    626     }
    627 
    628   m_nr_matches = nr_outliers;
    629 }
    630 
    631 void db_FrameToReferenceRegistration::ComputeCostHistogram()
    632 {
    633   ComputeCostArray();
    634 
    635   for ( int b = 0; b < m_nr_bins; ++b )
    636     m_cost_histogram[b] = 0;
    637 
    638   for(int c = 0; c < m_nr_matches; c++)
    639     {
    640       double error = db_SafeSqrt(m_sq_cost[c]);
    641       int bin = (int)(error/m_max_cost_pix*m_nr_bins);
    642       if ( bin < m_nr_bins )
    643     m_cost_histogram[bin]++;
    644       else
    645     m_cost_histogram[m_nr_bins-1]++;
    646     }
    647 
    648 /*
    649   for ( int i = 0; i < m_nr_bins; ++i )
    650     std::cout << m_cost_histogram[i] << " ";
    651   std::cout << std::endl;
    652 */
    653 }
    654 
    655 void db_FrameToReferenceRegistration::SetOutlierThreshold()
    656 {
    657   ComputeCostHistogram();
    658 
    659   int i = 0, last=0;
    660   for (; i < m_nr_bins-1; ++i )
    661     {
    662       if ( last > m_cost_histogram[i] )
    663     break;
    664       last = m_cost_histogram[i];
    665     }
    666 
    667   //std::cout << "I " <<  i << std::endl;
    668 
    669   int max = m_cost_histogram[i];
    670 
    671   for (; i < m_nr_bins-1; ++i )
    672     {
    673       if ( m_cost_histogram[i] < (int)(0.1*max) )
    674     //if ( last < m_cost_histogram[i] )
    675     break;
    676       last = m_cost_histogram[i];
    677     }
    678   //std::cout << "J " <<  i << std::endl;
    679 
    680   m_outlier_t2 = db_sqr(i*m_max_cost_pix/m_nr_bins);
    681 
    682   //std::cout << "m_outlier_t2 " <<  m_outlier_t2 << std::endl;
    683 }
    684 
    685 void db_FrameToReferenceRegistration::SmoothMotion(void)
    686 {
    687   VP_MOTION inmot,outmot;
    688 
    689   double H[9];
    690 
    691   Get_H_dref_to_ins(H);
    692 
    693       MXX(inmot) = H[0];
    694     MXY(inmot) = H[1];
    695     MXZ(inmot) = H[2];
    696     MXW(inmot) = 0.0;
    697 
    698     MYX(inmot) = H[3];
    699     MYY(inmot) = H[4];
    700     MYZ(inmot) = H[5];
    701     MYW(inmot) = 0.0;
    702 
    703     MZX(inmot) = H[6];
    704     MZY(inmot) = H[7];
    705     MZZ(inmot) = H[8];
    706     MZW(inmot) = 0.0;
    707 
    708     MWX(inmot) = 0.0;
    709     MWY(inmot) = 0.0;
    710     MWZ(inmot) = 0.0;
    711     MWW(inmot) = 1.0;
    712 
    713     inmot.type = VP_MOTION_AFFINE;
    714 
    715     int w = m_im_width;
    716     int h = m_im_height;
    717 
    718     if(m_quarter_resolution)
    719     {
    720     w = w*2;
    721     h = h*2;
    722     }
    723 
    724 #if 0
    725     m_stab_smoother.smoothMotionAdaptive(w,h,&inmot,&outmot);
    726 #else
    727     m_stab_smoother.smoothMotion(&inmot,&outmot);
    728 #endif
    729 
    730     H[0] = MXX(outmot);
    731     H[1] = MXY(outmot);
    732     H[2] = MXZ(outmot);
    733 
    734     H[3] = MYX(outmot);
    735     H[4] = MYY(outmot);
    736     H[5] = MYZ(outmot);
    737 
    738     H[6] = MZX(outmot);
    739     H[7] = MZY(outmot);
    740     H[8] = MZZ(outmot);
    741 
    742     Set_H_dref_to_ins(H);
    743 }
    744 
    745 void db_FrameToReferenceRegistration::GenerateQuarterResImage(const unsigned char* const* im)
    746 {
    747   int input_h = m_im_height*2;
    748   int input_w = m_im_width*2;
    749 
    750   for (int j = 0; j < input_h; j++)
    751   {
    752     const unsigned char* in_row_ptr = im[j];
    753     unsigned char* out_row_ptr = m_horz_smooth_subsample_image[j]+1;
    754 
    755     for (int i = 2; i < input_w-2; i += 2)
    756     {
    757       int smooth_val = (
    758             6*in_row_ptr[i] +
    759             ((in_row_ptr[i-1]+in_row_ptr[i+1])<<2) +
    760             in_row_ptr[i-2]+in_row_ptr[i+2]
    761             ) >> 4;
    762       *out_row_ptr++ = (unsigned char) smooth_val;
    763 
    764       if ( (smooth_val < 0) || (smooth_val > 255))
    765       {
    766         return;
    767       }
    768 
    769     }
    770   }
    771 
    772   for (int j = 2; j < input_h-2; j+=2)
    773   {
    774 
    775     unsigned char* in_row_ptr = m_horz_smooth_subsample_image[j];
    776     unsigned char* out_row_ptr = m_quarter_res_image[j/2];
    777 
    778     for (int i = 1; i < m_im_width-1; i++)
    779     {
    780       int smooth_val = (
    781             6*in_row_ptr[i] +
    782             ((in_row_ptr[i-m_im_width]+in_row_ptr[i+m_im_width]) << 2)+
    783             in_row_ptr[i-2*m_im_width]+in_row_ptr[i+2*m_im_width]
    784             ) >> 4;
    785       *out_row_ptr++ = (unsigned char)smooth_val;
    786 
    787       if ( (smooth_val < 0) || (smooth_val > 255))
    788       {
    789         return;
    790       }
    791 
    792     }
    793   }
    794 }
    795