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// pyramid.cpp
18e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
19e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen#include <stdio.h>
20e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen#include <string.h>
21e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
22e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen#include "Pyramid.h"
23e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
24e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen// We allocate the entire pyramid into one contiguous storage. This makes
25e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen// cleanup easier than fragmented stuff. In addition, we added a "pitch"
26e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen// field, so pointer manipulation is much simpler when it would be faster.
27e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta ChenPyramidShort *PyramidShort::allocatePyramidPacked(real levels,
28e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        real width, real height, real border)
29e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen{
30e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    real border2 = (real) (border << 1);
31e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    int lines, size = calcStorage(width, height, border2, levels, &lines);
32e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
33e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    PyramidShort *img = (PyramidShort *) calloc(sizeof(PyramidShort) * levels
34e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            + sizeof(short *) * lines +
35e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            + sizeof(short) * size, 1);
36e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
37e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    if (img) {
38e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        PyramidShort *curr, *last;
39e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        ImageTypeShort *y = (ImageTypeShort *) &img[levels];
40e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        ImageTypeShort position = (ImageTypeShort) &y[lines];
41e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        for (last = (curr = img) + levels; curr < last; curr++) {
42e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            curr->width = width;
43e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            curr->height = height;
44e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            curr->border = border;
45e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            curr->pitch = (real) (width + border2);
46e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            curr->ptr = y + border;
47e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
48e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            // Assign row pointers
49e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            for (int j = height + border2; j--; y++, position += curr->pitch) {
50e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                *y = position + border;
51e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            }
52e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
53e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            width >>= 1;
54e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            height >>= 1;
55e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        }
56e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    }
57e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
58e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    return img;
59e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen}
60e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
61e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen// Allocate an image of type short
62e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta ChenPyramidShort *PyramidShort::allocateImage(real width, real height, real border)
63e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen{
64e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    real border2 = (real) (border << 1);
65e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    PyramidShort *img = (PyramidShort *)
66e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        calloc(sizeof(PyramidShort) + sizeof(short *) * (height + border2) +
67e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                sizeof(short) * (width + border2) * (height + border2), 1);
68e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
69e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    if (img) {
70e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        short **y = (short **) &img[1];
71e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        short *position = (short *) &y[height + border2];
72e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        img->width = width;
73e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        img->height = height;
74e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        img->border = border;
75e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        img->pitch = (real) (width + border2);
76e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        img->ptr = y + border;
77e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        position += border; // Move position down to origin of real image
78e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
79e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        // Assign row pointers
80e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        for (int j = height + border2; j--; y++, position += img->pitch) {
81e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            *y = position;
82e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        }
83e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    }
84e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
85e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    return img;
86e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen}
87e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
88e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen// Free the images
89e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chenvoid PyramidShort::freeImage(PyramidShort *image)
90e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen{
91e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    if (image != NULL)
92e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        free(image);
93e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen}
94e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
95e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen// Calculate amount of storage needed taking into account the borders, etc.
96e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chenunsigned int PyramidShort::calcStorage(real width, real height, real border2,   int levels, int *lines)
97e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen{
98e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    int size;
99e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
100e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    *lines = size = 0;
101e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
102e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    while(levels--) {
103e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        size += (width + border2) * (height + border2);
104e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        *lines += height + border2;
105e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        width >>= 1;
106e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        height >>= 1;
107e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    }
108e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
109e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    return size;
110e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen}
111e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
112e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chenvoid PyramidShort::BorderSpread(PyramidShort *pyr, int left, int right,
113e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        int top, int bot)
114e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen{
115e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    int off, off2, height, h, w;
116e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    ImageTypeShort base;
117e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
118e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    if (left || right) {
119e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        off = pyr->border - left;
120e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        off2 = pyr->width + off + pyr->border - right - 1;
121e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        h = pyr->border - top;
122e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        height = pyr->height + (h << 1);
123e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        base = pyr->ptr[-h] - off;
124e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
125e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        // spread in X
126e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        for (h = height; h--; base += pyr->pitch) {
127e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            for (w = left; w--;)
128e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                base[-1 - w] = base[0];
129e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            for (w = right; w--;)
130e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                base[off2 + w + 1] = base[off2];
131e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        }
132e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    }
133e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
134e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    if (top || bot) {
135e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        // spread in Y
136e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        base = pyr->ptr[top - pyr->border] - pyr->border;
137e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        for (h = top; h--; base -= pyr->pitch) {
138e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            memcpy(base - pyr->pitch, base, pyr->pitch * sizeof(short));
139e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        }
140e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
141e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        base = pyr->ptr[pyr->height + pyr->border - bot] - pyr->border;
142e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        for (h = bot; h--; base += pyr->pitch) {
143e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            memcpy(base, base - pyr->pitch, pyr->pitch * sizeof(short));
144e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        }
145e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    }
146e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen}
147e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
148e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chenvoid PyramidShort::BorderExpandOdd(PyramidShort *in, PyramidShort *out, PyramidShort *scr,
149e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        int mode)
150e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen{
151e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    int i,j;
152e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    int off = in->border / 2;
153e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
154e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    // Vertical Filter
155e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    for (j = -off; j < in->height + off; j++) {
156e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        int j2 = j * 2;
157e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        for (i = -scr->border; i < scr->width + scr->border; i++) {
158e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            scr->ptr[j2][i] = (short)
159e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                ((6 * in->ptr[j][i] + (in->ptr[j-1][i] + in->ptr[j+1][i]) + 4) >> 3);
160e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            scr->ptr[j2+1][i] = (short)((in->ptr[j][i] + in->ptr[j+1][i] + 1) >> 1);
161e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        }
162e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    }
163e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
164e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    BorderSpread(scr, 0, 0, 3, 3);
165e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
166e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    // Horizontal Filter
167e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    for (i = -off; i < scr->width + off; i++) {
168e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        int i2 = i * 2;
169e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        for (j = -out->border; j < out->height + out->border; j++) {
170e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            out->ptr[j][i2] = (short) (out->ptr[j][i2] +
171e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                    (mode * ((6 * scr->ptr[j][i] +
172e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                              scr->ptr[j][i-1] + scr->ptr[j][i+1] + 4) >> 3)));
173e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            out->ptr[j][i2+1] = (short) (out->ptr[j][i2+1] +
174e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                    (mode * ((scr->ptr[j][i] + scr->ptr[j][i+1] + 1) >> 1)));
175e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        }
176e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    }
177e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
178e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen}
179e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
180e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chenint PyramidShort::BorderExpand(PyramidShort *pyr, int nlev, int mode)
181e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen{
182e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    PyramidShort *tpyr = pyr + nlev - 1;
183e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    PyramidShort *scr = allocateImage(pyr[1].width, pyr[0].height, pyr->border);
184e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    if (scr == NULL) return 0;
185e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
186e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    if (mode > 0) {
187e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        // Expand and add (reconstruct from Laplacian)
188e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        for (; tpyr > pyr; tpyr--) {
189e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            scr->width = tpyr[0].width;
190e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            scr->height = tpyr[-1].height;
191e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            BorderExpandOdd(tpyr, tpyr - 1, scr, 1);
192e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        }
193e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    }
194e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    else if (mode < 0) {
195e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        // Expand and subtract (build Laplacian)
196e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        while ((pyr++) < tpyr) {
197e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            scr->width = pyr[0].width;
198e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            scr->height = pyr[-1].height;
199e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            BorderExpandOdd(pyr, pyr - 1, scr, -1);
200e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        }
201e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    }
202e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
203e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    freeImage(scr);
204e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    return 1;
205e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen}
206e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
207e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chenvoid PyramidShort::BorderReduceOdd(PyramidShort *in, PyramidShort *out, PyramidShort *scr)
208e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen{
209e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    ImageTypeShortBase *s, *ns, *ls, *p, *np;
210e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
211e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    int off = scr->border - 2;
212e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    s = scr->ptr[-scr->border] - (off >> 1);
213e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    ns = s + scr->pitch;
214e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    ls = scr->ptr[scr->height + scr->border - 1] + scr->pitch - (off >> 1);
215e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    int width = scr->width + scr->border;
216e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    p = in->ptr[-scr->border] - off;
217e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    np = p + in->pitch;
218e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
219e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    // treat it as if the whole thing were the image
220e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    for (; s < ls; s = ns, ns += scr->pitch, p = np, np += in->pitch) {
221e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        for (int w = width; w--; s++, p += 2) {
222e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            *s = (short)((((int) p[-2]) + ((int) p[2]) + 8 +    // 1
223e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                        ((((int) p[-1]) + ((int) p[1])) << 2) + // 4
224e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                        ((int) *p) * 6) >> 4);          // 6
225e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        }
226e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    }
227e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
228e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    BorderSpread(scr, 5, 4 + ((in->width ^ 1) & 1), 0, 0); //
229e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
230e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    s = out->ptr[-(off >> 1)] - out->border;
231e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    ns = s + out->pitch;
232e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    ls = s + out->pitch * (out->height + off);
233e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    p = scr->ptr[-off] - out->border;
234e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    int pitch = scr->pitch;
235e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    int pitch2 = pitch << 1;
236e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    np = p + pitch2;
237e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    for (; s < ls; s = ns, ns += out->pitch, p = np, np += pitch2) {
238e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        for (int w = out->pitch; w--; s++, p++) {
239e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen            *s = (short)((((int) p[-pitch2]) + ((int) p[pitch2]) + 8 + // 1
240e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                        ((((int) p[-pitch]) + ((int) p[pitch])) << 2) + // 4
241e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen                        ((int) *p) * 6) >> 4);              // 6
242e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        }
243e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    }
244e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    BorderSpread(out, 0, 0, 5, 5);
245e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
246e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen}
247e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
248e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chenint PyramidShort::BorderReduce(PyramidShort *pyr, int nlev)
249e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen{
250e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    PyramidShort *scr = allocateImage(pyr[1].width, pyr[0].height, pyr->border);
251e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    if (scr == NULL)
252e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        return 0;
253e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
254e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    BorderSpread(pyr, pyr->border, pyr->border, pyr->border, pyr->border);
255e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    while (--nlev) {
256e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        BorderReduceOdd(pyr, pyr + 1, scr);
257e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        pyr++;
258e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        scr->width = pyr[1].width;
259e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen        scr->height = pyr[0].height;
260e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    }
261e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen
262e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    freeImage(scr);
263e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen    return 1;
264e295e32b68cf04f0d99138bf4a6d25555f3aef99Wei-Ta Chen}
265