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
33Align::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
43Align::~Align()
44{
45  // Free gray-scale image
46  if (imageGray != ImageUtils::IMAGE_TYPE_NOIMAGE)
47    ImageUtils::freeImage(imageGray);
48}
49
50char* Align::getRegProfileString()
51{
52  return reg.profile_string;
53}
54
55int 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
98int Align::addFrameRGB(ImageType imageRGB)
99{
100  ImageUtils::rgb2gray(imageGray, imageRGB, width, height);
101  return addFrame(imageGray);
102}
103
104int 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
193int 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