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 ///////////////////////////////////////////////////
18 // AlignFeatures.cpp
19 // S.O. # :
20 // Author(s): zkira, mbansal, bsouthall, narodits
21 // $Id: AlignFeatures.cpp,v 1.20 2011/06/17 13:35:47 mbansal Exp $
22 
23 #include <stdio.h>
24 #include <string.h>
25 
26 #include "trsMatrix.h"
27 #include "MatrixUtils.h"
28 #include "AlignFeatures.h"
29 #include "Log.h"
30 
31 #define LOG_TAG "AlignFeatures"
32 
Align()33 Align::Align()
34 {
35   width = height = 0;
36   frame_number = 0;
37   num_frames_captured = 0;
38   reference_frame_index = 0;
39   db_Identity3x3(Hcurr);
40   db_Identity3x3(Hprev);
41 }
42 
~Align()43 Align::~Align()
44 {
45   // Free gray-scale image
46   if (imageGray != ImageUtils::IMAGE_TYPE_NOIMAGE)
47     ImageUtils::freeImage(imageGray);
48 }
49 
getRegProfileString()50 char* Align::getRegProfileString()
51 {
52   return reg.profile_string;
53 }
54 
initialize(int width,int height,bool _quarter_res,float _thresh_still)55 int Align::initialize(int width, int height, bool _quarter_res, float _thresh_still)
56 {
57   int    nr_corners = DEFAULT_NR_CORNERS;
58   double max_disparity = DEFAULT_MAX_DISPARITY;
59   int    motion_model_type = DEFAULT_MOTION_MODEL;
60   int nrsamples = DB_DEFAULT_NR_SAMPLES;
61   double scale = DB_POINT_STANDARDDEV;
62   int chunk_size = DB_DEFAULT_CHUNK_SIZE;
63   int nrhorz = width/48;  // Empirically determined number of horizontal
64   int nrvert = height/60; // and vertical buckets for harris corner detection.
65   bool linear_polish = false;
66   unsigned int reference_update_period = DEFAULT_REFERENCE_UPDATE_PERIOD;
67 
68   const bool DEFAULT_USE_SMALLER_MATCHING_WINDOW = false;
69   bool   use_smaller_matching_window = DEFAULT_USE_SMALLER_MATCHING_WINDOW;
70 
71   quarter_res = _quarter_res;
72   thresh_still = _thresh_still;
73 
74   frame_number = 0;
75   num_frames_captured = 0;
76   reference_frame_index = 0;
77   db_Identity3x3(Hcurr);
78   db_Identity3x3(Hprev);
79 
80   if (!reg.Initialized())
81   {
82     reg.Init(width, height, motion_model_type, 20, linear_polish, quarter_res,
83             scale, reference_update_period, false, 0, nrsamples, chunk_size,
84             nr_corners, max_disparity, use_smaller_matching_window,
85             nrhorz, nrvert);
86   }
87   this->width = width;
88   this->height = height;
89 
90   imageGray = ImageUtils::allocateImage(width, height, 1);
91 
92   if (reg.Initialized())
93     return ALIGN_RET_OK;
94   else
95     return ALIGN_RET_ERROR;
96 }
97 
addFrameRGB(ImageType imageRGB)98 int Align::addFrameRGB(ImageType imageRGB)
99 {
100   ImageUtils::rgb2gray(imageGray, imageRGB, width, height);
101   return addFrame(imageGray);
102 }
103 
addFrame(ImageType imageGray_)104 int Align::addFrame(ImageType imageGray_)
105 {
106   int ret_code = ALIGN_RET_OK;
107 
108  // Obtain a vector of pointers to rows in image and pass in to dbreg
109   ImageType *m_rows = ImageUtils::imageTypeToRowPointers(imageGray_, width, height);
110 
111   if (frame_number == 0)
112   {
113       reg.AddFrame(m_rows, Hcurr, true);    // Force this to be a reference frame
114       int num_corner_ref = reg.GetNrRefCorners();
115 
116       if (num_corner_ref < MIN_NR_REF_CORNERS)
117       {
118           return ALIGN_RET_LOW_TEXTURE;
119       }
120   }
121   else
122   {
123       reg.AddFrame(m_rows, Hcurr, false);
124   }
125 
126   // Average translation per frame =
127   //    [Translation from Frame0 to Frame(n-1)] / [(n-1)]
128   average_tx_per_frame = (num_frames_captured < 2) ? 0.0 :
129         Hprev[2] / (num_frames_captured - 1);
130 
131   // Increment the captured frame counter if we already have a reference frame
132   num_frames_captured++;
133 
134   if (frame_number != 0)
135   {
136     int num_inliers = reg.GetNrInliers();
137 
138     if(num_inliers < MIN_NR_INLIERS)
139     {
140         ret_code = ALIGN_RET_FEW_INLIERS;
141 
142         Hcurr[0] = 1.0;
143         Hcurr[1] = 0.0;
144         // Set this as the average per frame translation taking into acccount
145         // the separation of the current frame from the reference frame...
146         Hcurr[2] = -average_tx_per_frame *
147                 (num_frames_captured - reference_frame_index);
148         Hcurr[3] = 0.0;
149         Hcurr[4] = 1.0;
150         Hcurr[5] = 0.0;
151         Hcurr[6] = 0.0;
152         Hcurr[7] = 0.0;
153         Hcurr[8] = 1.0;
154     }
155 
156     if(fabs(Hcurr[2])<thresh_still && fabs(Hcurr[5])<thresh_still)  // Still camera
157     {
158         return ALIGN_RET_ERROR;
159     }
160 
161     // compute the homography:
162     double Hinv33[3][3];
163     double Hprev33[3][3];
164     double Hcurr33[3][3];
165 
166     // Invert and multiple with previous transformation
167     Matrix33::convert9to33(Hcurr33, Hcurr);
168     Matrix33::convert9to33(Hprev33, Hprev);
169     normProjMat33d(Hcurr33);
170 
171     inv33d(Hcurr33, Hinv33);
172 
173     mult33d(Hcurr33, Hprev33, Hinv33);
174     normProjMat33d(Hcurr33);
175     Matrix9::convert33to9(Hprev, Hcurr33);
176     // Since we have already factored the current transformation
177     // into Hprev, we can reset the Hcurr to identity
178     db_Identity3x3(Hcurr);
179 
180     // Update the reference frame to be the current frame
181     reg.UpdateReference(m_rows,quarter_res,false);
182 
183     // Update the reference frame index
184     reference_frame_index = num_frames_captured;
185   }
186 
187   frame_number++;
188 
189   return ret_code;
190 }
191 
192 // Get current transformation
getLastTRS(double trs[3][3])193 int Align::getLastTRS(double trs[3][3])
194 {
195   if (frame_number < 1)
196   {
197     trs[0][0] = 1.0;
198     trs[0][1] = 0.0;
199     trs[0][2] = 0.0;
200     trs[1][0] = 0.0;
201     trs[1][1] = 1.0;
202     trs[1][2] = 0.0;
203     trs[2][0] = 0.0;
204     trs[2][1] = 0.0;
205     trs[2][2] = 1.0;
206     return ALIGN_RET_ERROR;
207   }
208 
209   // Note that the logic here handles the case, where a frame is not used for
210   // mosaicing but is captured and used in the preview-rendering.
211   // For these frames, we don't set Hcurr to identity in AddFrame() and the
212   // logic here appends their transformation to Hprev to render them with the
213   // correct transformation. For the frames we do use for mosaicing, we already
214   // append their Hcurr to Hprev in AddFrame() and then set Hcurr to identity.
215 
216   double Hinv33[3][3];
217   double Hprev33[3][3];
218   double Hcurr33[3][3];
219 
220   Matrix33::convert9to33(Hcurr33, Hcurr);
221   normProjMat33d(Hcurr33);
222   inv33d(Hcurr33, Hinv33);
223 
224   Matrix33::convert9to33(Hprev33, Hprev);
225 
226   mult33d(trs, Hprev33, Hinv33);
227   normProjMat33d(trs);
228 
229   return ALIGN_RET_OK;
230 }
231 
232