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
32Mosaic::Mosaic()
33{
34    initialized = false;
35    imageMosaicYVU = NULL;
36    frames_size = 0;
37    max_frames = 200;
38}
39
40Mosaic::~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
56int 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
119int 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
129int 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
179int 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
221ImageType Mosaic::getMosaic(int &width, int &height)
222{
223    width = mosaicWidth;
224    height = mosaicHeight;
225
226    return imageMosaicYVU;
227}
228
229
230
231int 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