/* * 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. */ /////////////////////////////////////////////////// // Mosaic.pp // S.O. # : // Author(s): zkira // $Id: Mosaic.cpp,v 1.20 2011/06/24 04:22:14 mbansal Exp $ #include <stdio.h> #include <string.h> #include "Mosaic.h" #include "trsMatrix.h" #include "Log.h" #define LOG_TAG "MOSAIC" Mosaic::Mosaic() { initialized = false; imageMosaicYVU = NULL; frames_size = 0; max_frames = 200; } Mosaic::~Mosaic() { for (int i = 0; i < frames_size; i++) { if (frames[i]) delete frames[i]; } delete frames; delete rframes; for (int j = 0; j < owned_size; j++) delete owned_frames[j]; delete owned_frames; if (aligner != NULL) delete aligner; if (blender != NULL) delete blender; } int Mosaic::initialize(int blendingType, int stripType, int width, int height, int nframes, bool quarter_res, float thresh_still) { this->blendingType = blendingType; // TODO: Review this logic if enabling FULL or PAN mode if (blendingType == Blend::BLEND_TYPE_FULL || blendingType == Blend::BLEND_TYPE_PAN) { stripType = Blend::STRIP_TYPE_THIN; } this->stripType = stripType; this->width = width; this->height = height; mosaicWidth = mosaicHeight = 0; imageMosaicYVU = NULL; frames = new MosaicFrame *[max_frames]; rframes = new MosaicFrame *[max_frames]; if(nframes>-1) { for(int i=0; i<nframes; i++) { frames[i] = new MosaicFrame(this->width,this->height,false); // Do no allocate memory for YUV data } } else { for(int i=0; i<max_frames; i++) { frames[i] = NULL; } } owned_frames = new ImageType[max_frames]; owned_size = 0; LOGV("Initialize %d %d", width, height); LOGV("Frame width %d,%d", width, height); LOGV("Max num frames %d", max_frames); aligner = new Align(); aligner->initialize(width, height,quarter_res,thresh_still); if (blendingType == Blend::BLEND_TYPE_FULL || blendingType == Blend::BLEND_TYPE_PAN || blendingType == Blend::BLEND_TYPE_CYLPAN || blendingType == Blend::BLEND_TYPE_HORZ) { blender = new Blend(); blender->initialize(blendingType, stripType, width, height); } else { blender = NULL; LOGE("Error: Unknown blending type %d",blendingType); return MOSAIC_RET_ERROR; } initialized = true; return MOSAIC_RET_OK; } int Mosaic::addFrameRGB(ImageType imageRGB) { ImageType imageYVU; // Convert to YVU24 which is used by blending imageYVU = ImageUtils::allocateImage(this->width, this->height, ImageUtils::IMAGE_TYPE_NUM_CHANNELS); ImageUtils::rgb2yvu(imageYVU, imageRGB, width, height); int existing_frames_size = frames_size; int ret = addFrame(imageYVU); if (frames_size > existing_frames_size) owned_frames[owned_size++] = imageYVU; else ImageUtils::freeImage(imageYVU); return ret; } int Mosaic::addFrame(ImageType imageYVU) { if(frames[frames_size]==NULL) frames[frames_size] = new MosaicFrame(this->width,this->height,false); MosaicFrame *frame = frames[frames_size]; frame->image = imageYVU; // Add frame to aligner int ret = MOSAIC_RET_ERROR; if (aligner != NULL) { // Note aligner takes in RGB images int align_flag = Align::ALIGN_RET_OK; align_flag = aligner->addFrame(frame->image); aligner->getLastTRS(frame->trs); if (frames_size >= max_frames) { LOGV("WARNING: More frames than preallocated, ignoring." "Increase maximum number of frames (-f <max_frames>) to avoid this"); return MOSAIC_RET_ERROR; } switch (align_flag) { case Align::ALIGN_RET_OK: frames_size++; ret = MOSAIC_RET_OK; break; case Align::ALIGN_RET_FEW_INLIERS: frames_size++; ret = MOSAIC_RET_FEW_INLIERS; break; case Align::ALIGN_RET_LOW_TEXTURE: ret = MOSAIC_RET_LOW_TEXTURE; break; case Align::ALIGN_RET_ERROR: ret = MOSAIC_RET_ERROR; break; default: break; } } return ret; } int Mosaic::createMosaic(float &progress, bool &cancelComputation) { if (frames_size <= 0) { // Haven't accepted any frame in aligner. No need to do blending. progress = TIME_PERCENT_ALIGN + TIME_PERCENT_BLEND + TIME_PERCENT_FINAL; return MOSAIC_RET_OK; } if (blendingType == Blend::BLEND_TYPE_PAN) { balanceRotations(); } int ret = Blend::BLEND_RET_ERROR; // Blend the mosaic (alignment has already been done) if (blender != NULL) { ret = blender->runBlend((MosaicFrame **) frames, (MosaicFrame **) rframes, frames_size, imageMosaicYVU, mosaicWidth, mosaicHeight, progress, cancelComputation); } switch(ret) { case Blend::BLEND_RET_ERROR: case Blend::BLEND_RET_ERROR_MEMORY: ret = MOSAIC_RET_ERROR; break; case Blend::BLEND_RET_CANCELLED: ret = MOSAIC_RET_CANCELLED; break; case Blend::BLEND_RET_OK: ret = MOSAIC_RET_OK; } return ret; } ImageType Mosaic::getMosaic(int &width, int &height) { width = mosaicWidth; height = mosaicHeight; return imageMosaicYVU; } int Mosaic::balanceRotations() { // Normalize to the mean angle of rotation (Smiley face) double sineAngle = 0.0; for (int i = 0; i < frames_size; i++) sineAngle += frames[i]->trs[0][1]; sineAngle /= frames_size; // Calculate the cosineAngle (1 - sineAngle*sineAngle) = cosineAngle*cosineAngle double cosineAngle = sqrt(1.0 - sineAngle*sineAngle); double m[3][3] = { { cosineAngle, -sineAngle, 0 }, { sineAngle, cosineAngle, 0}, { 0, 0, 1}}; double tmp[3][3]; for (int i = 0; i < frames_size; i++) { memcpy(tmp, frames[i]->trs, sizeof(tmp)); mult33d(frames[i]->trs, m, tmp); } return MOSAIC_RET_OK; }