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 // Mosaic.pp
19 // S.O. # :
20 // Author(s): zkira
21 // $Id: Mosaic.cpp,v 1.20 2011/06/24 04:22:14 mbansal Exp $
22 
23 #include <stdio.h>
24 #include <string.h>
25 
26 #include "Mosaic.h"
27 #include "trsMatrix.h"
28 
29 #include "Log.h"
30 #define LOG_TAG "MOSAIC"
31 
Mosaic()32 Mosaic::Mosaic()
33 {
34     initialized = false;
35     imageMosaicYVU = NULL;
36     frames_size = 0;
37     max_frames = 200;
38 }
39 
~Mosaic()40 Mosaic::~Mosaic()
41 {
42     for (int i = 0; i < frames_size; i++)
43     {
44         if (frames[i])
45             delete frames[i];
46     }
47     delete frames;
48     delete rframes;
49 
50     if (aligner != NULL)
51         delete aligner;
52     if (blender != NULL)
53         delete blender;
54 }
55 
initialize(int blendingType,int stripType,int width,int height,int nframes,bool quarter_res,float thresh_still)56 int Mosaic::initialize(int blendingType, int stripType, int width, int height, int nframes, bool quarter_res, float thresh_still)
57 {
58     this->blendingType = blendingType;
59 
60     // TODO: Review this logic if enabling FULL or PAN mode
61     if (blendingType == Blend::BLEND_TYPE_FULL ||
62             blendingType == Blend::BLEND_TYPE_PAN)
63     {
64         stripType = Blend::STRIP_TYPE_THIN;
65     }
66 
67     this->stripType = stripType;
68     this->width = width;
69     this->height = height;
70 
71 
72     mosaicWidth = mosaicHeight = 0;
73     imageMosaicYVU = NULL;
74 
75     frames = new MosaicFrame *[max_frames];
76     rframes = new MosaicFrame *[max_frames];
77 
78     if(nframes>-1)
79     {
80         for(int i=0; i<nframes; i++)
81         {
82             frames[i] = new MosaicFrame(this->width,this->height,false); // Do no allocate memory for YUV data
83         }
84     }
85     else
86     {
87         for(int i=0; i<max_frames; i++)
88         {
89             frames[i] = NULL;
90         }
91 
92 
93     }
94 
95     LOGV("Initialize %d %d", width, height);
96     LOGV("Frame width %d,%d", width, height);
97     LOGV("Max num frames %d", max_frames);
98 
99     aligner = new Align();
100     aligner->initialize(width, height,quarter_res,thresh_still);
101 
102     if (blendingType == Blend::BLEND_TYPE_FULL ||
103             blendingType == Blend::BLEND_TYPE_PAN ||
104             blendingType == Blend::BLEND_TYPE_CYLPAN ||
105             blendingType == Blend::BLEND_TYPE_HORZ) {
106         blender = new Blend();
107         blender->initialize(blendingType, stripType, width, height);
108     } else {
109         blender = NULL;
110         LOGE("Error: Unknown blending type %d",blendingType);
111         return MOSAIC_RET_ERROR;
112     }
113 
114     initialized = true;
115 
116     return MOSAIC_RET_OK;
117 }
118 
addFrameRGB(ImageType imageRGB)119 int Mosaic::addFrameRGB(ImageType imageRGB)
120 {
121     ImageType imageYVU;
122     // Convert to YVU24 which is used by blending
123     imageYVU = ImageUtils::allocateImage(this->width, this->height, ImageUtils::IMAGE_TYPE_NUM_CHANNELS);
124     ImageUtils::rgb2yvu(imageYVU, imageRGB, width, height);
125 
126     return addFrame(imageYVU);
127 }
128 
addFrame(ImageType imageYVU)129 int Mosaic::addFrame(ImageType imageYVU)
130 {
131     if(frames[frames_size]==NULL)
132         frames[frames_size] = new MosaicFrame(this->width,this->height,false);
133 
134     MosaicFrame *frame = frames[frames_size];
135 
136     frame->image = imageYVU;
137 
138     // Add frame to aligner
139     int ret = MOSAIC_RET_ERROR;
140     if (aligner != NULL)
141     {
142         // Note aligner takes in RGB images
143         int align_flag = Align::ALIGN_RET_OK;
144         align_flag = aligner->addFrame(frame->image);
145         aligner->getLastTRS(frame->trs);
146 
147         if (frames_size >= max_frames)
148         {
149             LOGV("WARNING: More frames than preallocated, ignoring."
150                  "Increase maximum number of frames (-f <max_frames>) to avoid this");
151             return MOSAIC_RET_ERROR;
152         }
153 
154         switch (align_flag)
155         {
156             case Align::ALIGN_RET_OK:
157                 frames_size++;
158                 ret = MOSAIC_RET_OK;
159                 break;
160             case Align::ALIGN_RET_FEW_INLIERS:
161                 frames_size++;
162                 ret = MOSAIC_RET_FEW_INLIERS;
163                 break;
164             case Align::ALIGN_RET_LOW_TEXTURE:
165                 ret = MOSAIC_RET_LOW_TEXTURE;
166                 break;
167             case Align::ALIGN_RET_ERROR:
168                 ret = MOSAIC_RET_ERROR;
169                 break;
170             default:
171                 break;
172         }
173     }
174 
175     return ret;
176 }
177 
178 
createMosaic(float & progress,bool & cancelComputation)179 int Mosaic::createMosaic(float &progress, bool &cancelComputation)
180 {
181     if (frames_size <= 0)
182     {
183         // Haven't accepted any frame in aligner. No need to do blending.
184         progress = TIME_PERCENT_ALIGN + TIME_PERCENT_BLEND
185                 + TIME_PERCENT_FINAL;
186         return MOSAIC_RET_OK;
187     }
188 
189     if (blendingType == Blend::BLEND_TYPE_PAN)
190     {
191 
192         balanceRotations();
193 
194     }
195 
196     int ret = Blend::BLEND_RET_ERROR;
197 
198     // Blend the mosaic (alignment has already been done)
199     if (blender != NULL)
200     {
201         ret = blender->runBlend((MosaicFrame **) frames, (MosaicFrame **) rframes,
202                 frames_size, imageMosaicYVU,
203                 mosaicWidth, mosaicHeight, progress, cancelComputation);
204     }
205 
206     switch(ret)
207     {
208         case Blend::BLEND_RET_ERROR:
209         case Blend::BLEND_RET_ERROR_MEMORY:
210             ret = MOSAIC_RET_ERROR;
211             break;
212         case Blend::BLEND_RET_CANCELLED:
213             ret = MOSAIC_RET_CANCELLED;
214             break;
215         case Blend::BLEND_RET_OK:
216             ret = MOSAIC_RET_OK;
217     }
218     return ret;
219 }
220 
getMosaic(int & width,int & height)221 ImageType Mosaic::getMosaic(int &width, int &height)
222 {
223     width = mosaicWidth;
224     height = mosaicHeight;
225 
226     return imageMosaicYVU;
227 }
228 
229 
230 
balanceRotations()231 int Mosaic::balanceRotations()
232 {
233     // Normalize to the mean angle of rotation (Smiley face)
234     double sineAngle = 0.0;
235 
236     for (int i = 0; i < frames_size; i++) sineAngle += frames[i]->trs[0][1];
237     sineAngle /= frames_size;
238     // Calculate the cosineAngle (1 - sineAngle*sineAngle) = cosineAngle*cosineAngle
239     double cosineAngle = sqrt(1.0 - sineAngle*sineAngle);
240     double m[3][3] = {
241         { cosineAngle, -sineAngle, 0 },
242         { sineAngle, cosineAngle, 0},
243         { 0, 0, 1}};
244     double tmp[3][3];
245 
246     for (int i = 0; i < frames_size; i++) {
247         memcpy(tmp, frames[i]->trs, sizeof(tmp));
248         mult33d(frames[i]->trs, m, tmp);
249     }
250 
251     return MOSAIC_RET_OK;
252 }
253