summaryrefslogtreecommitdiffstats
path: root/jni/feature_stab/src/dbreg/dbreg.h
diff options
context:
space:
mode:
Diffstat (limited to 'jni/feature_stab/src/dbreg/dbreg.h')
-rw-r--r--jni/feature_stab/src/dbreg/dbreg.h581
1 files changed, 581 insertions, 0 deletions
diff --git a/jni/feature_stab/src/dbreg/dbreg.h b/jni/feature_stab/src/dbreg/dbreg.h
new file mode 100644
index 000000000..4eb244481
--- /dev/null
+++ b/jni/feature_stab/src/dbreg/dbreg.h
@@ -0,0 +1,581 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#pragma once
+
+#ifdef _WIN32
+#ifdef DBREG_EXPORTS
+#define DBREG_API __declspec(dllexport)
+#else
+#define DBREG_API __declspec(dllimport)
+#endif
+#else
+#define DBREG_API
+#endif
+
+// @jke - the next few lines are for extracting timing data. TODO: Remove after test
+#define PROFILE 0
+
+#include "dbstabsmooth.h"
+
+#include <db_feature_detection.h>
+#include <db_feature_matching.h>
+#include <db_rob_image_homography.h>
+
+#if PROFILE
+ #include <sys/time.h>
+#endif
+
+/*! \mainpage db_FrameToReferenceRegistration
+
+ \section intro Introduction
+
+ db_FrameToReferenceRegistration provides a simple interface to a set of sophisticated algorithms for stabilizing
+ video sequences. As its name suggests, the class is used to compute parameters that will allow us to warp incoming video
+ frames and register them with respect to a so-called <i>reference</i> frame. The reference frame is simply the first
+ frame of a sequence; the registration process is that of estimating the parameters of a warp that can be applied to
+ subsequent frames to make those frames align with the reference. A video made up of these warped frames will be more
+ stable than the input video.
+
+ For more technical information on the internal structure of the algorithms used within the db_FrameToRegistration class,
+ please follow this <a href="../Sarnoff image registration.docx">link</a>.
+
+ \section usage Usage
+ In addition to the class constructor, there are two main functions of db_FrameToReferenceRegistration that are of
+ interest to the programmer. db_FrameToReferenceRegistration::Init(...) is used to initialize the parameters of the
+ registration algorithm. db_FrameToReferenceRegistration::AddFrame(...) is the method by which each new video frame
+ is introduced to the registration algorithm, and produces the estimated registration warp parameters.
+
+ The following example illustrates how the major methods of the class db_FrameToReferenceRegistration can be used together
+ to calculate the registration parameters for an image sequence. In the example, the calls to the methods of
+ db_FrameToReferenceRegistration match those found in the API, but supporting code should be considered pseudo-code.
+ For a more complete example, please consult the source code for dbregtest.
+
+
+ \code
+ // feature-based image registration class:
+ db_FrameToReferenceRegistration reg;
+
+ // Image data
+ const unsigned char * const * image_storage;
+
+ // The 3x3 frame to reference registration parameters
+ double frame_to_ref_homography[9];
+
+ // a counter to count the number of frames processed.
+ unsigned long frame_counter;
+ // ...
+
+ // main loop - keep going while there are images to process.
+ while (ImagesAreAvailable)
+ {
+ // Call functions to place latest data into image_storage
+ // ...
+
+ // if the registration object is not yet initialized, then do so
+ // The arguments to this function are explained in the accompanying
+ // html API documentation
+ if (!reg.Initialized())
+ {
+ reg.Init(w,h,motion_model_type,25,linear_polish,quarter_resolution,
+ DB_POINT_STANDARDDEV,reference_update_period,
+ do_motion_smoothing,motion_smoothing_gain,
+ DB_DEFAULT_NR_SAMPLES,DB_DEFAULT_CHUNK_SIZE,
+ nr_corners,max_disparity);
+ }
+
+ // Present the new image data to the registration algorithm,
+ // with the result being stored in the frame_to_ref_homography
+ // variable.
+ reg.AddFrame(image_storage,frame_to_ref_homography);
+
+ // frame_to_ref_homography now contains the stabilizing transform
+ // use this to warp the latest image for display, etc.
+
+ // if this is the first frame, we need to tell the registration
+ // class to store the image as its reference. Otherwise, AddFrame
+ // takes care of that.
+ if (frame_counter == 0)
+ {
+ reg.UpdateReference(image_storage);
+ }
+
+ // increment the frame counter
+ frame_counter++;
+ }
+
+ \endcode
+
+ */
+
+/*!
+ * Performs feature-based frame to reference image registration.
+ */
+class DBREG_API db_FrameToReferenceRegistration
+{
+public:
+ db_FrameToReferenceRegistration(void);
+ ~db_FrameToReferenceRegistration();
+
+ /*!
+ * Set parameters and allocate memory. Note: The default values of these parameters have been set to the values used for the android implementation (i.e. the demo APK).
+ * \param width image width
+ * \param height image height
+ * \param homography_type see definitions in \ref LMRobImageHomography
+ * \param max_iterations max number of polishing steps
+ * \param linear_polish whether to perform a linear polishing step after RANSAC
+ * \param quarter_resolution whether to process input images at quarter resolution (for computational efficiency)
+ * \param scale Cauchy scale coefficient (see db_ExpCauchyReprojectionError() )
+ * \param reference_update_period how often to update the alignment reference (in units of number of frames)
+ * \param do_motion_smoothing whether to perform display reference smoothing
+ * \param motion_smoothing_gain weight factor to reflect how fast the display reference must follow the current frame if motion smoothing is enabled
+ * \param nr_samples number of times to compute a hypothesis
+ * \param chunk_size size of cost chunks
+ * \param cd_target_nr_corners target number of corners for corner detector
+ * \param cm_max_disparity maximum disparity search range for corner matcher (in units of ratio of image width)
+ * \param cm_use_smaller_matching_window if set to true, uses a correlation window of 5x5 instead of the default 11x11
+ * \param cd_nr_horz_blocks the number of horizontal blocks for the corner detector to partition the image
+ * \param cd_nr_vert_blocks the number of vertical blocks for the corner detector to partition the image
+ */
+ void Init(int width, int height,
+ int homography_type = DB_HOMOGRAPHY_TYPE_DEFAULT,
+ int max_iterations = DB_DEFAULT_MAX_ITERATIONS,
+ bool linear_polish = false,
+ bool quarter_resolution = true,
+ double scale = DB_POINT_STANDARDDEV,
+ unsigned int reference_update_period = 3,
+ bool do_motion_smoothing = false,
+ double motion_smoothing_gain = 0.75,
+ int nr_samples = DB_DEFAULT_NR_SAMPLES,
+ int chunk_size = DB_DEFAULT_CHUNK_SIZE,
+ int cd_target_nr_corners = 500,
+ double cm_max_disparity = 0.2,
+ bool cm_use_smaller_matching_window = false,
+ int cd_nr_horz_blocks = 5,
+ int cd_nr_vert_blocks = 5);
+
+ /*!
+ * Reset the transformation type that is being use to perform alignment. Use this to change the alignment type at run time.
+ * \param homography_type the type of transformation to use for performing alignment (see definitions in \ref LMRobImageHomography)
+ */
+ void ResetHomographyType(int homography_type) { m_homography_type = homography_type; }
+
+ /*!
+ * Enable/Disable motion smoothing. Use this to turn motion smoothing on/off at run time.
+ * \param enable flag indicating whether to turn the motion smoothing on or off.
+ */
+ void ResetSmoothing(bool enable) { m_do_motion_smoothing = enable; }
+
+ /*!
+ * Align an inspection image to an existing reference image, update the reference image if due and perform motion smoothing if enabled.
+ * \param im new inspection image
+ * \param H computed transformation from reference to inspection coordinate frame. Identity is returned if no reference frame was set.
+ * \param force_reference make this the new reference image
+ */
+ int AddFrame(const unsigned char * const * im, double H[9], bool force_reference=false, bool prewarp=false);
+
+ /*!
+ * Returns true if Init() was run.
+ */
+ bool Initialized() const { return m_initialized; }
+
+ /*!
+ * Returns true if the current frame is being used as the alignment reference.
+ */
+ bool IsCurrentReference() const { return m_current_is_reference; }
+
+ /*!
+ * Returns true if we need to call UpdateReference now.
+ */
+ bool NeedReferenceUpdate();
+
+ /*!
+ * Returns the pointer reference to the alignment reference image data
+ */
+ unsigned char ** GetReferenceImage() { return m_reference_image; }
+
+ /*!
+ * Returns the pointer reference to the double array containing the homogeneous coordinates for the matched reference image corners.
+ */
+ double * GetRefCorners() { return m_corners_ref; }
+ /*!
+ * Returns the pointer reference to the double array containing the homogeneous coordinates for the matched inspection image corners.
+ */
+ double * GetInsCorners() { return m_corners_ins; }
+ /*!
+ * Returns the number of correspondences between the reference and inspection images.
+ */
+ int GetNrMatches() { return m_nr_matches; }
+
+ /*!
+ * Returns the number of corners detected in the current reference image.
+ */
+ int GetNrRefCorners() { return m_nr_corners_ref; }
+
+ /*!
+ * Returns the pointer to an array of indices that were found to be RANSAC inliers from the matched corner lists.
+ */
+ int* GetInliers() { return m_inlier_indices; }
+
+ /*!
+ * Returns the number of inliers from the RANSAC matching step.
+ */
+ int GetNrInliers() { return m_num_inlier_indices; }
+
+ //std::vector<int>& GetInliers();
+ //void Polish(std::vector<int> &inlier_indices);
+
+ /*!
+ * Perform a linear polishing step by re-estimating the alignment transformation using the RANSAC inliers.
+ * \param inlier_indices pointer to an array of indices that were found to be RANSAC inliers from the matched corner lists.
+ * \param num_inlier_indices number of inliers i.e. the length of the array passed as the first argument.
+ */
+ void Polish(int *inlier_indices, int &num_inlier_indices);
+
+ /*!
+ * Reset the motion smoothing parameters to their initial values.
+ */
+ void ResetMotionSmoothingParameters() { m_stab_smoother.Init(); }
+
+ /*!
+ * Update the alignment reference image to the specified image.
+ * \param im pointer to the image data to be used as the new alignment reference.
+ * \param subsample boolean flag to control whether the function should internally subsample the provided image to the size provided in the Init() function.
+ */
+ int UpdateReference(const unsigned char * const * im, bool subsample = true, bool detect_corners = true);
+
+ /*!
+ * Returns the transformation from the display reference to the alignment reference frame
+ */
+ void Get_H_dref_to_ref(double H[9]);
+ /*!
+ * Returns the transformation from the display reference to the inspection reference frame
+ */
+ void Get_H_dref_to_ins(double H[9]);
+ /*!
+ * Set the transformation from the display reference to the inspection reference frame
+ * \param H the transformation to set
+ */
+ void Set_H_dref_to_ins(double H[9]);
+
+ /*!
+ * Reset the display reference to the current frame.
+ */
+ void ResetDisplayReference();
+
+ /*!
+ * Estimate a secondary motion model starting from the specified transformation.
+ * \param H the primary motion model to start from
+ */
+ void EstimateSecondaryModel(double H[9]);
+
+ /*!
+ *
+ */
+ void SelectOutliers();
+
+ char *profile_string;
+
+protected:
+ void Clean();
+ void GenerateQuarterResImage(const unsigned char* const * im);
+
+ int m_im_width;
+ int m_im_height;
+
+ // RANSAC and refinement parameters:
+ int m_homography_type;
+ int m_max_iterations;
+ double m_scale;
+ int m_nr_samples;
+ int m_chunk_size;
+ double m_outlier_t2;
+
+ // Whether to fit a linear model to just the inliers at the end
+ bool m_linear_polish;
+ double m_polish_C[36];
+ double m_polish_D[6];
+
+ // local state
+ bool m_current_is_reference;
+ bool m_initialized;
+
+ // inspection to reference homography:
+ double m_H_ref_to_ins[9];
+ double m_H_dref_to_ref[9];
+
+ // feature extraction and matching:
+ db_CornerDetector_u m_cd;
+ db_Matcher_u m_cm;
+
+ // length of corner arrays:
+ unsigned long m_max_nr_corners;
+
+ // corner locations of reference image features:
+ double * m_x_corners_ref;
+ double * m_y_corners_ref;
+ int m_nr_corners_ref;
+
+ // corner locations of inspection image features:
+ double * m_x_corners_ins;
+ double * m_y_corners_ins;
+ int m_nr_corners_ins;
+
+ // length of match index arrays:
+ unsigned long m_max_nr_matches;
+
+ // match indices:
+ int * m_match_index_ref;
+ int * m_match_index_ins;
+ int m_nr_matches;
+
+ // pointer to internal copy of the reference image:
+ unsigned char ** m_reference_image;
+
+ // pointer to internal copy of last aligned inspection image:
+ unsigned char ** m_aligned_ins_image;
+
+ // pointer to quarter resolution image, if used.
+ unsigned char** m_quarter_res_image;
+
+ // temporary storage for the quarter resolution image processing
+ unsigned char** m_horz_smooth_subsample_image;
+
+ // temporary space for homography computation:
+ double * m_temp_double;
+ int * m_temp_int;
+
+ // homogenous image point arrays:
+ double * m_corners_ref;
+ double * m_corners_ins;
+
+ // Indices of the points within the match lists
+ int * m_inlier_indices;
+ int m_num_inlier_indices;
+
+ //void ComputeInliers(double H[9], std::vector<int> &inlier_indices);
+ void ComputeInliers(double H[9]);
+
+ // cost arrays:
+ void ComputeCostArray();
+ bool m_sq_cost_computed;
+ double * m_sq_cost;
+
+ // cost histogram:
+ void ComputeCostHistogram();
+ int *m_cost_histogram;
+
+ void SetOutlierThreshold();
+
+ // utility function for smoothing the motion parameters.
+ void SmoothMotion(void);
+
+private:
+ double m_K[9];
+ const int m_over_allocation;
+
+ bool m_reference_set;
+
+ // Maximum number of inliers seen until now w.r.t the current reference frame
+ int m_max_inlier_count;
+
+ // Number of cost histogram bins:
+ int m_nr_bins;
+ // All costs above this threshold get put into the last bin:
+ int m_max_cost_pix;
+
+ // whether to quarter the image resolution for processing, or not
+ bool m_quarter_resolution;
+
+ // the period (in number of frames) for reference update.
+ unsigned int m_reference_update_period;
+
+ // the number of frames processed so far.
+ unsigned int m_nr_frames_processed;
+
+ // smoother for motion transformations
+ db_StabilizationSmoother m_stab_smoother;
+
+ // boolean to control whether motion smoothing occurs (or not)
+ bool m_do_motion_smoothing;
+
+ // double to set the gain for motion smoothing
+ double m_motion_smoothing_gain;
+};
+/*!
+ Create look-up tables to undistort images. Only Bougeut (Matlab toolkit)
+ is currently supported. Can be used with db_WarpImageLut_u().
+ \code
+ xd = H*xs;
+ xd = xd/xd(3);
+ \endcode
+ \param lut_x pre-allocated float image
+ \param lut_y pre-allocated float image
+ \param w width
+ \param h height
+ \param H image homography from source to destination
+ */
+inline void db_GenerateHomographyLut(float ** lut_x,float ** lut_y,int w,int h,const double H[9])
+{
+ assert(lut_x && lut_y);
+ double x[3] = {0.0,0.0,1.0};
+ double xb[3];
+
+/*
+ double xl[3];
+
+ // Determine the output coordinate system ROI
+ double Hinv[9];
+ db_InvertAffineTransform(Hinv,H);
+ db_Multiply3x3_3x1(xl, Hinv, x);
+ xl[0] = db_SafeDivision(xl[0],xl[2]);
+ xl[1] = db_SafeDivision(xl[1],xl[2]);
+*/
+
+ for ( int i = 0; i < w; ++i )
+ for ( int j = 0; j < h; ++j )
+ {
+ x[0] = double(i);
+ x[1] = double(j);
+ db_Multiply3x3_3x1(xb, H, x);
+ xb[0] = db_SafeDivision(xb[0],xb[2]);
+ xb[1] = db_SafeDivision(xb[1],xb[2]);
+
+ lut_x[j][i] = float(xb[0]);
+ lut_y[j][i] = float(xb[1]);
+ }
+}
+
+/*!
+ * Perform a look-up table warp for packed RGB ([rgbrgbrgb...]) images.
+ * The LUTs must be float images of the same size as source image.
+ * The source value x_s is determined from destination (x_d,y_d) through lut_x
+ * and y_s is determined from lut_y:
+ \code
+ x_s = lut_x[y_d][x_d];
+ y_s = lut_y[y_d][x_d];
+ \endcode
+
+ * \param src source image (w*3 by h)
+ * \param dst destination image (w*3 by h)
+ * \param w width
+ * \param h height
+ * \param lut_x LUT for x
+ * \param lut_y LUT for y
+ */
+inline void db_WarpImageLutFast_rgb(const unsigned char * const * src, unsigned char ** dst, int w, int h,
+ const float * const * lut_x, const float * const * lut_y)
+{
+ assert(src && dst);
+ int xd=0, yd=0;
+
+ for ( int i = 0; i < w; ++i )
+ for ( int j = 0; j < h; ++j )
+ {
+ xd = static_cast<unsigned int>(lut_x[j][i]);
+ yd = static_cast<unsigned int>(lut_y[j][i]);
+ if ( xd >= w || yd >= h ||
+ xd < 0 || yd < 0)
+ {
+ dst[j][3*i ] = 0;
+ dst[j][3*i+1] = 0;
+ dst[j][3*i+2] = 0;
+ }
+ else
+ {
+ dst[j][3*i ] = src[yd][3*xd ];
+ dst[j][3*i+1] = src[yd][3*xd+1];
+ dst[j][3*i+2] = src[yd][3*xd+2];
+ }
+ }
+}
+
+inline unsigned char db_BilinearInterpolationRGB(double y, double x, const unsigned char * const * v, int offset)
+{
+ int floor_x=(int) x;
+ int floor_y=(int) y;
+
+ int ceil_x=floor_x+1;
+ int ceil_y=floor_y+1;
+
+ unsigned char f00 = v[floor_y][3*floor_x+offset];
+ unsigned char f01 = v[floor_y][3*ceil_x+offset];
+ unsigned char f10 = v[ceil_y][3*floor_x+offset];
+ unsigned char f11 = v[ceil_y][3*ceil_x+offset];
+
+ double xl = x-floor_x;
+ double yl = y-floor_y;
+
+ return (unsigned char)(f00*(1-yl)*(1-xl) + f10*yl*(1-xl) + f01*(1-yl)*xl + f11*yl*xl);
+}
+
+inline void db_WarpImageLutBilinear_rgb(const unsigned char * const * src, unsigned char ** dst, int w, int h,
+ const float * const * lut_x, const float * const * lut_y)
+{
+ assert(src && dst);
+ double xd=0.0, yd=0.0;
+
+ for ( int i = 0; i < w; ++i )
+ for ( int j = 0; j < h; ++j )
+ {
+ xd = static_cast<double>(lut_x[j][i]);
+ yd = static_cast<double>(lut_y[j][i]);
+ if ( xd > w-2 || yd > h-2 ||
+ xd < 0.0 || yd < 0.0)
+ {
+ dst[j][3*i ] = 0;
+ dst[j][3*i+1] = 0;
+ dst[j][3*i+2] = 0;
+ }
+ else
+ {
+ dst[j][3*i ] = db_BilinearInterpolationRGB(yd,xd,src,0);
+ dst[j][3*i+1] = db_BilinearInterpolationRGB(yd,xd,src,1);
+ dst[j][3*i+2] = db_BilinearInterpolationRGB(yd,xd,src,2);
+ }
+ }
+}
+
+inline double SquaredInhomogenousHomographyError(double y[3],double H[9],double x[3]){
+ double x0,x1,x2,mult;
+ double sd;
+
+ x0=H[0]*x[0]+H[1]*x[1]+H[2];
+ x1=H[3]*x[0]+H[4]*x[1]+H[5];
+ x2=H[6]*x[0]+H[7]*x[1]+H[8];
+ mult=1.0/((x2!=0.0)?x2:1.0);
+ sd=(y[0]-x0*mult)*(y[0]-x0*mult)+(y[1]-x1*mult)*(y[1]-x1*mult);
+
+ return(sd);
+}
+
+
+// functions related to profiling
+#if PROFILE
+
+/* return current time in milliseconds */
+static double
+now_ms(void)
+{
+ //struct timespec res;
+ struct timeval res;
+ //clock_gettime(CLOCK_REALTIME, &res);
+ gettimeofday(&res, NULL);
+ return 1000.0*res.tv_sec + (double)res.tv_usec/1e3;
+}
+
+#endif