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