1e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen/*
2e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen * Copyright (C) 2011 The Android Open Source Project
3e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen *
4e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen * Licensed under the Apache License, Version 2.0 (the "License");
5e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen * you may not use this file except in compliance with the License.
6e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen * You may obtain a copy of the License at
7e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen *
8e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen *      http://www.apache.org/licenses/LICENSE-2.0
9e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen *
10e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen * Unless required by applicable law or agreed to in writing, software
11e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen * distributed under the License is distributed on an "AS IS" BASIS,
12e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen * See the License for the specific language governing permissions and
14e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen * limitations under the License.
15e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen */
16e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
17e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen///////////////////////////////////////////////////
18e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen// Blend.cpp
19e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen// $Id: Blend.cpp,v 1.22 2011/06/24 04:22:14 mbansal Exp $
20e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
21e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen#include <string.h>
22e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
23e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen#include "Interp.h"
24e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen#include "Blend.h"
25e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
26e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen#include "Geometry.h"
27e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen#include "trsMatrix.h"
28e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
29274ca49c63557a8c3ee12c8da5f75e28b4875a5dWei-Ta Chen#include "Log.h"
30274ca49c63557a8c3ee12c8da5f75e28b4875a5dWei-Ta Chen#define LOG_TAG "BLEND"
31274ca49c63557a8c3ee12c8da5f75e28b4875a5dWei-Ta Chen
32e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta ChenBlend::Blend()
33e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen{
34e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen  m_wb.blendingType = BLEND_TYPE_NONE;
35e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen}
36e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
37e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta ChenBlend::~Blend()
38e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen{
39e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    if (m_pFrameVPyr) free(m_pFrameVPyr);
40e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    if (m_pFrameUPyr) free(m_pFrameUPyr);
41e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    if (m_pFrameYPyr) free(m_pFrameYPyr);
42e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen}
43e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
44b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansalint Blend::initialize(int blendingType, int stripType, int frame_width, int frame_height)
45e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen{
46e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    this->width = frame_width;
47e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    this->height = frame_height;
48e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    this->m_wb.blendingType = blendingType;
49b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal    this->m_wb.stripType = stripType;
50e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
51e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    m_wb.blendRange = m_wb.blendRangeUV = BLEND_RANGE_DEFAULT;
52e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    m_wb.nlevs = m_wb.blendRange;
53e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    m_wb.nlevsC = m_wb.blendRangeUV;
54e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
55e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    if (m_wb.nlevs <= 0) m_wb.nlevs = 1; // Need levels for YUV processing
56e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    if (m_wb.nlevsC > m_wb.nlevs) m_wb.nlevsC = m_wb.nlevs;
57e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
58e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    m_wb.roundoffOverlap = 1.5;
59e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
60e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    m_pFrameYPyr = NULL;
61e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    m_pFrameUPyr = NULL;
62e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    m_pFrameVPyr = NULL;
63e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
64e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    m_pFrameYPyr = PyramidShort::allocatePyramidPacked(m_wb.nlevs, (unsigned short) width, (unsigned short) height, BORDER);
65e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    m_pFrameUPyr = PyramidShort::allocatePyramidPacked(m_wb.nlevsC, (unsigned short) (width), (unsigned short) (height), BORDER);
66e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    m_pFrameVPyr = PyramidShort::allocatePyramidPacked(m_wb.nlevsC, (unsigned short) (width), (unsigned short) (height), BORDER);
67e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
68e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    if (!m_pFrameYPyr || !m_pFrameUPyr || !m_pFrameVPyr)
69e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    {
70274ca49c63557a8c3ee12c8da5f75e28b4875a5dWei-Ta Chen        LOGE("Error: Could not allocate pyramids for blending");
71e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        return BLEND_RET_ERROR_MEMORY;
72e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    }
73e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
74e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    return BLEND_RET_OK;
75e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen}
76e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
776c5b20113ba9f91352f32e5a53df66aec0ec761ambansalinline double max(double a, double b) { return a > b ? a : b; }
786c5b20113ba9f91352f32e5a53df66aec0ec761ambansalinline double min(double a, double b) { return a < b ? a : b; }
796c5b20113ba9f91352f32e5a53df66aec0ec761ambansal
801e762b1f935c9d4a06af6dd56121590ca81d48b1mbansalvoid Blend::AlignToMiddleFrame(MosaicFrame **frames, int frames_size)
811e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal{
821e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    // Unwarp this frame and Warp the others to match
831e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    MosaicFrame *mb = NULL;
841e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    MosaicFrame *ref = frames[int(frames_size/2)];    // Middle frame
851e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal
861e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    double invtrs[3][3];
871e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    inv33d(ref->trs, invtrs);
881e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal
891e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    for(int mfit = 0; mfit < frames_size; mfit++)
901e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    {
911e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal        mb = frames[mfit];
921e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal        double temp[3][3];
931e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal        mult33d(temp, invtrs, mb->trs);
941e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal        memcpy(mb->trs, temp, sizeof(temp));
951e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal        normProjMat33d(mb->trs);
961e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    }
971e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal}
981e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal
99b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansalint Blend::runBlend(MosaicFrame **oframes, MosaicFrame **rframes,
100b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal        int frames_size,
10150b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal        ImageType &imageMosaicYVU, int &mosaicWidth, int &mosaicHeight,
102e1178a73fd5756771d25d0b8375452450f509e99mbansal        float &progress, bool &cancelComputation)
103e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen{
104e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    int ret;
105e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    int numCenters;
106e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
107b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal    MosaicFrame **frames;
108b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal
109b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal    // For THIN strip mode, accept all frames for blending
110b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal    if (m_wb.stripType == STRIP_TYPE_THIN)
111b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal    {
112b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal        frames = oframes;
113b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal    }
114b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal    else // For WIDE strip mode, first select the relevant frames to blend.
115b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal    {
116b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal        SelectRelevantFrames(oframes, frames_size, rframes, frames_size);
117b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal        frames = rframes;
118b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal    }
119b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal
120fa45108679c51623e716acbc3301b1e4535c3267Wei-Ta Chen    ComputeBlendParameters(frames, frames_size, true);
121e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    numCenters = frames_size;
122e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
123e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    if (numCenters == 0)
124e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    {
125274ca49c63557a8c3ee12c8da5f75e28b4875a5dWei-Ta Chen        LOGE("Error: No frames to blend");
126e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        return BLEND_RET_ERROR;
127e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    }
128e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
129e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    if (!(m_AllSites = m_Triangulator.allocMemory(numCenters)))
130e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    {
131e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        return BLEND_RET_ERROR_MEMORY;
132e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    }
133e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
1346c5b20113ba9f91352f32e5a53df66aec0ec761ambansal    // Bounding rectangle (real numbers) of the final mosaic computed by projecting
1356c5b20113ba9f91352f32e5a53df66aec0ec761ambansal    // each input frame into the mosaic coordinate system.
136e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    BlendRect global_rect;
137e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
138e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    global_rect.lft = global_rect.bot = 2e30; // min values
139e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    global_rect.rgt = global_rect.top = -2e30; // max values
140e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    MosaicFrame *mb = NULL;
141e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    double halfwidth = width / 2.0;
142e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    double halfheight = height / 2.0;
143e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
144e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    double z, x0, y0, x1, y1, x2, y2, x3, y3;
145e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
146a369cd3153170975a5e5bd6fa5544dcd6f22ee85mbansal    // Corners of the left-most and right-most frames respectively in the
147a369cd3153170975a5e5bd6fa5544dcd6f22ee85mbansal    // mosaic coordinate system.
148a369cd3153170975a5e5bd6fa5544dcd6f22ee85mbansal    double xLeftCorners[2] = {2e30, 2e30};
149a369cd3153170975a5e5bd6fa5544dcd6f22ee85mbansal    double xRightCorners[2] = {-2e30, -2e30};
1506c5b20113ba9f91352f32e5a53df66aec0ec761ambansal
151ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal    // Corners of the top-most and bottom-most frames respectively in the
152ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal    // mosaic coordinate system.
153ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal    double yTopCorners[2] = {2e30, 2e30};
154ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal    double yBottomCorners[2] = {-2e30, -2e30};
155ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal
156ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal
157e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    // Determine the extents of the final mosaic
158e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    CSite *csite = m_AllSites ;
159e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    for(int mfit = 0; mfit < frames_size; mfit++)
160e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    {
161e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        mb = frames[mfit];
162e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
163e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        // Compute clipping for this frame's rect
164e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        FrameToMosaicRect(mb->width, mb->height, mb->trs, mb->brect);
165e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        // Clip global rect using this frame's rect
166e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        ClipRect(mb->brect, global_rect);
167e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
168e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        // Calculate the corner points
169e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        FrameToMosaic(mb->trs, 0.0,             0.0,            x0, y0);
170e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        FrameToMosaic(mb->trs, 0.0,             mb->height-1.0, x1, y1);
171e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        FrameToMosaic(mb->trs, mb->width-1.0,   mb->height-1.0, x2, y2);
172e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        FrameToMosaic(mb->trs, mb->width-1.0,   0.0,            x3, y3);
173e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
174a369cd3153170975a5e5bd6fa5544dcd6f22ee85mbansal        if(x0 < xLeftCorners[0] || x1 < xLeftCorners[1])    // If either of the left corners is lower
1756c5b20113ba9f91352f32e5a53df66aec0ec761ambansal        {
176a369cd3153170975a5e5bd6fa5544dcd6f22ee85mbansal            xLeftCorners[0] = x0;
177a369cd3153170975a5e5bd6fa5544dcd6f22ee85mbansal            xLeftCorners[1] = x1;
1786c5b20113ba9f91352f32e5a53df66aec0ec761ambansal        }
1796c5b20113ba9f91352f32e5a53df66aec0ec761ambansal
180a369cd3153170975a5e5bd6fa5544dcd6f22ee85mbansal        if(x3 > xRightCorners[0] || x2 > xRightCorners[1])    // If either of the right corners is higher
1816c5b20113ba9f91352f32e5a53df66aec0ec761ambansal        {
182a369cd3153170975a5e5bd6fa5544dcd6f22ee85mbansal            xRightCorners[0] = x3;
183a369cd3153170975a5e5bd6fa5544dcd6f22ee85mbansal            xRightCorners[1] = x2;
1846c5b20113ba9f91352f32e5a53df66aec0ec761ambansal        }
1856c5b20113ba9f91352f32e5a53df66aec0ec761ambansal
186ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal        if(y0 < yTopCorners[0] || y3 < yTopCorners[1])    // If either of the top corners is lower
187ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal        {
188ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal            yTopCorners[0] = y0;
189ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal            yTopCorners[1] = y3;
190ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal        }
191ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal
192ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal        if(y1 > yBottomCorners[0] || y2 > yBottomCorners[1])    // If either of the bottom corners is higher
193ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal        {
194ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal            yBottomCorners[0] = y1;
195ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal            yBottomCorners[1] = y2;
196ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal        }
197ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal
198ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal
199e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        // Compute the centroid of the warped region
200e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        FindQuadCentroid(x0, y0, x1, y1, x2, y2, x3, y3, csite->getVCenter().x, csite->getVCenter().y);
201e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
202e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        csite->setMb(mb);
203e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        csite++;
204e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    }
205e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
206e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    // Get origin and sizes
2076c5b20113ba9f91352f32e5a53df66aec0ec761ambansal
2086c5b20113ba9f91352f32e5a53df66aec0ec761ambansal    // Bounding rectangle (int numbers) of the final mosaic computed by projecting
2096c5b20113ba9f91352f32e5a53df66aec0ec761ambansal    // each input frame into the mosaic coordinate system.
210e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    MosaicRect fullRect;
211e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
212e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    fullRect.left = (int) floor(global_rect.lft); // min-x
213e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    fullRect.top = (int) floor(global_rect.bot);  // min-y
214e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    fullRect.right = (int) ceil(global_rect.rgt); // max-x
215e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    fullRect.bottom = (int) ceil(global_rect.top);// max-y
216e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    Mwidth = (unsigned short) (fullRect.right - fullRect.left + 1);
217e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    Mheight = (unsigned short) (fullRect.bottom - fullRect.top + 1);
218e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
219a369cd3153170975a5e5bd6fa5544dcd6f22ee85mbansal    int xLeftMost, xRightMost;
220ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal    int yTopMost, yBottomMost;
2216c5b20113ba9f91352f32e5a53df66aec0ec761ambansal
222a369cd3153170975a5e5bd6fa5544dcd6f22ee85mbansal    // Rounding up, so that we don't include the gray border.
223a369cd3153170975a5e5bd6fa5544dcd6f22ee85mbansal    xLeftMost = max(0, max(xLeftCorners[0], xLeftCorners[1]) - fullRect.left + 1);
224a369cd3153170975a5e5bd6fa5544dcd6f22ee85mbansal    xRightMost = min(Mwidth - 1, min(xRightCorners[0], xRightCorners[1]) - fullRect.left - 1);
2256c5b20113ba9f91352f32e5a53df66aec0ec761ambansal
226ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal    yTopMost = max(0, max(yTopCorners[0], yTopCorners[1]) - fullRect.top + 1);
227ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal    yBottomMost = min(Mheight - 1, min(yBottomCorners[0], yBottomCorners[1]) - fullRect.top - 1);
228ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal
2290a039136e8e46ddbcb45b55e92d80ddb2ddfc2c2Wei-Ta Chen    if (xRightMost <= xLeftMost || yBottomMost <= yTopMost)
2300a039136e8e46ddbcb45b55e92d80ddb2ddfc2c2Wei-Ta Chen    {
2310a039136e8e46ddbcb45b55e92d80ddb2ddfc2c2Wei-Ta Chen        LOGE("RunBlend: aborting -consistency check failed,"
2320a039136e8e46ddbcb45b55e92d80ddb2ddfc2c2Wei-Ta Chen             "(xLeftMost, xRightMost, yTopMost, yBottomMost): (%d, %d, %d, %d)",
2330a039136e8e46ddbcb45b55e92d80ddb2ddfc2c2Wei-Ta Chen             xLeftMost, xRightMost, yTopMost, yBottomMost);
2340a039136e8e46ddbcb45b55e92d80ddb2ddfc2c2Wei-Ta Chen        return BLEND_RET_ERROR;
2350a039136e8e46ddbcb45b55e92d80ddb2ddfc2c2Wei-Ta Chen    }
2360a039136e8e46ddbcb45b55e92d80ddb2ddfc2c2Wei-Ta Chen
237e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    // Make sure image width is multiple of 4
238e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    Mwidth = (unsigned short) ((Mwidth + 3) & ~3);
239e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    Mheight = (unsigned short) ((Mheight + 3) & ~3);    // Round up.
240e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
2410a039136e8e46ddbcb45b55e92d80ddb2ddfc2c2Wei-Ta Chen    ret = MosaicSizeCheck(LIMIT_SIZE_MULTIPLIER, LIMIT_HEIGHT_MULTIPLIER);
2420a039136e8e46ddbcb45b55e92d80ddb2ddfc2c2Wei-Ta Chen    if (ret != BLEND_RET_OK)
243e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    {
2440a039136e8e46ddbcb45b55e92d80ddb2ddfc2c2Wei-Ta Chen       LOGE("RunBlend: aborting - mosaic size check failed, "
2450a039136e8e46ddbcb45b55e92d80ddb2ddfc2c2Wei-Ta Chen            "(frame_width, frame_height) vs (mosaic_width, mosaic_height): "
2460a039136e8e46ddbcb45b55e92d80ddb2ddfc2c2Wei-Ta Chen            "(%d, %d) vs (%d, %d)", width, height, Mwidth, Mheight);
2470a039136e8e46ddbcb45b55e92d80ddb2ddfc2c2Wei-Ta Chen       return ret;
248e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    }
249e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
25089b9c07b5bbcc2de25dd5f61c28de4575b4df996Wei-Ta Chen    LOGI("Allocate mosaic image for blending - size: %d x %d", Mwidth, Mheight);
251e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    YUVinfo *imgMos = YUVinfo::allocateImage(Mwidth, Mheight);
252e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    if (imgMos == NULL)
253e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    {
254274ca49c63557a8c3ee12c8da5f75e28b4875a5dWei-Ta Chen        LOGE("RunBlend: aborting - couldn't alloc %d x %d mosaic image", Mwidth, Mheight);
255e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        return BLEND_RET_ERROR_MEMORY;
256e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    }
257e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
258e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    // Set the Y image to 255 so we can distinguish when frame idx are written to it
259e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    memset(imgMos->Y.ptr[0], 255, (imgMos->Y.width * imgMos->Y.height));
260e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    // Set the v and u images to black
261e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    memset(imgMos->V.ptr[0], 128, (imgMos->V.width * imgMos->V.height) << 1);
262e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
263e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    // Do the triangulation.  It returns a sorted list of edges
264e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    SEdgeVector *edge;
265e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    int n = m_Triangulator.triangulate(&edge, numCenters, width, height);
266e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    m_Triangulator.linkNeighbors(edge, n, numCenters);
267e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
2686c5b20113ba9f91352f32e5a53df66aec0ec761ambansal    // Bounding rectangle that determines the positioning of the rectangle that is
2696c5b20113ba9f91352f32e5a53df66aec0ec761ambansal    // cropped out of the computed mosaic to get rid of the gray borders.
270e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    MosaicRect cropping_rect;
271e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
272ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal    if (m_wb.horizontal)
273ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal    {
274ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal        cropping_rect.left = xLeftMost;
275ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal        cropping_rect.right = xRightMost;
276ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal    }
277ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal    else
278ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal    {
279ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal        cropping_rect.top = yTopMost;
280ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal        cropping_rect.bottom = yBottomMost;
281ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal    }
2826c5b20113ba9f91352f32e5a53df66aec0ec761ambansal
283e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    // Do merging and blending :
28450b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal    ret = DoMergeAndBlend(frames, numCenters, width, height, *imgMos, fullRect,
285e1178a73fd5756771d25d0b8375452450f509e99mbansal            cropping_rect, progress, cancelComputation);
286e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
287e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    if (m_wb.blendingType == BLEND_TYPE_HORZ)
288e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        CropFinalMosaic(*imgMos, cropping_rect);
289e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
290e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
291e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    m_Triangulator.freeMemory();    // note: can be called even if delaunay_alloc() wasn't successful
292e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
293e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    imageMosaicYVU = imgMos->Y.ptr[0];
294e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
295e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
296e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    if (m_wb.blendingType == BLEND_TYPE_HORZ)
297e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    {
298e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        mosaicWidth = cropping_rect.right - cropping_rect.left + 1;
299e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        mosaicHeight = cropping_rect.bottom - cropping_rect.top + 1;
300e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    }
301e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    else
302e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    {
303e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        mosaicWidth = Mwidth;
304e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        mosaicHeight = Mheight;
305e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    }
306e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
307e1178a73fd5756771d25d0b8375452450f509e99mbansal    return ret;
308e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen}
309e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
3100a039136e8e46ddbcb45b55e92d80ddb2ddfc2c2Wei-Ta Chenint Blend::MosaicSizeCheck(float sizeMultiplier, float heightMultiplier) {
3110a039136e8e46ddbcb45b55e92d80ddb2ddfc2c2Wei-Ta Chen   if (Mwidth < width || Mheight < height) {
3120a039136e8e46ddbcb45b55e92d80ddb2ddfc2c2Wei-Ta Chen        return BLEND_RET_ERROR;
3130a039136e8e46ddbcb45b55e92d80ddb2ddfc2c2Wei-Ta Chen    }
3140a039136e8e46ddbcb45b55e92d80ddb2ddfc2c2Wei-Ta Chen
3150a039136e8e46ddbcb45b55e92d80ddb2ddfc2c2Wei-Ta Chen   if ((Mwidth * Mheight) > (width * height * sizeMultiplier)) {
3160a039136e8e46ddbcb45b55e92d80ddb2ddfc2c2Wei-Ta Chen         return BLEND_RET_ERROR;
3170a039136e8e46ddbcb45b55e92d80ddb2ddfc2c2Wei-Ta Chen   }
3180a039136e8e46ddbcb45b55e92d80ddb2ddfc2c2Wei-Ta Chen
3190a039136e8e46ddbcb45b55e92d80ddb2ddfc2c2Wei-Ta Chen   // We won't do blending for the cases where users swing the device too much
3200a039136e8e46ddbcb45b55e92d80ddb2ddfc2c2Wei-Ta Chen   // in the secondary direction. We use a short side to determine the
3210a039136e8e46ddbcb45b55e92d80ddb2ddfc2c2Wei-Ta Chen   // secondary direction because users may hold the device in landsape
3220a039136e8e46ddbcb45b55e92d80ddb2ddfc2c2Wei-Ta Chen   // or portrait.
3230a039136e8e46ddbcb45b55e92d80ddb2ddfc2c2Wei-Ta Chen   int shortSide = min(Mwidth, Mheight);
3240a039136e8e46ddbcb45b55e92d80ddb2ddfc2c2Wei-Ta Chen   if (shortSide > height * heightMultiplier) {
3250a039136e8e46ddbcb45b55e92d80ddb2ddfc2c2Wei-Ta Chen       return BLEND_RET_ERROR;
3260a039136e8e46ddbcb45b55e92d80ddb2ddfc2c2Wei-Ta Chen   }
3270a039136e8e46ddbcb45b55e92d80ddb2ddfc2c2Wei-Ta Chen
3280a039136e8e46ddbcb45b55e92d80ddb2ddfc2c2Wei-Ta Chen   return BLEND_RET_OK;
3290a039136e8e46ddbcb45b55e92d80ddb2ddfc2c2Wei-Ta Chen}
330e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
331e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chenint Blend::FillFramePyramid(MosaicFrame *mb)
332e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen{
333e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    ImageType mbY, mbU, mbV;
334e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    // Lay this image, centered into the temporary buffer
335e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    mbY = mb->image;
336e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    mbU = mb->getU();
337e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    mbV = mb->getV();
338e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
339e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    int h, w;
340e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
341e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    for(h=0; h<height; h++)
342e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    {
343e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        ImageTypeShort yptr = m_pFrameYPyr->ptr[h];
344e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        ImageTypeShort uptr = m_pFrameUPyr->ptr[h];
345e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        ImageTypeShort vptr = m_pFrameVPyr->ptr[h];
346e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
347e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        for(w=0; w<width; w++)
348e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        {
349e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            yptr[w] = (short) ((*(mbY++)) << 3);
350e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            uptr[w] = (short) ((*(mbU++)) << 3);
351e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            vptr[w] = (short) ((*(mbV++)) << 3);
352e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        }
353e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    }
354e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
355e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    // Spread the image through the border
356e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    PyramidShort::BorderSpread(m_pFrameYPyr, BORDER, BORDER, BORDER, BORDER);
357e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    PyramidShort::BorderSpread(m_pFrameUPyr, BORDER, BORDER, BORDER, BORDER);
358e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    PyramidShort::BorderSpread(m_pFrameVPyr, BORDER, BORDER, BORDER, BORDER);
359e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
360e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    // Generate Laplacian pyramids
361e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    if (!PyramidShort::BorderReduce(m_pFrameYPyr, m_wb.nlevs) || !PyramidShort::BorderExpand(m_pFrameYPyr, m_wb.nlevs, -1) ||
362e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            !PyramidShort::BorderReduce(m_pFrameUPyr, m_wb.nlevsC) || !PyramidShort::BorderExpand(m_pFrameUPyr, m_wb.nlevsC, -1) ||
363e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            !PyramidShort::BorderReduce(m_pFrameVPyr, m_wb.nlevsC) || !PyramidShort::BorderExpand(m_pFrameVPyr, m_wb.nlevsC, -1))
364e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    {
365274ca49c63557a8c3ee12c8da5f75e28b4875a5dWei-Ta Chen        LOGE("Error: Could not generate Laplacian pyramids");
366e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        return BLEND_RET_ERROR;
367e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    }
368e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    else
369e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    {
370e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        return BLEND_RET_OK;
371e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    }
372e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen}
373e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
374e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chenint Blend::DoMergeAndBlend(MosaicFrame **frames, int nsite,
37550b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal             int width, int height, YUVinfo &imgMos, MosaicRect &rect,
376e1178a73fd5756771d25d0b8375452450f509e99mbansal             MosaicRect &cropping_rect, float &progress, bool &cancelComputation)
377e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen{
378e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    m_pMosaicYPyr = NULL;
379e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    m_pMosaicUPyr = NULL;
380e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    m_pMosaicVPyr = NULL;
381e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
382e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    m_pMosaicYPyr = PyramidShort::allocatePyramidPacked(m_wb.nlevs,(unsigned short)rect.Width(),(unsigned short)rect.Height(),BORDER);
383e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    m_pMosaicUPyr = PyramidShort::allocatePyramidPacked(m_wb.nlevsC,(unsigned short)rect.Width(),(unsigned short)rect.Height(),BORDER);
384e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    m_pMosaicVPyr = PyramidShort::allocatePyramidPacked(m_wb.nlevsC,(unsigned short)rect.Width(),(unsigned short)rect.Height(),BORDER);
385e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    if (!m_pMosaicYPyr || !m_pMosaicUPyr || !m_pMosaicVPyr)
386e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    {
387274ca49c63557a8c3ee12c8da5f75e28b4875a5dWei-Ta Chen      LOGE("Error: Could not allocate pyramids for blending");
388e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen      return BLEND_RET_ERROR_MEMORY;
389e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    }
390e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
391e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    MosaicFrame *mb;
392e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
393e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    CSite *esite = m_AllSites + nsite;
394e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    int site_idx;
395e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
396e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    // First go through each frame and for each mosaic pixel determine which frame it should come from
397e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    site_idx = 0;
398e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    for(CSite *csite = m_AllSites; csite < esite; csite++)
399e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    {
400e1178a73fd5756771d25d0b8375452450f509e99mbansal        if(cancelComputation)
401e1178a73fd5756771d25d0b8375452450f509e99mbansal        {
402e1178a73fd5756771d25d0b8375452450f509e99mbansal            if (m_pMosaicVPyr) free(m_pMosaicVPyr);
403e1178a73fd5756771d25d0b8375452450f509e99mbansal            if (m_pMosaicUPyr) free(m_pMosaicUPyr);
404e1178a73fd5756771d25d0b8375452450f509e99mbansal            if (m_pMosaicYPyr) free(m_pMosaicYPyr);
405e1178a73fd5756771d25d0b8375452450f509e99mbansal            return BLEND_RET_CANCELLED;
406e1178a73fd5756771d25d0b8375452450f509e99mbansal        }
407e1178a73fd5756771d25d0b8375452450f509e99mbansal
408e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        mb = csite->getMb();
409e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
410e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        mb->vcrect = mb->brect;
411e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        ClipBlendRect(csite, mb->vcrect);
412e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
413e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        ComputeMask(csite, mb->vcrect, mb->brect, rect, imgMos, site_idx);
414e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
415e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        site_idx++;
416e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    }
417e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
418b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal    ////////// imgMos.Y, imgMos.V, imgMos.U are used as follows //////////////
419b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal    ////////////////////// THIN STRIP MODE ///////////////////////////////////
420b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal
421b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal    // imgMos.Y is used to store the index of the image from which each pixel
422b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal    // in the output mosaic can be read out for the thin-strip mode. Thus,
423b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal    // there is no special handling for pixels around the seam. Also, imgMos.Y
424b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal    // is set to 255 wherever we can't get its value from any input image e.g.
425b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal    // in the gray border areas. imgMos.V and imgMos.U are set to 128 for the
426b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal    // thin-strip mode.
427b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal
428b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal    ////////////////////// WIDE STRIP MODE ///////////////////////////////////
429b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal
430b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal    // imgMos.Y is used the same way as the thin-strip mode.
431b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal    // imgMos.V is used to store the index of the neighboring image which
432b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal    // should contribute to the color of an output pixel in a band around
433b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal    // the seam. Thus, in this band, we will crossfade between the color values
434b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal    // from the image index imgMos.Y and image index imgMos.V. imgMos.U is
435b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal    // used to store the weight (multiplied by 100) that each image will
436b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal    // contribute to the blending process. Thus, we start at 99% contribution
437b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal    // from the first image, then go to 50% contribution from each image at
438b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal    // the seam. Then, the contribution from the second image goes up to 99%.
439b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal
440b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal    // For WIDE mode, set the pixel masks to guide the blender to cross-fade
441b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal    // between the images on either side of each seam:
442b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal    if (m_wb.stripType == STRIP_TYPE_WIDE)
443b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal    {
444ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal        if(m_wb.horizontal)
445b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal        {
446ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal            // Set the number of pixels around the seam to cross-fade between
447ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal            // the two component images,
4488252bf716c798a1007e7869569b35815d2df3c6cmbansal            int tw = STRIP_CROSS_FADE_WIDTH_PXLS;
449ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal
450d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen            // Proceed with the image index calculation for cross-fading
451d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen            // only if the cross-fading width is larger than 0
452d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen            if (tw > 0)
453b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal            {
454d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen                for(int y = 0; y < imgMos.Y.height; y++)
455b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal                {
456d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen                    // Since we compare two adjecant pixels to determine
457d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen                    // whether there is a seam, the termination condition of x
458d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen                    // is set to imgMos.Y.width - tw, so that x+1 below
459d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen                    // won't exceed the imgMos' boundary.
460d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen                    for(int x = tw; x < imgMos.Y.width - tw; )
461b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal                    {
462d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen                        // Determine where the seam is...
463d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen                        if (imgMos.Y.ptr[y][x] != imgMos.Y.ptr[y][x+1] &&
464d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen                                imgMos.Y.ptr[y][x] != 255 &&
465d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen                                imgMos.Y.ptr[y][x+1] != 255)
466ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal                        {
467d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen                            // Find the image indices on both sides of the seam
468d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen                            unsigned char idx1 = imgMos.Y.ptr[y][x];
469d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen                            unsigned char idx2 = imgMos.Y.ptr[y][x+1];
470d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen
471d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen                            for (int o = tw; o >= 0; o--)
472d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen                            {
473d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen                                // Set the image index to use for cross-fading
474d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen                                imgMos.V.ptr[y][x - o] = idx2;
475d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen                                // Set the intensity weights to use for cross-fading
476d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen                                imgMos.U.ptr[y][x - o] = 50 + (99 - 50) * o / tw;
477d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen                            }
478d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen
479d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen                            for (int o = 1; o <= tw; o++)
480d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen                            {
481d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen                                // Set the image index to use for cross-fading
482d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen                                imgMos.V.ptr[y][x + o] = idx1;
483d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen                                // Set the intensity weights to use for cross-fading
484d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen                                imgMos.U.ptr[y][x + o] = imgMos.U.ptr[y][x - o];
485d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen                            }
486d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen
487d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen                            x += (tw + 1);
488ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal                        }
489d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen                        else
490ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal                        {
491d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen                            x++;
492ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal                        }
493b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal                    }
494b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal                }
495ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal            }
496ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal        }
497ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal        else
498ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal        {
499ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal            // Set the number of pixels around the seam to cross-fade between
500ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal            // the two component images,
5018252bf716c798a1007e7869569b35815d2df3c6cmbansal            int tw = STRIP_CROSS_FADE_WIDTH_PXLS;
502ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal
503d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen            // Proceed with the image index calculation for cross-fading
504d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen            // only if the cross-fading width is larger than 0
505d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen            if (tw > 0)
506ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal            {
507d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen                for(int x = 0; x < imgMos.Y.width; x++)
508b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal                {
509d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen                    // Since we compare two adjecant pixels to determine
510d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen                    // whether there is a seam, the termination condition of y
511d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen                    // is set to imgMos.Y.height - tw, so that y+1 below
512d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen                    // won't exceed the imgMos' boundary.
513d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen                    for(int y = tw; y < imgMos.Y.height - tw; )
514ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal                    {
515d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen                        // Determine where the seam is...
516d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen                        if (imgMos.Y.ptr[y][x] != imgMos.Y.ptr[y+1][x] &&
517d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen                                imgMos.Y.ptr[y][x] != 255 &&
518d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen                                imgMos.Y.ptr[y+1][x] != 255)
519ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal                        {
520d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen                            // Find the image indices on both sides of the seam
521d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen                            unsigned char idx1 = imgMos.Y.ptr[y][x];
522d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen                            unsigned char idx2 = imgMos.Y.ptr[y+1][x];
523d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen
524d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen                            for (int o = tw; o >= 0; o--)
525d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen                            {
526d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen                                // Set the image index to use for cross-fading
527d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen                                imgMos.V.ptr[y - o][x] = idx2;
528d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen                                // Set the intensity weights to use for cross-fading
529d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen                                imgMos.U.ptr[y - o][x] = 50 + (99 - 50) * o / tw;
530d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen                            }
531d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen
532d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen                            for (int o = 1; o <= tw; o++)
533d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen                            {
534d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen                                // Set the image index to use for cross-fading
535d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen                                imgMos.V.ptr[y + o][x] = idx1;
536d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen                                // Set the intensity weights to use for cross-fading
537d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen                                imgMos.U.ptr[y + o][x] = imgMos.U.ptr[y - o][x];
538d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen                            }
539d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen
540d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen                            y += (tw + 1);
541ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal                        }
542d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen                        else
543ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal                        {
544d97245f738813db9e55e5ae34b01eb7ecd4381e0Wei-Ta Chen                            y++;
545ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal                        }
546ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal                    }
547b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal                }
548b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal            }
549b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal        }
550ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal
551b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal    }
552b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal
553e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    // Now perform the actual blending using the frame assignment determined above
554e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    site_idx = 0;
555e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    for(CSite *csite = m_AllSites; csite < esite; csite++)
556e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    {
557e1178a73fd5756771d25d0b8375452450f509e99mbansal        if(cancelComputation)
558e1178a73fd5756771d25d0b8375452450f509e99mbansal        {
559e1178a73fd5756771d25d0b8375452450f509e99mbansal            if (m_pMosaicVPyr) free(m_pMosaicVPyr);
560e1178a73fd5756771d25d0b8375452450f509e99mbansal            if (m_pMosaicUPyr) free(m_pMosaicUPyr);
561e1178a73fd5756771d25d0b8375452450f509e99mbansal            if (m_pMosaicYPyr) free(m_pMosaicYPyr);
562e1178a73fd5756771d25d0b8375452450f509e99mbansal            return BLEND_RET_CANCELLED;
563e1178a73fd5756771d25d0b8375452450f509e99mbansal        }
564e1178a73fd5756771d25d0b8375452450f509e99mbansal
565e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        mb = csite->getMb();
566e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
567e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
568e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        if(FillFramePyramid(mb)!=BLEND_RET_OK)
569e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            return BLEND_RET_ERROR;
570e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
571e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        ProcessPyramidForThisFrame(csite, mb->vcrect, mb->brect, rect, imgMos, mb->trs, site_idx);
572e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
57350b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal        progress += TIME_PERCENT_BLEND/nsite;
57450b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal
575e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        site_idx++;
576e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    }
577e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
578e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
579e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    // Blend
580e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    PerformFinalBlending(imgMos, cropping_rect);
581e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
582316fa92553bc0d54587f8984b9262769df86cf57Wei-Ta Chen    if (cropping_rect.Width() <= 0 || cropping_rect.Height() <= 0)
583316fa92553bc0d54587f8984b9262769df86cf57Wei-Ta Chen    {
5843002213841cdd25078d37809ad6efd86fd3fb9b0Wei-Ta Chen        LOGE("Size of the cropping_rect is invalid - (width, height): (%d, %d)",
585316fa92553bc0d54587f8984b9262769df86cf57Wei-Ta Chen                cropping_rect.Width(), cropping_rect.Height());
586316fa92553bc0d54587f8984b9262769df86cf57Wei-Ta Chen        return BLEND_RET_ERROR;
587316fa92553bc0d54587f8984b9262769df86cf57Wei-Ta Chen    }
588316fa92553bc0d54587f8984b9262769df86cf57Wei-Ta Chen
589e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    if (m_pMosaicVPyr) free(m_pMosaicVPyr);
590e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    if (m_pMosaicUPyr) free(m_pMosaicUPyr);
591e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    if (m_pMosaicYPyr) free(m_pMosaicYPyr);
592e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
59350b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal    progress += TIME_PERCENT_FINAL;
59450b3c890986aadb3780b4da8c0b8dbb0f1422ebambansal
595e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    return BLEND_RET_OK;
596e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen}
597e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
598e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chenvoid Blend::CropFinalMosaic(YUVinfo &imgMos, MosaicRect &cropping_rect)
599e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen{
600e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    int i, j, k;
601e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    ImageType yimg;
602e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    ImageType uimg;
603e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    ImageType vimg;
604e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
605e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
606e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    yimg = imgMos.Y.ptr[0];
607e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    uimg = imgMos.U.ptr[0];
608e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    vimg = imgMos.V.ptr[0];
609e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
610e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    k = 0;
611e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    for (j = cropping_rect.top; j <= cropping_rect.bottom; j++)
612e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    {
613e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        for (i = cropping_rect.left; i <= cropping_rect.right; i++)
614e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        {
615e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            yimg[k] = yimg[j*imgMos.Y.width+i];
616e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            k++;
617e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        }
618e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    }
619e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    for (j = cropping_rect.top; j <= cropping_rect.bottom; j++)
620e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    {
621e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen       for (i = cropping_rect.left; i <= cropping_rect.right; i++)
622e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        {
623e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            yimg[k] = vimg[j*imgMos.Y.width+i];
624e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            k++;
625e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        }
626e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    }
627e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    for (j = cropping_rect.top; j <= cropping_rect.bottom; j++)
628e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    {
629e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen       for (i = cropping_rect.left; i <= cropping_rect.right; i++)
630e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        {
631e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            yimg[k] = uimg[j*imgMos.Y.width+i];
632e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            k++;
633e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        }
634e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    }
635e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen}
636e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
637e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chenint Blend::PerformFinalBlending(YUVinfo &imgMos, MosaicRect &cropping_rect)
638e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen{
639e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    if (!PyramidShort::BorderExpand(m_pMosaicYPyr, m_wb.nlevs, 1) || !PyramidShort::BorderExpand(m_pMosaicUPyr, m_wb.nlevsC, 1) ||
640e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        !PyramidShort::BorderExpand(m_pMosaicVPyr, m_wb.nlevsC, 1))
641e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    {
642274ca49c63557a8c3ee12c8da5f75e28b4875a5dWei-Ta Chen      LOGE("Error: Could not BorderExpand!");
643e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen      return BLEND_RET_ERROR;
644e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    }
645e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
646e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    ImageTypeShort myimg;
647e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    ImageTypeShort muimg;
648e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    ImageTypeShort mvimg;
649e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    ImageType yimg;
650e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    ImageType uimg;
651e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    ImageType vimg;
652e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
653e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    int cx = (int)imgMos.Y.width/2;
654e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    int cy = (int)imgMos.Y.height/2;
655e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
6566c5b20113ba9f91352f32e5a53df66aec0ec761ambansal    // 2D boolean array that contains true wherever the mosaic image data is
6576c5b20113ba9f91352f32e5a53df66aec0ec761ambansal    // invalid (i.e. in the gray border).
6586c5b20113ba9f91352f32e5a53df66aec0ec761ambansal    bool **b = new bool*[imgMos.Y.height];
6596c5b20113ba9f91352f32e5a53df66aec0ec761ambansal
6606c5b20113ba9f91352f32e5a53df66aec0ec761ambansal    for(int j=0; j<imgMos.Y.height; j++)
6616c5b20113ba9f91352f32e5a53df66aec0ec761ambansal    {
6626c5b20113ba9f91352f32e5a53df66aec0ec761ambansal        b[j] = new bool[imgMos.Y.width];
6636c5b20113ba9f91352f32e5a53df66aec0ec761ambansal    }
664e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
665e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    // Copy the resulting image into the full image using the mask
666e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    int i, j;
667e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
668e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    yimg = imgMos.Y.ptr[0];
669e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    uimg = imgMos.U.ptr[0];
670e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    vimg = imgMos.V.ptr[0];
671e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
672e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    for (j = 0; j < imgMos.Y.height; j++)
673e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    {
674e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        myimg = m_pMosaicYPyr->ptr[j];
675e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        muimg = m_pMosaicUPyr->ptr[j];
676e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        mvimg = m_pMosaicVPyr->ptr[j];
677e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
6786c5b20113ba9f91352f32e5a53df66aec0ec761ambansal        for (i = 0; i<imgMos.Y.width; i++)
679e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        {
680e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            // A final mask was set up previously,
681e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            // if the value is zero skip it, otherwise replace it.
682e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            if (*yimg <255)
683e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            {
684e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                short value = (short) ((*myimg) >> 3);
685e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                if (value < 0) value = 0;
686e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                else if (value > 255) value = 255;
687e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                *yimg = (unsigned char) value;
688e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
689e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                value = (short) ((*muimg) >> 3);
690e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                if (value < 0) value = 0;
691e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                else if (value > 255) value = 255;
692e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                *uimg = (unsigned char) value;
693e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
694e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                value = (short) ((*mvimg) >> 3);
695e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                if (value < 0) value = 0;
696e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                else if (value > 255) value = 255;
697e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                *vimg = (unsigned char) value;
698e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
6996c5b20113ba9f91352f32e5a53df66aec0ec761ambansal                b[j][i] = false;
7006c5b20113ba9f91352f32e5a53df66aec0ec761ambansal
701e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            }
702e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            else
703e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            {   // set border color in here
704e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                *yimg = (unsigned char) 96;
7056c5b20113ba9f91352f32e5a53df66aec0ec761ambansal                *uimg = (unsigned char) 128;
7066c5b20113ba9f91352f32e5a53df66aec0ec761ambansal                *vimg = (unsigned char) 128;
7076c5b20113ba9f91352f32e5a53df66aec0ec761ambansal
7086c5b20113ba9f91352f32e5a53df66aec0ec761ambansal                b[j][i] = true;
709e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            }
710e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
711e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            yimg++;
712e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            uimg++;
713e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            vimg++;
714e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            myimg++;
715e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            muimg++;
716e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            mvimg++;
717e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        }
718e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    }
719e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
720ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal    if(m_wb.horizontal)
721e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    {
722ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal        //Scan through each row and increment top if the row contains any gray
723ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal        for (j = 0; j < imgMos.Y.height; j++)
724e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        {
725ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal            for (i = cropping_rect.left; i < cropping_rect.right; i++)
726e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            {
727ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal                if (b[j][i])
728ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal                {
729ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal                    break; // to next row
730ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal                }
731ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal            }
732ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal
733ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal            if (i == cropping_rect.right)   //no gray pixel in this row!
734ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal            {
735ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal                cropping_rect.top = j;
736ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal                break;
737e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            }
738e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        }
739e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
740ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal        //Scan through each row and decrement bottom if the row contains any gray
741ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal        for (j = imgMos.Y.height-1; j >= 0; j--)
7426c5b20113ba9f91352f32e5a53df66aec0ec761ambansal        {
743ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal            for (i = cropping_rect.left; i < cropping_rect.right; i++)
744ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal            {
745ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal                if (b[j][i])
746ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal                {
747ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal                    break; // to next row
748ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal                }
749ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal            }
750ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal
751ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal            if (i == cropping_rect.right)   //no gray pixel in this row!
752ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal            {
753ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal                cropping_rect.bottom = j;
754ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal                break;
755ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal            }
7566c5b20113ba9f91352f32e5a53df66aec0ec761ambansal        }
757e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    }
758ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal    else // Vertical Mosaic
759e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    {
760ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal        //Scan through each column and increment left if the column contains any gray
761ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal        for (i = 0; i < imgMos.Y.width; i++)
762e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        {
763ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal            for (j = cropping_rect.top; j < cropping_rect.bottom; j++)
764ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal            {
765ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal                if (b[j][i])
766ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal                {
767ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal                    break; // to next column
768ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal                }
769ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal            }
770ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal
771ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal            if (j == cropping_rect.bottom)   //no gray pixel in this column!
772e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            {
773ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal                cropping_rect.left = i;
774ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal                break;
775e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            }
776e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        }
777e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
778ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal        //Scan through each column and decrement right if the column contains any gray
779ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal        for (i = imgMos.Y.width-1; i >= 0; i--)
7806c5b20113ba9f91352f32e5a53df66aec0ec761ambansal        {
781ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal            for (j = cropping_rect.top; j < cropping_rect.bottom; j++)
782ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal            {
783ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal                if (b[j][i])
784ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal                {
785ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal                    break; // to next column
786ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal                }
787ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal            }
788ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal
789ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal            if (j == cropping_rect.bottom)   //no gray pixel in this column!
790ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal            {
791ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal                cropping_rect.right = i;
792ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal                break;
793ff1c641693cf537703fef3949ccf15898c3ad5d0mbansal            }
7946c5b20113ba9f91352f32e5a53df66aec0ec761ambansal        }
795d05569f2b8ff7fafc7b7b6547adf62431a2011b8Wei-Ta Chen
7966c5b20113ba9f91352f32e5a53df66aec0ec761ambansal    }
797e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
798d05569f2b8ff7fafc7b7b6547adf62431a2011b8Wei-Ta Chen    RoundingCroppingSizeToMultipleOf8(cropping_rect);
799d05569f2b8ff7fafc7b7b6547adf62431a2011b8Wei-Ta Chen
8006c5b20113ba9f91352f32e5a53df66aec0ec761ambansal    for(int j=0; j<imgMos.Y.height; j++)
8016c5b20113ba9f91352f32e5a53df66aec0ec761ambansal    {
8026c5b20113ba9f91352f32e5a53df66aec0ec761ambansal        delete b[j];
803e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    }
804e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
8056c5b20113ba9f91352f32e5a53df66aec0ec761ambansal    delete b;
806e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
807e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    return BLEND_RET_OK;
808e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen}
809e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
810d05569f2b8ff7fafc7b7b6547adf62431a2011b8Wei-Ta Chenvoid Blend::RoundingCroppingSizeToMultipleOf8(MosaicRect &rect) {
811d05569f2b8ff7fafc7b7b6547adf62431a2011b8Wei-Ta Chen    int height = rect.bottom - rect.top + 1;
812d05569f2b8ff7fafc7b7b6547adf62431a2011b8Wei-Ta Chen    int residue = height & 7;
813d05569f2b8ff7fafc7b7b6547adf62431a2011b8Wei-Ta Chen    rect.bottom -= residue;
814d05569f2b8ff7fafc7b7b6547adf62431a2011b8Wei-Ta Chen
815d05569f2b8ff7fafc7b7b6547adf62431a2011b8Wei-Ta Chen    int width = rect.right - rect.left + 1;
816d05569f2b8ff7fafc7b7b6547adf62431a2011b8Wei-Ta Chen    residue = width & 7;
817d05569f2b8ff7fafc7b7b6547adf62431a2011b8Wei-Ta Chen    rect.right -= residue;
818d05569f2b8ff7fafc7b7b6547adf62431a2011b8Wei-Ta Chen}
819d05569f2b8ff7fafc7b7b6547adf62431a2011b8Wei-Ta Chen
820e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chenvoid Blend::ComputeMask(CSite *csite, BlendRect &vcrect, BlendRect &brect, MosaicRect &rect, YUVinfo &imgMos, int site_idx)
821e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen{
822e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    PyramidShort *dptr = m_pMosaicYPyr;
823e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
824e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    int nC = m_wb.nlevsC;
825e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    int l = (int) ((vcrect.lft - rect.left));
826e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    int b = (int) ((vcrect.bot - rect.top));
827e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    int r = (int) ((vcrect.rgt - rect.left));
828e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    int t = (int) ((vcrect.top - rect.top));
829e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
830e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    if (vcrect.lft == brect.lft)
831e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        l = (l <= 0) ? -BORDER : l - BORDER;
832e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    else if (l < -BORDER)
833e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        l = -BORDER;
834e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
835e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    if (vcrect.bot == brect.bot)
836e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        b = (b <= 0) ? -BORDER : b - BORDER;
837e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    else if (b < -BORDER)
838e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        b = -BORDER;
839e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
840e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    if (vcrect.rgt == brect.rgt)
841e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        r = (r >= dptr->width) ? dptr->width + BORDER - 1 : r + BORDER;
842e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    else if (r >= dptr->width + BORDER)
843e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        r = dptr->width + BORDER - 1;
844e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
845e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    if (vcrect.top == brect.top)
846e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        t = (t >= dptr->height) ? dptr->height + BORDER - 1 : t + BORDER;
847e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    else if (t >= dptr->height + BORDER)
848e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        t = dptr->height + BORDER - 1;
849e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
850e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    // Walk the Region of interest and populate the pyramid
851e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    for (int j = b; j <= t; j++)
852e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    {
853e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        int jj = j;
854e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        double sj = jj + rect.top;
855e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
856e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        for (int i = l; i <= r; i++)
857e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        {
858e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            int ii = i;
859e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            // project point and then triangulate to neighbors
860e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            double si = ii + rect.left;
861e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
862e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            double dself = hypotSq(csite->getVCenter().x - si, csite->getVCenter().y - sj);
863e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            int inMask = ((unsigned) ii < imgMos.Y.width &&
864e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                    (unsigned) jj < imgMos.Y.height) ? 1 : 0;
865e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
866e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            if(!inMask)
867e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                continue;
868e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
869e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            // scan the neighbors to see if this is a valid position
870e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            unsigned char mask = (unsigned char) 255;
871e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            SEdgeVector *ce;
872e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            int ecnt;
873e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            for (ce = csite->getNeighbor(), ecnt = csite->getNumNeighbors(); ecnt--; ce++)
874e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            {
875e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                double d1 = hypotSq(m_AllSites[ce->second].getVCenter().x - si,
876e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                        m_AllSites[ce->second].getVCenter().y - sj);
877e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                if (d1 < dself)
878e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                {
879e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                    break;
880e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                }
881e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            }
882e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
883e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            if (ecnt >= 0) continue;
884e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
885e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            imgMos.Y.ptr[jj][ii] = (unsigned char)site_idx;
886e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        }
887e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    }
888e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen}
889e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
890e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chenvoid Blend::ProcessPyramidForThisFrame(CSite *csite, BlendRect &vcrect, BlendRect &brect, MosaicRect &rect, YUVinfo &imgMos, double trs[3][3], int site_idx)
891e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen{
892e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    // Put the Region of interest (for all levels) into m_pMosaicYPyr
893e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    double inv_trs[3][3];
894e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    inv33d(trs, inv_trs);
895e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
896e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    // Process each pyramid level
897e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    PyramidShort *sptr = m_pFrameYPyr;
898e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    PyramidShort *suptr = m_pFrameUPyr;
899e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    PyramidShort *svptr = m_pFrameVPyr;
900e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
901e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    PyramidShort *dptr = m_pMosaicYPyr;
902e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    PyramidShort *duptr = m_pMosaicUPyr;
903e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    PyramidShort *dvptr = m_pMosaicVPyr;
904e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
905e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    int dscale = 0; // distance scale for the current level
906e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    int nC = m_wb.nlevsC;
907e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    for (int n = m_wb.nlevs; n--; dscale++, dptr++, sptr++, dvptr++, duptr++, svptr++, suptr++, nC--)
908e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    {
909e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        int l = (int) ((vcrect.lft - rect.left) / (1 << dscale));
910e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        int b = (int) ((vcrect.bot - rect.top) / (1 << dscale));
911e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        int r = (int) ((vcrect.rgt - rect.left) / (1 << dscale) + .5);
912e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        int t = (int) ((vcrect.top - rect.top) / (1 << dscale) + .5);
913e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
914e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        if (vcrect.lft == brect.lft)
915e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            l = (l <= 0) ? -BORDER : l - BORDER;
916e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        else if (l < -BORDER)
917e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            l = -BORDER;
918e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
919e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        if (vcrect.bot == brect.bot)
920e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            b = (b <= 0) ? -BORDER : b - BORDER;
921e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        else if (b < -BORDER)
922e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            b = -BORDER;
923e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
924e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        if (vcrect.rgt == brect.rgt)
925e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            r = (r >= dptr->width) ? dptr->width + BORDER - 1 : r + BORDER;
926e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        else if (r >= dptr->width + BORDER)
927e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            r = dptr->width + BORDER - 1;
928e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
929e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        if (vcrect.top == brect.top)
930e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            t = (t >= dptr->height) ? dptr->height + BORDER - 1 : t + BORDER;
931e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        else if (t >= dptr->height + BORDER)
932e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            t = dptr->height + BORDER - 1;
933e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
934e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        // Walk the Region of interest and populate the pyramid
935e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        for (int j = b; j <= t; j++)
936e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        {
937e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            int jj = (j << dscale);
938e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            double sj = jj + rect.top;
939e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
940e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            for (int i = l; i <= r; i++)
941e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            {
942e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                int ii = (i << dscale);
943e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                // project point and then triangulate to neighbors
944e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                double si = ii + rect.left;
945e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
946e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                int inMask = ((unsigned) ii < imgMos.Y.width &&
947e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                        (unsigned) jj < imgMos.Y.height) ? 1 : 0;
948e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
949b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal                if(inMask && imgMos.Y.ptr[jj][ii] != site_idx &&
950b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal                        imgMos.V.ptr[jj][ii] != site_idx &&
951b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal                        imgMos.Y.ptr[jj][ii] != 255)
952e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                    continue;
953e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
954b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal                // Setup weights for cross-fading
955b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal                // Weight of the intensity already in the output pixel
956b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal                double wt0 = 0.0;
957b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal                // Weight of the intensity from the input pixel (current frame)
958b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal                double wt1 = 1.0;
959b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal
960b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal                if (m_wb.stripType == STRIP_TYPE_WIDE)
961b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal                {
962b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal                    if(inMask && imgMos.Y.ptr[jj][ii] != 255)
963b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal                    {
9648252bf716c798a1007e7869569b35815d2df3c6cmbansal                        // If not on a seam OR pyramid level exceeds
9658252bf716c798a1007e7869569b35815d2df3c6cmbansal                        // maximum level for cross-fading.
9668252bf716c798a1007e7869569b35815d2df3c6cmbansal                        if((imgMos.V.ptr[jj][ii] == 128) ||
9678252bf716c798a1007e7869569b35815d2df3c6cmbansal                            (dscale > STRIP_CROSS_FADE_MAX_PYR_LEVEL))
968b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal                        {
969b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal                            wt0 = 0.0;
970b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal                            wt1 = 1.0;
971b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal                        }
972b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal                        else
973b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal                        {
974b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal                            wt0 = 1.0;
975b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal                            wt1 = ((imgMos.Y.ptr[jj][ii] == site_idx) ?
976b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal                                    (double)imgMos.U.ptr[jj][ii] / 100.0 :
977b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal                                    1.0 - (double)imgMos.U.ptr[jj][ii] / 100.0);
978b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal                        }
979b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal                    }
980b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal                }
981b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal
982e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                // Project this mosaic point into the original frame coordinate space
983e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                double xx, yy;
984e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
985e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                MosaicToFrame(inv_trs, si, sj, xx, yy);
986e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
987e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                if (xx < 0.0 || yy < 0.0 || xx > width - 1.0 || yy > height - 1.0)
988e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                {
989e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                    if(inMask)
990e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                    {
991e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                        imgMos.Y.ptr[jj][ii] = 255;
992b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal                        wt0 = 0.0f;
993b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal                        wt1 = 1.0f;
994e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                    }
995e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                }
996e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
997e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                xx /= (1 << dscale);
998e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                yy /= (1 << dscale);
999e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
1000e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
1001e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                int x1 = (xx >= 0.0) ? (int) xx : (int) floor(xx);
1002e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                int y1 = (yy >= 0.0) ? (int) yy : (int) floor(yy);
1003e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
1004e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                // Final destination in extended pyramid
1005e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen#ifndef LINEAR_INTERP
1006b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal                if(inSegment(x1, sptr->width, BORDER-1) &&
1007b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal                        inSegment(y1, sptr->height, BORDER-1))
1008e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                {
1009e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                    double xfrac = xx - x1;
1010e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                    double yfrac = yy - y1;
1011b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal                    dptr->ptr[j][i] = (short) (wt0 * dptr->ptr[j][i] + .5 +
1012b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal                            wt1 * ciCalc(sptr, x1, y1, xfrac, yfrac));
1013e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                    if (dvptr >= m_pMosaicVPyr && nC > 0)
1014e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                    {
1015b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal                        duptr->ptr[j][i] = (short) (wt0 * duptr->ptr[j][i] + .5 +
1016b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal                                wt1 * ciCalc(suptr, x1, y1, xfrac, yfrac));
1017b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal                        dvptr->ptr[j][i] = (short) (wt0 * dvptr->ptr[j][i] + .5 +
1018b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal                                wt1 * ciCalc(svptr, x1, y1, xfrac, yfrac));
1019e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                    }
1020e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                }
1021e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen#else
1022e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                if(inSegment(x1, sptr->width, BORDER) && inSegment(y1, sptr->height, BORDER))
1023e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                {
1024e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                    int x2 = x1 + 1;
1025e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                    int y2 = y1 + 1;
1026e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                    double xfrac = xx - x1;
1027e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                    double yfrac = yy - y1;
1028e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                    double y1val = sptr->ptr[y1][x1] +
1029e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                        (sptr->ptr[y1][x2] - sptr->ptr[y1][x1]) * xfrac;
1030e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                    double y2val = sptr->ptr[y2][x1] +
1031e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                        (sptr->ptr[y2][x2] - sptr->ptr[y2][x1]) * xfrac;
1032e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                    dptr->ptr[j][i] = (short) (y1val + yfrac * (y2val - y1val));
1033e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
1034e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                    if (dvptr >= m_pMosaicVPyr && nC > 0)
1035e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                    {
1036e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                        y1val = suptr->ptr[y1][x1] +
1037e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                            (suptr->ptr[y1][x2] - suptr->ptr[y1][x1]) * xfrac;
1038e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                        y2val = suptr->ptr[y2][x1] +
1039e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                            (suptr->ptr[y2][x2] - suptr->ptr[y2][x1]) * xfrac;
1040e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
1041e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                        duptr->ptr[j][i] = (short) (y1val + yfrac * (y2val - y1val));
1042e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
1043e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                        y1val = svptr->ptr[y1][x1] +
1044e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                            (svptr->ptr[y1][x2] - svptr->ptr[y1][x1]) * xfrac;
1045e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                        y2val = svptr->ptr[y2][x1] +
1046e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                            (svptr->ptr[y2][x2] - svptr->ptr[y2][x1]) * xfrac;
1047e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
1048e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                        dvptr->ptr[j][i] = (short) (y1val + yfrac * (y2val - y1val));
1049e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                    }
1050e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                }
1051e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen#endif
1052e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                else
1053e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                {
1054e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                    clipToSegment(x1, sptr->width, BORDER);
1055e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                    clipToSegment(y1, sptr->height, BORDER);
1056e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
1057b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal                    dptr->ptr[j][i] = (short) (wt0 * dptr->ptr[j][i] + 0.5 +
1058b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal                            wt1 * sptr->ptr[y1][x1] );
1059e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                    if (dvptr >= m_pMosaicVPyr && nC > 0)
1060e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                    {
1061b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal                        dvptr->ptr[j][i] = (short) (wt0 * dvptr->ptr[j][i] +
1062b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal                                0.5 + wt1 * svptr->ptr[y1][x1] );
1063b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal                        duptr->ptr[j][i] = (short) (wt0 * duptr->ptr[j][i] +
1064b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal                                0.5 + wt1 * suptr->ptr[y1][x1] );
1065e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                    }
1066e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                }
1067e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            }
1068e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        }
1069e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    }
1070e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen}
1071e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
1072e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chenvoid Blend::MosaicToFrame(double trs[3][3], double x, double y, double &wx, double &wy)
1073e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen{
1074e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    double X, Y, z;
1075e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    if (m_wb.theta == 0.0)
1076e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    {
1077e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        X = x;
1078e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        Y = y;
1079e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    }
1080e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    else if (m_wb.horizontal)
1081e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    {
1082e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        double alpha = x * m_wb.direction / m_wb.width;
1083e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        double length = (y - alpha * m_wb.correction) * m_wb.direction + m_wb.radius;
1084e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        double deltaTheta = m_wb.theta * alpha;
1085e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        double sinTheta = sin(deltaTheta);
1086e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        double cosTheta = sqrt(1.0 - sinTheta * sinTheta) * m_wb.direction;
1087e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        X = length * sinTheta + m_wb.x;
1088e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        Y = length * cosTheta + m_wb.y;
1089e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    }
1090e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    else
1091e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    {
1092e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        double alpha = y * m_wb.direction / m_wb.width;
1093e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        double length = (x - alpha * m_wb.correction) * m_wb.direction + m_wb.radius;
1094e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        double deltaTheta = m_wb.theta * alpha;
1095e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        double sinTheta = sin(deltaTheta);
1096e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        double cosTheta = sqrt(1.0 - sinTheta * sinTheta) * m_wb.direction;
1097e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        Y = length * sinTheta + m_wb.y;
1098e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        X = length * cosTheta + m_wb.x;
1099e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    }
1100e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    z = ProjZ(trs, X, Y, 1.0);
1101e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    wx = ProjX(trs, X, Y, z, 1.0);
1102e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    wy = ProjY(trs, X, Y, z, 1.0);
1103e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen}
1104e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
1105e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chenvoid Blend::FrameToMosaic(double trs[3][3], double x, double y, double &wx, double &wy)
1106e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen{
1107e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    // Project into the intermediate Mosaic coordinate system
1108e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    double z = ProjZ(trs, x, y, 1.0);
1109e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    double X = ProjX(trs, x, y, z, 1.0);
1110e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    double Y = ProjY(trs, x, y, z, 1.0);
1111e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
1112e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    if (m_wb.theta == 0.0)
1113e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    {
1114e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        // No rotation, then this is all we need to do.
1115e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        wx = X;
1116e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        wy = Y;
1117e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    }
1118e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    else if (m_wb.horizontal)
1119e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    {
1120e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        double deltaX = X - m_wb.x;
1121e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        double deltaY = Y - m_wb.y;
1122e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        double length = sqrt(deltaX * deltaX + deltaY * deltaY);
1123e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        double deltaTheta = asin(deltaX / length);
1124e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        double alpha = deltaTheta / m_wb.theta;
1125e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        wx = alpha * m_wb.width * m_wb.direction;
1126e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        wy = (length - m_wb.radius) * m_wb.direction + alpha * m_wb.correction;
1127e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    }
1128e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    else
1129e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    {
1130e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        double deltaX = X - m_wb.x;
1131e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        double deltaY = Y - m_wb.y;
1132e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        double length = sqrt(deltaX * deltaX + deltaY * deltaY);
1133e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        double deltaTheta = asin(deltaY / length);
1134e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        double alpha = deltaTheta / m_wb.theta;
1135e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        wy = alpha * m_wb.width * m_wb.direction;
1136e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        wx = (length - m_wb.radius) * m_wb.direction + alpha * m_wb.correction;
1137e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    }
1138e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen}
1139e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
1140e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
1141e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
1142e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen// Clip the region of interest as small as possible by using the Voronoi edges of
1143e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen// the neighbors
1144e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chenvoid Blend::ClipBlendRect(CSite *csite, BlendRect &brect)
1145e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen{
1146e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen      SEdgeVector *ce;
1147e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen      int ecnt;
1148e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen      for (ce = csite->getNeighbor(), ecnt = csite->getNumNeighbors(); ecnt--; ce++)
1149e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen      {
1150e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        // calculate the Voronoi bisector intersection
1151e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        const double epsilon = 1e-5;
1152e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        double dx = (m_AllSites[ce->second].getVCenter().x - m_AllSites[ce->first].getVCenter().x);
1153e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        double dy = (m_AllSites[ce->second].getVCenter().y - m_AllSites[ce->first].getVCenter().y);
1154e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        double xmid = m_AllSites[ce->first].getVCenter().x + dx/2.0;
1155e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        double ymid = m_AllSites[ce->first].getVCenter().y + dy/2.0;
1156e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        double inter;
1157e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
1158e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        if (dx > epsilon)
1159e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        {
1160e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen          // neighbor is on right
1161e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen          if ((inter = m_wb.roundoffOverlap + xmid - dy * (((dy >= 0.0) ? brect.bot : brect.top) - ymid) / dx) < brect.rgt)
1162e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            brect.rgt = inter;
1163e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        }
1164e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        else if (dx < -epsilon)
1165e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        {
1166e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen          // neighbor is on left
1167e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen          if ((inter = -m_wb.roundoffOverlap + xmid - dy * (((dy >= 0.0) ? brect.bot : brect.top) - ymid) / dx) > brect.lft)
1168e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            brect.lft = inter;
1169e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        }
1170e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        if (dy > epsilon)
1171e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        {
1172e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen          // neighbor is above
1173e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen          if ((inter = m_wb.roundoffOverlap + ymid - dx * (((dx >= 0.0) ? brect.lft : brect.rgt) - xmid) / dy) < brect.top)
1174e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            brect.top = inter;
1175e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        }
1176e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        else if (dy < -epsilon)
1177e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        {
1178e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen          // neighbor is below
1179e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen          if ((inter = -m_wb.roundoffOverlap + ymid - dx * (((dx >= 0.0) ? brect.lft : brect.rgt) - xmid) / dy) > brect.bot)
1180e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            brect.bot = inter;
1181e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        }
1182e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen      }
1183e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen}
1184e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
1185e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chenvoid Blend::FrameToMosaicRect(int width, int height, double trs[3][3], BlendRect &brect)
1186e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen{
1187e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    // We need to walk the perimeter since the borders can be bent.
1188e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    brect.lft = brect.bot = 2e30;
1189e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    brect.rgt = brect.top = -2e30;
1190e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    double xpos, ypos;
1191e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    double lasty = height - 1.0;
1192e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    double lastx = width - 1.0;
1193e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    int i;
1194e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
1195e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    for (i = width; i--;)
1196e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    {
1197e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
1198e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        FrameToMosaic(trs, (double) i, 0.0, xpos, ypos);
1199e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        ClipRect(xpos, ypos, brect);
1200e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        FrameToMosaic(trs, (double) i, lasty, xpos, ypos);
1201e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        ClipRect(xpos, ypos, brect);
1202e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    }
1203e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    for (i = height; i--;)
1204e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    {
1205e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        FrameToMosaic(trs, 0.0, (double) i, xpos, ypos);
1206e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        ClipRect(xpos, ypos, brect);
1207e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        FrameToMosaic(trs, lastx, (double) i, xpos, ypos);
1208e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        ClipRect(xpos, ypos, brect);
1209e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    }
1210e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen}
1211e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
1212b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansalvoid Blend::SelectRelevantFrames(MosaicFrame **frames, int frames_size,
1213b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal        MosaicFrame **relevant_frames, int &relevant_frames_size)
1214b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal{
1215b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal    MosaicFrame *first = frames[0];
1216b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal    MosaicFrame *last = frames[frames_size-1];
1217b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal    MosaicFrame *mb;
1218b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal
1219b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal    double fxpos = first->trs[0][2], fypos = first->trs[1][2];
1220b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal
1221b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal    double midX = last->width / 2.0;
1222b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal    double midY = last->height / 2.0;
1223b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal    double z = ProjZ(first->trs, midX, midY, 1.0);
1224b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal    double firstX, firstY;
1225b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal    double prevX = firstX = ProjX(first->trs, midX, midY, z, 1.0);
1226b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal    double prevY = firstY = ProjY(first->trs, midX, midY, z, 1.0);
1227b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal
1228b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal    relevant_frames[0] = first; // Add first frame by default
1229b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal    relevant_frames_size = 1;
1230b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal
1231b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal    for (int i = 0; i < frames_size - 1; i++)
1232b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal    {
1233b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal        mb = frames[i];
1234b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal        double currX, currY;
1235b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal        z = ProjZ(mb->trs, midX, midY, 1.0);
1236b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal        currX = ProjX(mb->trs, midX, midY, z, 1.0);
1237b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal        currY = ProjY(mb->trs, midX, midY, z, 1.0);
1238b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal        double deltaX = currX - prevX;
1239b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal        double deltaY = currY - prevY;
1240b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal        double center2centerDist = sqrt(deltaY * deltaY + deltaX * deltaX);
1241b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal
12428252bf716c798a1007e7869569b35815d2df3c6cmbansal        if (fabs(deltaX) > STRIP_SEPARATION_THRESHOLD_PXLS ||
12438252bf716c798a1007e7869569b35815d2df3c6cmbansal                fabs(deltaY) > STRIP_SEPARATION_THRESHOLD_PXLS)
1244b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal        {
1245b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal            relevant_frames[relevant_frames_size] = mb;
1246b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal            relevant_frames_size++;
1247b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal
1248b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal            prevX = currX;
1249b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal            prevY = currY;
1250b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal        }
1251b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal    }
1252e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
1253b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal    // Add last frame by default
1254b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal    relevant_frames[relevant_frames_size] = last;
1255b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal    relevant_frames_size++;
1256b28b9c0fa991bc97e8aa11da83d27f71fdfef6dambansal}
1257e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
1258e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chenvoid Blend::ComputeBlendParameters(MosaicFrame **frames, int frames_size, int is360)
1259e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen{
12606c5b20113ba9f91352f32e5a53df66aec0ec761ambansal    // For FULL and PAN modes, we do not unwarp the mosaic into a rectangular coordinate system
12616c5b20113ba9f91352f32e5a53df66aec0ec761ambansal    // and so we set the theta to 0 and return.
1262e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    if (m_wb.blendingType != BLEND_TYPE_CYLPAN && m_wb.blendingType != BLEND_TYPE_HORZ)
1263e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    {
1264e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        m_wb.theta = 0.0;
1265e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        return;
1266e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    }
1267e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
1268e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    MosaicFrame *first = frames[0];
1269e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    MosaicFrame *last = frames[frames_size-1];
1270e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    MosaicFrame *mb;
1271e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
12721e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    double lxpos = last->trs[0][2], lypos = last->trs[1][2];
12731e762b1f935c9d4a06af6dd56121590ca81d48b1mbansal    double fxpos = first->trs[0][2], fypos = first->trs[1][2];
1274e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
1275e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    // Calculate warp to produce proper stitching.
1276e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    // get x, y displacement
1277e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    double midX = last->width / 2.0;
1278e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    double midY = last->height / 2.0;
1279e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    double z = ProjZ(first->trs, midX, midY, 1.0);
1280e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    double firstX, firstY;
1281e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    double prevX = firstX = ProjX(first->trs, midX, midY, z, 1.0);
1282e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    double prevY = firstY = ProjY(first->trs, midX, midY, z, 1.0);
1283e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
1284e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    double arcLength, lastTheta;
1285e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    m_wb.theta = lastTheta = arcLength = 0.0;
12866c5b20113ba9f91352f32e5a53df66aec0ec761ambansal
12876c5b20113ba9f91352f32e5a53df66aec0ec761ambansal    // Step through all the frames to compute the total arc-length of the cone
12886c5b20113ba9f91352f32e5a53df66aec0ec761ambansal    // swept while capturing the mosaic (in the original conical coordinate system).
1289e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    for (int i = 0; i < frames_size; i++)
1290e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    {
1291e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        mb = frames[i];
1292e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        double currX, currY;
1293e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        z = ProjZ(mb->trs, midX, midY, 1.0);
1294e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        currX = ProjX(mb->trs, midX, midY, z, 1.0);
1295e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        currY = ProjY(mb->trs, midX, midY, z, 1.0);
1296e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        double deltaX = currX - prevX;
1297e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        double deltaY = currY - prevY;
12986c5b20113ba9f91352f32e5a53df66aec0ec761ambansal
12996c5b20113ba9f91352f32e5a53df66aec0ec761ambansal        // The arcLength is computed by summing the lengths of the chords
13006c5b20113ba9f91352f32e5a53df66aec0ec761ambansal        // connecting the pairwise projected image centers of the input image frames.
1301e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        arcLength += sqrt(deltaY * deltaY + deltaX * deltaX);
13026c5b20113ba9f91352f32e5a53df66aec0ec761ambansal
1303e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        if (!is360)
1304e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        {
1305e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            double thisTheta = asin(mb->trs[1][0]);
1306e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            m_wb.theta += thisTheta - lastTheta;
1307e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            lastTheta = thisTheta;
1308e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        }
13096c5b20113ba9f91352f32e5a53df66aec0ec761ambansal
1310e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        prevX = currX;
1311e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        prevY = currY;
1312e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    }
1313e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
13146c5b20113ba9f91352f32e5a53df66aec0ec761ambansal    // Stretch this to end at the proper alignment i.e. the width of the
13156c5b20113ba9f91352f32e5a53df66aec0ec761ambansal    // rectangle is determined by the arcLength computed above and the cone
13166c5b20113ba9f91352f32e5a53df66aec0ec761ambansal    // sector angle is determined using the rotation of the last frame.
1317e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    m_wb.width = arcLength;
1318e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    if (is360) m_wb.theta = asin(last->trs[1][0]);
1319e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
1320e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    // If there is no rotation, we're done.
1321e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    if (m_wb.theta != 0.0)
1322e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    {
1323e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        double dx = prevX - firstX;
1324e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        double dy = prevY - firstY;
13256c5b20113ba9f91352f32e5a53df66aec0ec761ambansal
13266c5b20113ba9f91352f32e5a53df66aec0ec761ambansal        // If the mosaic was captured by sweeping horizontally
1327e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        if (abs(lxpos - fxpos) > abs(lypos - fypos))
1328e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        {
1329e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            m_wb.horizontal = 1;
1330e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            // Calculate radius position to make ends exactly the same Y offset
1331e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            double radiusTheta = dx / cos(3.14159 / 2.0 - m_wb.theta);
1332e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            m_wb.radius = dy + radiusTheta * cos(m_wb.theta);
1333e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            if (m_wb.radius < 0.0) m_wb.radius = -m_wb.radius;
1334e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        }
1335e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        else
1336e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        {
1337e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            m_wb.horizontal = 0;
1338e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            // Calculate radius position to make ends exactly the same Y offset
1339e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            double radiusTheta = dy / cos(3.14159 / 2.0 - m_wb.theta);
1340e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            m_wb.radius = dx + radiusTheta * cos(m_wb.theta);
1341e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            if (m_wb.radius < 0.0) m_wb.radius = -m_wb.radius;
1342e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        }
1343e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
1344e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        // Determine major direction
1345e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        if (m_wb.horizontal)
1346e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        {
1347e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            // Horizontal strip
13486c5b20113ba9f91352f32e5a53df66aec0ec761ambansal            // m_wb.x,y record the origin of the rectangle coordinate system.
1349e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            if (is360) m_wb.x = firstX;
1350e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            else
1351e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            {
1352e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                if (lxpos - fxpos < 0)
1353e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                {
1354e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                    m_wb.x = firstX + midX;
1355e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                    z = ProjZ(last->trs, 0.0, midY, 1.0);
1356e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                    prevX = ProjX(last->trs, 0.0, midY, z, 1.0);
1357e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                    prevY = ProjY(last->trs, 0.0, midY, z, 1.0);
1358e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                }
1359e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                else
1360e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                {
1361e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                    m_wb.x = firstX - midX;
1362e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                    z = ProjZ(last->trs, last->width - 1.0, midY, 1.0);
1363e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                    prevX = ProjX(last->trs, last->width - 1.0, midY, z, 1.0);
1364e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                    prevY = ProjY(last->trs, last->width - 1.0, midY, z, 1.0);
1365e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                }
1366e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            }
1367e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            dy = prevY - firstY;
1368e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            if (dy < 0.0) m_wb.direction = 1.0;
1369e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            else m_wb.direction = -1.0;
1370e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            m_wb.y = firstY - m_wb.radius * m_wb.direction;
1371e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            if (dy * m_wb.theta > 0.0) m_wb.width = -m_wb.width;
1372e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        }
1373e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        else
1374e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        {
1375e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            // Vertical strip
1376e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            if (is360) m_wb.y = firstY;
1377e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            else
1378e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            {
1379e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                if (lypos - fypos < 0)
1380e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                {
1381e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                    m_wb.x = firstY + midY;
1382e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                    z = ProjZ(last->trs, midX, 0.0, 1.0);
1383e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                    prevX = ProjX(last->trs, midX, 0.0, z, 1.0);
1384e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                    prevY = ProjY(last->trs, midX, 0.0, z, 1.0);
1385e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                }
1386e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                else
1387e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                {
1388e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                    m_wb.x = firstX - midX;
1389e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                    z = ProjZ(last->trs, midX, last->height - 1.0, 1.0);
1390e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                    prevX = ProjX(last->trs, midX, last->height - 1.0, z, 1.0);
1391e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                    prevY = ProjY(last->trs, midX, last->height - 1.0, z, 1.0);
1392e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                }
1393e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            }
1394e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            dx = prevX - firstX;
1395e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            if (dx < 0.0) m_wb.direction = 1.0;
1396e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            else m_wb.direction = -1.0;
1397e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            m_wb.x = firstX - m_wb.radius * m_wb.direction;
1398e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            if (dx * m_wb.theta > 0.0) m_wb.width = -m_wb.width;
1399e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        }
1400e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
1401e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        // Calculate the correct correction factor
1402e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        double deltaX = prevX - m_wb.x;
1403e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        double deltaY = prevY - m_wb.y;
1404e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        double length = sqrt(deltaX * deltaX + deltaY * deltaY);
1405e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        double deltaTheta = (m_wb.horizontal) ? deltaX : deltaY;
1406e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        deltaTheta = asin(deltaTheta / length);
1407e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        m_wb.correction = ((m_wb.radius - length) * m_wb.direction) /
1408e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            (deltaTheta / m_wb.theta);
1409e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    }
1410e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen}
1411