190b1d251973bfa748d435896fc277cb4024451adJohn Hoford/*
290b1d251973bfa748d435896fc277cb4024451adJohn Hoford * Copyright (C) 2012 The Android Open Source Project
390b1d251973bfa748d435896fc277cb4024451adJohn Hoford *
490b1d251973bfa748d435896fc277cb4024451adJohn Hoford * Licensed under the Apache License, Version 2.0 (the "License");
590b1d251973bfa748d435896fc277cb4024451adJohn Hoford * you may not use this file except in compliance with the License.
690b1d251973bfa748d435896fc277cb4024451adJohn Hoford * You may obtain a copy of the License at
790b1d251973bfa748d435896fc277cb4024451adJohn Hoford *
890b1d251973bfa748d435896fc277cb4024451adJohn Hoford *      http://www.apache.org/licenses/LICENSE-2.0
990b1d251973bfa748d435896fc277cb4024451adJohn Hoford *
1090b1d251973bfa748d435896fc277cb4024451adJohn Hoford * Unless required by applicable law or agreed to in writing, software
1190b1d251973bfa748d435896fc277cb4024451adJohn Hoford * distributed under the License is distributed on an "AS IS" BASIS,
1290b1d251973bfa748d435896fc277cb4024451adJohn Hoford * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1390b1d251973bfa748d435896fc277cb4024451adJohn Hoford * See the License for the specific language governing permissions and
1490b1d251973bfa748d435896fc277cb4024451adJohn Hoford * limitations under the License.
1590b1d251973bfa748d435896fc277cb4024451adJohn Hoford */
1690b1d251973bfa748d435896fc277cb4024451adJohn Hoford
1790b1d251973bfa748d435896fc277cb4024451adJohn Hoford#include <math.h>
1890b1d251973bfa748d435896fc277cb4024451adJohn Hoford#include "filters.h"
1990b1d251973bfa748d435896fc277cb4024451adJohn Hoford
2090b1d251973bfa748d435896fc277cb4024451adJohn Hofordint value(int r, int g, int b) {
2190b1d251973bfa748d435896fc277cb4024451adJohn Hoford    return MAX(r, MAX(g, b));
2290b1d251973bfa748d435896fc277cb4024451adJohn Hoford}
2390b1d251973bfa748d435896fc277cb4024451adJohn Hoford
2490b1d251973bfa748d435896fc277cb4024451adJohn Hofordint isRed(unsigned char *src, int p) {
2590b1d251973bfa748d435896fc277cb4024451adJohn Hoford    int b = src[p + 2];
2690b1d251973bfa748d435896fc277cb4024451adJohn Hoford    int g = src[p + 1];
2790b1d251973bfa748d435896fc277cb4024451adJohn Hoford    int r = src[p];
2890b1d251973bfa748d435896fc277cb4024451adJohn Hoford    int max = MAX(g, b);
2990b1d251973bfa748d435896fc277cb4024451adJohn Hoford
3090b1d251973bfa748d435896fc277cb4024451adJohn Hoford    return ((r * 100 / (max + 2) > 160) & (max < 80));
3190b1d251973bfa748d435896fc277cb4024451adJohn Hoford}
3290b1d251973bfa748d435896fc277cb4024451adJohn Hoford
3390b1d251973bfa748d435896fc277cb4024451adJohn Hofordvoid findPossible(unsigned char *src, unsigned char *mask, int iw, int ih,
3490b1d251973bfa748d435896fc277cb4024451adJohn Hoford        short *rect) {
3590b1d251973bfa748d435896fc277cb4024451adJohn Hoford    int recX = rect[0], recY = rect[1], recW = rect[2], recH = rect[3];
3690b1d251973bfa748d435896fc277cb4024451adJohn Hoford    int y, x;
3790b1d251973bfa748d435896fc277cb4024451adJohn Hoford
3890b1d251973bfa748d435896fc277cb4024451adJohn Hoford    for (y = 0; y < recH; y++) {
3990b1d251973bfa748d435896fc277cb4024451adJohn Hoford        int sy = (recY + y) * iw;
4090b1d251973bfa748d435896fc277cb4024451adJohn Hoford        for (x = 0; x < recW; x++) {
4190b1d251973bfa748d435896fc277cb4024451adJohn Hoford            int p = (recX + x + sy) * 4;
4290b1d251973bfa748d435896fc277cb4024451adJohn Hoford
4390b1d251973bfa748d435896fc277cb4024451adJohn Hoford            int b = src[p + 2];
4490b1d251973bfa748d435896fc277cb4024451adJohn Hoford            int g = src[p + 1];
4590b1d251973bfa748d435896fc277cb4024451adJohn Hoford            int r = src[p];
4690b1d251973bfa748d435896fc277cb4024451adJohn Hoford            mask[x + y * recW] = (
4790b1d251973bfa748d435896fc277cb4024451adJohn Hoford                    mask[x + y * recW] > 0 && (value(r, g, b) > 240) ? 1 : 0);
4890b1d251973bfa748d435896fc277cb4024451adJohn Hoford
4990b1d251973bfa748d435896fc277cb4024451adJohn Hoford        }
5090b1d251973bfa748d435896fc277cb4024451adJohn Hoford
5190b1d251973bfa748d435896fc277cb4024451adJohn Hoford    }
5290b1d251973bfa748d435896fc277cb4024451adJohn Hoford}
5390b1d251973bfa748d435896fc277cb4024451adJohn Hoford
5490b1d251973bfa748d435896fc277cb4024451adJohn Hofordvoid findReds(unsigned char *src, unsigned char *mask, int iw, int ih,
5590b1d251973bfa748d435896fc277cb4024451adJohn Hoford        short *rect) {
5690b1d251973bfa748d435896fc277cb4024451adJohn Hoford    int recX = rect[0], recY = rect[1], recW = rect[2], recH = rect[3];
5790b1d251973bfa748d435896fc277cb4024451adJohn Hoford    int y, x;
5890b1d251973bfa748d435896fc277cb4024451adJohn Hoford
5990b1d251973bfa748d435896fc277cb4024451adJohn Hoford    for (y = 0; y < recH; y++) {
6090b1d251973bfa748d435896fc277cb4024451adJohn Hoford        int sy = (recY + y) * iw;
6190b1d251973bfa748d435896fc277cb4024451adJohn Hoford        for (x = 0; x < recW; x++) {
6290b1d251973bfa748d435896fc277cb4024451adJohn Hoford            int p = (recX + x + sy) * 4;
6390b1d251973bfa748d435896fc277cb4024451adJohn Hoford
6490b1d251973bfa748d435896fc277cb4024451adJohn Hoford            mask[x + y * recW] = ((isRed(src, p)) ? 1 : 0);
6590b1d251973bfa748d435896fc277cb4024451adJohn Hoford
6690b1d251973bfa748d435896fc277cb4024451adJohn Hoford        }
6790b1d251973bfa748d435896fc277cb4024451adJohn Hoford
6890b1d251973bfa748d435896fc277cb4024451adJohn Hoford    }
6990b1d251973bfa748d435896fc277cb4024451adJohn Hoford}
7090b1d251973bfa748d435896fc277cb4024451adJohn Hoford
7190b1d251973bfa748d435896fc277cb4024451adJohn Hofordvoid dialateMaskIfRed(unsigned char *src, int iw, int ih, unsigned char *mask,
7290b1d251973bfa748d435896fc277cb4024451adJohn Hoford        unsigned char *out, short *rect) {
7390b1d251973bfa748d435896fc277cb4024451adJohn Hoford    int recX = rect[0], recY = rect[1], recW = rect[2], recH = rect[3];
7490b1d251973bfa748d435896fc277cb4024451adJohn Hoford    int y, x;
7590b1d251973bfa748d435896fc277cb4024451adJohn Hoford
7690b1d251973bfa748d435896fc277cb4024451adJohn Hoford    for (y = 1; y < recH - 1; y++) {
7790b1d251973bfa748d435896fc277cb4024451adJohn Hoford        int row = recW * y;
7890b1d251973bfa748d435896fc277cb4024451adJohn Hoford        int sy = (recY + y) * iw;
7990b1d251973bfa748d435896fc277cb4024451adJohn Hoford        for (x = 1; x < recW - 1; x++) {
8090b1d251973bfa748d435896fc277cb4024451adJohn Hoford            int p = (recX + x + sy) * 4;
8190b1d251973bfa748d435896fc277cb4024451adJohn Hoford
8290b1d251973bfa748d435896fc277cb4024451adJohn Hoford            char b = (mask[row + x] | mask[row + x + 1] | mask[row + x - 1]
8390b1d251973bfa748d435896fc277cb4024451adJohn Hoford                    | mask[row + x - recW] | mask[row + x + recW]);
8490b1d251973bfa748d435896fc277cb4024451adJohn Hoford            if (b != 0 && isRed(src, p))
8590b1d251973bfa748d435896fc277cb4024451adJohn Hoford                out[row + x] = 1;
8690b1d251973bfa748d435896fc277cb4024451adJohn Hoford            else
8790b1d251973bfa748d435896fc277cb4024451adJohn Hoford                out[row + x] = mask[row + x];
8890b1d251973bfa748d435896fc277cb4024451adJohn Hoford        }
8990b1d251973bfa748d435896fc277cb4024451adJohn Hoford    }
9090b1d251973bfa748d435896fc277cb4024451adJohn Hoford}
9190b1d251973bfa748d435896fc277cb4024451adJohn Hoford
9290b1d251973bfa748d435896fc277cb4024451adJohn Hofordvoid dialateMask(unsigned char *mask, unsigned char *out, int mw, int mh) {
9390b1d251973bfa748d435896fc277cb4024451adJohn Hoford    int y, x;
9490b1d251973bfa748d435896fc277cb4024451adJohn Hoford    for (y = 1; y < mh - 1; y++) {
9590b1d251973bfa748d435896fc277cb4024451adJohn Hoford        int row = mw * y;
9690b1d251973bfa748d435896fc277cb4024451adJohn Hoford        for (x = 1; x < mw - 1; x++) {
9790b1d251973bfa748d435896fc277cb4024451adJohn Hoford            out[row + x] = (mask[row + x] | mask[row + x + 1]
9890b1d251973bfa748d435896fc277cb4024451adJohn Hoford                    | mask[row + x - 1] | mask[row + x - mw]
9990b1d251973bfa748d435896fc277cb4024451adJohn Hoford                    | mask[row + x + mw]);
10090b1d251973bfa748d435896fc277cb4024451adJohn Hoford        }
10190b1d251973bfa748d435896fc277cb4024451adJohn Hoford    }
10290b1d251973bfa748d435896fc277cb4024451adJohn Hoford}
10390b1d251973bfa748d435896fc277cb4024451adJohn Hoford
10490b1d251973bfa748d435896fc277cb4024451adJohn Hofordvoid stuff(int r, int g, int b, unsigned char *img, int off) {
10590b1d251973bfa748d435896fc277cb4024451adJohn Hoford    img[off + 2] = b;
10690b1d251973bfa748d435896fc277cb4024451adJohn Hoford    img[off + 1] = g;
10790b1d251973bfa748d435896fc277cb4024451adJohn Hoford    img[off] = r;
10890b1d251973bfa748d435896fc277cb4024451adJohn Hoford}
10990b1d251973bfa748d435896fc277cb4024451adJohn Hoford
11090b1d251973bfa748d435896fc277cb4024451adJohn Hofordvoid filterRedEye(unsigned char *src, unsigned char *dest, int iw, int ih, short *rect) {
11190b1d251973bfa748d435896fc277cb4024451adJohn Hoford    int recX = rect[0], recY = rect[1], recW = rect[2], recH = rect[3];
11290b1d251973bfa748d435896fc277cb4024451adJohn Hoford    unsigned char *mask1 = (unsigned char *) malloc(recW * recH);
11390b1d251973bfa748d435896fc277cb4024451adJohn Hoford    unsigned char *mask2 = (unsigned char *)malloc(recW*recH);
11490b1d251973bfa748d435896fc277cb4024451adJohn Hoford    int QUE_LEN = 100;
11590b1d251973bfa748d435896fc277cb4024451adJohn Hoford    int y, x, i;
11690b1d251973bfa748d435896fc277cb4024451adJohn Hoford
11790b1d251973bfa748d435896fc277cb4024451adJohn Hoford    rect[0] = MAX(rect[0],0);
11890b1d251973bfa748d435896fc277cb4024451adJohn Hoford    rect[1] = MAX(rect[1],0);
11990b1d251973bfa748d435896fc277cb4024451adJohn Hoford    rect[2] = MIN(rect[2]+rect[0],iw)-rect[0];
12090b1d251973bfa748d435896fc277cb4024451adJohn Hoford    rect[3] = MIN(rect[3]+rect[1],ih)-rect[1];
12190b1d251973bfa748d435896fc277cb4024451adJohn Hoford
12290b1d251973bfa748d435896fc277cb4024451adJohn Hoford    findReds(src, mask2, iw, ih, rect);
12390b1d251973bfa748d435896fc277cb4024451adJohn Hoford    dialateMask(mask2, mask1, recW, recH);
12490b1d251973bfa748d435896fc277cb4024451adJohn Hoford    dialateMask(mask1, mask2, recW, recH);
12590b1d251973bfa748d435896fc277cb4024451adJohn Hoford    dialateMask(mask2, mask1, recW, recH);
12690b1d251973bfa748d435896fc277cb4024451adJohn Hoford    dialateMask(mask1, mask2, recW, recH);
12790b1d251973bfa748d435896fc277cb4024451adJohn Hoford    findPossible(src, mask2, iw, ih, rect);
12890b1d251973bfa748d435896fc277cb4024451adJohn Hoford    dialateMask(mask2, mask1, recW, recH);
12990b1d251973bfa748d435896fc277cb4024451adJohn Hoford
13090b1d251973bfa748d435896fc277cb4024451adJohn Hoford    for (i = 0; i < 12; i++) {
13190b1d251973bfa748d435896fc277cb4024451adJohn Hoford        dialateMaskIfRed(src, iw, ih, mask1, mask2, rect);
13290b1d251973bfa748d435896fc277cb4024451adJohn Hoford        dialateMaskIfRed(src, iw, ih, mask2, mask1, rect);
13390b1d251973bfa748d435896fc277cb4024451adJohn Hoford    }
13490b1d251973bfa748d435896fc277cb4024451adJohn Hoford    dialateMask(mask1, mask2, recW, recH);
13590b1d251973bfa748d435896fc277cb4024451adJohn Hoford    dialateMask(mask2, mask1, recW, recH);
13690b1d251973bfa748d435896fc277cb4024451adJohn Hoford
13790b1d251973bfa748d435896fc277cb4024451adJohn Hoford    for (y = 3; y < recH-3; y++) {
13890b1d251973bfa748d435896fc277cb4024451adJohn Hoford        int sy = (recY + y) * iw;
13990b1d251973bfa748d435896fc277cb4024451adJohn Hoford        for (x = 3; x < recW-3; x++) {
14090b1d251973bfa748d435896fc277cb4024451adJohn Hoford            int p = (recX + x + sy) * 4;
14190b1d251973bfa748d435896fc277cb4024451adJohn Hoford
14290b1d251973bfa748d435896fc277cb4024451adJohn Hoford            int b = src[p + 2];
14390b1d251973bfa748d435896fc277cb4024451adJohn Hoford            int g = src[p + 1];
14490b1d251973bfa748d435896fc277cb4024451adJohn Hoford            int r = src[p];
14590b1d251973bfa748d435896fc277cb4024451adJohn Hoford
14690b1d251973bfa748d435896fc277cb4024451adJohn Hoford            if (mask1[x + y * recW] != 0) {
14790b1d251973bfa748d435896fc277cb4024451adJohn Hoford                int m = MAX(g,b);
14890b1d251973bfa748d435896fc277cb4024451adJohn Hoford                float rr = (r - m) / (float) m;
14990b1d251973bfa748d435896fc277cb4024451adJohn Hoford                if (rr > .7f && g < 60 && b < 60) {
15090b1d251973bfa748d435896fc277cb4024451adJohn Hoford                    dest[p + 2] = (0);
15190b1d251973bfa748d435896fc277cb4024451adJohn Hoford                    dest[p + 1] = (0);
15290b1d251973bfa748d435896fc277cb4024451adJohn Hoford                    dest[p] = (0);
15390b1d251973bfa748d435896fc277cb4024451adJohn Hoford                } else {
15490b1d251973bfa748d435896fc277cb4024451adJohn Hoford                    if (mask2[x + y * recW] != 0) {
15590b1d251973bfa748d435896fc277cb4024451adJohn Hoford                        stuff(r / 2, g / 2, b / 2, dest, p);
15690b1d251973bfa748d435896fc277cb4024451adJohn Hoford                    } else
15790b1d251973bfa748d435896fc277cb4024451adJohn Hoford                        stuff((2 * r) / 3, (2 * g) / 3, (2 * b) / 3, dest, p);
15890b1d251973bfa748d435896fc277cb4024451adJohn Hoford                }
15990b1d251973bfa748d435896fc277cb4024451adJohn Hoford
16090b1d251973bfa748d435896fc277cb4024451adJohn Hoford            } else
16190b1d251973bfa748d435896fc277cb4024451adJohn Hoford                stuff(r, g, b, dest, p);
16290b1d251973bfa748d435896fc277cb4024451adJohn Hoford
16390b1d251973bfa748d435896fc277cb4024451adJohn Hoford            //dest[p + 2] = dest[p + 1] =dest[p]=src[p];
16490b1d251973bfa748d435896fc277cb4024451adJohn Hoford        }
16590b1d251973bfa748d435896fc277cb4024451adJohn Hoford
16690b1d251973bfa748d435896fc277cb4024451adJohn Hoford    }
16790b1d251973bfa748d435896fc277cb4024451adJohn Hoford
16890b1d251973bfa748d435896fc277cb4024451adJohn Hoford    free(mask1);
16990b1d251973bfa748d435896fc277cb4024451adJohn Hoford    free(mask2);
17090b1d251973bfa748d435896fc277cb4024451adJohn Hoford}
17190b1d251973bfa748d435896fc277cb4024451adJohn Hoford
17290b1d251973bfa748d435896fc277cb4024451adJohn Hoford
173