| /* |
| * 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. |
| */ |
| |
| /////////////////////////////////////////////////// |
| // AlignFeatures.cpp |
| // S.O. # : |
| // Author(s): zkira, mbansal, bsouthall, narodits |
| // $Id: AlignFeatures.cpp,v 1.20 2011/06/17 13:35:47 mbansal Exp $ |
| |
| #include <stdio.h> |
| #include <string.h> |
| |
| #include "trsMatrix.h" |
| #include "MatrixUtils.h" |
| #include "AlignFeatures.h" |
| #include "Log.h" |
| |
| #define LOG_TAG "AlignFeatures" |
| |
| Align::Align() |
| { |
| width = height = 0; |
| frame_number = 0; |
| num_frames_captured = 0; |
| reference_frame_index = 0; |
| db_Identity3x3(Hcurr); |
| db_Identity3x3(Hprev); |
| } |
| |
| Align::~Align() |
| { |
| // Free gray-scale image |
| if (imageGray != ImageUtils::IMAGE_TYPE_NOIMAGE) |
| ImageUtils::freeImage(imageGray); |
| } |
| |
| char* Align::getRegProfileString() |
| { |
| return reg.profile_string; |
| } |
| |
| int Align::initialize(int width, int height, bool _quarter_res, float _thresh_still) |
| { |
| int nr_corners = DEFAULT_NR_CORNERS; |
| double max_disparity = DEFAULT_MAX_DISPARITY; |
| int motion_model_type = DEFAULT_MOTION_MODEL; |
| int nrsamples = DB_DEFAULT_NR_SAMPLES; |
| double scale = DB_POINT_STANDARDDEV; |
| int chunk_size = DB_DEFAULT_CHUNK_SIZE; |
| int nrhorz = width/48; // Empirically determined number of horizontal |
| int nrvert = height/60; // and vertical buckets for harris corner detection. |
| bool linear_polish = false; |
| unsigned int reference_update_period = DEFAULT_REFERENCE_UPDATE_PERIOD; |
| |
| const bool DEFAULT_USE_SMALLER_MATCHING_WINDOW = false; |
| bool use_smaller_matching_window = DEFAULT_USE_SMALLER_MATCHING_WINDOW; |
| |
| quarter_res = _quarter_res; |
| thresh_still = _thresh_still; |
| |
| frame_number = 0; |
| num_frames_captured = 0; |
| reference_frame_index = 0; |
| db_Identity3x3(Hcurr); |
| db_Identity3x3(Hprev); |
| |
| if (!reg.Initialized()) |
| { |
| reg.Init(width, height, motion_model_type, 20, linear_polish, quarter_res, |
| scale, reference_update_period, false, 0, nrsamples, chunk_size, |
| nr_corners, max_disparity, use_smaller_matching_window, |
| nrhorz, nrvert); |
| } |
| this->width = width; |
| this->height = height; |
| |
| imageGray = ImageUtils::allocateImage(width, height, 1); |
| |
| if (reg.Initialized()) |
| return ALIGN_RET_OK; |
| else |
| return ALIGN_RET_ERROR; |
| } |
| |
| int Align::addFrameRGB(ImageType imageRGB) |
| { |
| ImageUtils::rgb2gray(imageGray, imageRGB, width, height); |
| return addFrame(imageGray); |
| } |
| |
| int Align::addFrame(ImageType imageGray_) |
| { |
| int ret_code = ALIGN_RET_OK; |
| |
| // Obtain a vector of pointers to rows in image and pass in to dbreg |
| ImageType *m_rows = ImageUtils::imageTypeToRowPointers(imageGray_, width, height); |
| |
| if (frame_number == 0) |
| { |
| reg.AddFrame(m_rows, Hcurr, true); // Force this to be a reference frame |
| int num_corner_ref = reg.GetNrRefCorners(); |
| |
| if (num_corner_ref < MIN_NR_REF_CORNERS) |
| { |
| return ALIGN_RET_LOW_TEXTURE; |
| } |
| } |
| else |
| { |
| reg.AddFrame(m_rows, Hcurr, false); |
| } |
| |
| // Average translation per frame = |
| // [Translation from Frame0 to Frame(n-1)] / [(n-1)] |
| average_tx_per_frame = (num_frames_captured < 2) ? 0.0 : |
| Hprev[2] / (num_frames_captured - 1); |
| |
| // Increment the captured frame counter if we already have a reference frame |
| num_frames_captured++; |
| |
| if (frame_number != 0) |
| { |
| int num_inliers = reg.GetNrInliers(); |
| |
| if(num_inliers < MIN_NR_INLIERS) |
| { |
| ret_code = ALIGN_RET_FEW_INLIERS; |
| |
| Hcurr[0] = 1.0; |
| Hcurr[1] = 0.0; |
| // Set this as the average per frame translation taking into acccount |
| // the separation of the current frame from the reference frame... |
| Hcurr[2] = -average_tx_per_frame * |
| (num_frames_captured - reference_frame_index); |
| Hcurr[3] = 0.0; |
| Hcurr[4] = 1.0; |
| Hcurr[5] = 0.0; |
| Hcurr[6] = 0.0; |
| Hcurr[7] = 0.0; |
| Hcurr[8] = 1.0; |
| } |
| |
| if(fabs(Hcurr[2])<thresh_still && fabs(Hcurr[5])<thresh_still) // Still camera |
| { |
| return ALIGN_RET_ERROR; |
| } |
| |
| // compute the homography: |
| double Hinv33[3][3]; |
| double Hprev33[3][3]; |
| double Hcurr33[3][3]; |
| |
| // Invert and multiple with previous transformation |
| Matrix33::convert9to33(Hcurr33, Hcurr); |
| Matrix33::convert9to33(Hprev33, Hprev); |
| normProjMat33d(Hcurr33); |
| |
| inv33d(Hcurr33, Hinv33); |
| |
| mult33d(Hcurr33, Hprev33, Hinv33); |
| normProjMat33d(Hcurr33); |
| Matrix9::convert33to9(Hprev, Hcurr33); |
| // Since we have already factored the current transformation |
| // into Hprev, we can reset the Hcurr to identity |
| db_Identity3x3(Hcurr); |
| |
| // Update the reference frame to be the current frame |
| reg.UpdateReference(m_rows,quarter_res,false); |
| |
| // Update the reference frame index |
| reference_frame_index = num_frames_captured; |
| } |
| |
| frame_number++; |
| |
| return ret_code; |
| } |
| |
| // Get current transformation |
| int Align::getLastTRS(double trs[3][3]) |
| { |
| if (frame_number < 1) |
| { |
| trs[0][0] = 1.0; |
| trs[0][1] = 0.0; |
| trs[0][2] = 0.0; |
| trs[1][0] = 0.0; |
| trs[1][1] = 1.0; |
| trs[1][2] = 0.0; |
| trs[2][0] = 0.0; |
| trs[2][1] = 0.0; |
| trs[2][2] = 1.0; |
| return ALIGN_RET_ERROR; |
| } |
| |
| // Note that the logic here handles the case, where a frame is not used for |
| // mosaicing but is captured and used in the preview-rendering. |
| // For these frames, we don't set Hcurr to identity in AddFrame() and the |
| // logic here appends their transformation to Hprev to render them with the |
| // correct transformation. For the frames we do use for mosaicing, we already |
| // append their Hcurr to Hprev in AddFrame() and then set Hcurr to identity. |
| |
| double Hinv33[3][3]; |
| double Hprev33[3][3]; |
| double Hcurr33[3][3]; |
| |
| Matrix33::convert9to33(Hcurr33, Hcurr); |
| normProjMat33d(Hcurr33); |
| inv33d(Hcurr33, Hinv33); |
| |
| Matrix33::convert9to33(Hprev33, Hprev); |
| |
| mult33d(trs, Hprev33, Hinv33); |
| normProjMat33d(trs); |
| |
| return ALIGN_RET_OK; |
| } |
| |