1 /*
2  * Copyright (C) 2012 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <math.h>
18 #include <stdlib.h>
19 
20 #include "filters.h"
21 
value(int r,int g,int b)22 int value(int r, int g, int b) {
23     return MAX(r, MAX(g, b));
24 }
25 
isRed(unsigned char * src,int p)26 int isRed(unsigned char *src, int p) {
27     int b = src[p + 2];
28     int g = src[p + 1];
29     int r = src[p];
30     int max = MAX(g, b);
31 
32     return ((r * 100 / (max + 2) > 160) & (max < 80));
33 }
34 
findPossible(unsigned char * src,unsigned char * mask,int iw,int ih __unused,short * rect)35 void findPossible(unsigned char *src, unsigned char *mask, int iw,
36         int ih __unused, short *rect) {
37     int recX = rect[0], recY = rect[1], recW = rect[2], recH = rect[3];
38     int y, x;
39 
40     for (y = 0; y < recH; y++) {
41         int sy = (recY + y) * iw;
42         for (x = 0; x < recW; x++) {
43             int p = (recX + x + sy) * 4;
44 
45             int b = src[p + 2];
46             int g = src[p + 1];
47             int r = src[p];
48             mask[x + y * recW] = (
49                     mask[x + y * recW] > 0 && (value(r, g, b) > 240) ? 1 : 0);
50 
51         }
52 
53     }
54 }
55 
findReds(unsigned char * src,unsigned char * mask,int iw,int ih __unused,short * rect)56 void findReds(unsigned char *src, unsigned char *mask, int iw, int ih __unused,
57         short *rect) {
58     int recX = rect[0], recY = rect[1], recW = rect[2], recH = rect[3];
59     int y, x;
60 
61     for (y = 0; y < recH; y++) {
62         int sy = (recY + y) * iw;
63         for (x = 0; x < recW; x++) {
64             int p = (recX + x + sy) * 4;
65 
66             mask[x + y * recW] = ((isRed(src, p)) ? 1 : 0);
67 
68         }
69 
70     }
71 }
72 
dialateMaskIfRed(unsigned char * src,int iw,int ih __unused,unsigned char * mask,unsigned char * out,short * rect)73 void dialateMaskIfRed(unsigned char *src, int iw, int ih __unused,
74         unsigned char *mask, unsigned char *out, short *rect) {
75     int recX = rect[0], recY = rect[1], recW = rect[2], recH = rect[3];
76     int y, x;
77 
78     for (y = 1; y < recH - 1; y++) {
79         int row = recW * y;
80         int sy = (recY + y) * iw;
81         for (x = 1; x < recW - 1; x++) {
82             int p = (recX + x + sy) * 4;
83 
84             char b = (mask[row + x] | mask[row + x + 1] | mask[row + x - 1]
85                     | mask[row + x - recW] | mask[row + x + recW]);
86             if (b != 0 && isRed(src, p))
87                 out[row + x] = 1;
88             else
89                 out[row + x] = mask[row + x];
90         }
91     }
92 }
93 
dialateMask(unsigned char * mask,unsigned char * out,int mw,int mh)94 void dialateMask(unsigned char *mask, unsigned char *out, int mw, int mh) {
95     int y, x;
96     for (y = 1; y < mh - 1; y++) {
97         int row = mw * y;
98         for (x = 1; x < mw - 1; x++) {
99             out[row + x] = (mask[row + x] | mask[row + x + 1]
100                     | mask[row + x - 1] | mask[row + x - mw]
101                     | mask[row + x + mw]);
102         }
103     }
104 }
105 
stuff(int r,int g,int b,unsigned char * img,int off)106 void stuff(int r, int g, int b, unsigned char *img, int off) {
107     img[off + 2] = b;
108     img[off + 1] = g;
109     img[off] = r;
110 }
111 
filterRedEye(unsigned char * src,unsigned char * dest,int iw,int ih,short * rect)112 void filterRedEye(unsigned char *src, unsigned char *dest, int iw, int ih, short *rect) {
113     int recX = rect[0], recY = rect[1], recW = rect[2], recH = rect[3];
114     unsigned char *mask1 = (unsigned char *) malloc(recW * recH);
115     unsigned char *mask2 = (unsigned char *)malloc(recW*recH);
116     int y, x, i;
117 
118     rect[0] = MAX(rect[0],0);
119     rect[1] = MAX(rect[1],0);
120     rect[2] = MIN(rect[2]+rect[0],iw)-rect[0];
121     rect[3] = MIN(rect[3]+rect[1],ih)-rect[1];
122 
123     findReds(src, mask2, iw, ih, rect);
124     dialateMask(mask2, mask1, recW, recH);
125     dialateMask(mask1, mask2, recW, recH);
126     dialateMask(mask2, mask1, recW, recH);
127     dialateMask(mask1, mask2, recW, recH);
128     findPossible(src, mask2, iw, ih, rect);
129     dialateMask(mask2, mask1, recW, recH);
130 
131     for (i = 0; i < 12; i++) {
132         dialateMaskIfRed(src, iw, ih, mask1, mask2, rect);
133         dialateMaskIfRed(src, iw, ih, mask2, mask1, rect);
134     }
135     dialateMask(mask1, mask2, recW, recH);
136     dialateMask(mask2, mask1, recW, recH);
137 
138     for (y = 3; y < recH-3; y++) {
139         int sy = (recY + y) * iw;
140         for (x = 3; x < recW-3; x++) {
141             int p = (recX + x + sy) * 4;
142 
143             int b = src[p + 2];
144             int g = src[p + 1];
145             int r = src[p];
146 
147             if (mask1[x + y * recW] != 0) {
148                 int m = MAX(g,b);
149                 float rr = (r - m) / (float) m;
150                 if (rr > .7f && g < 60 && b < 60) {
151                     dest[p + 2] = (0);
152                     dest[p + 1] = (0);
153                     dest[p] = (0);
154                 } else {
155                     if (mask2[x + y * recW] != 0) {
156                         stuff(r / 2, g / 2, b / 2, dest, p);
157                     } else
158                         stuff((2 * r) / 3, (2 * g) / 3, (2 * b) / 3, dest, p);
159                 }
160 
161             } else
162                 stuff(r, g, b, dest, p);
163 
164             //dest[p + 2] = dest[p + 1] =dest[p]=src[p];
165         }
166 
167     }
168 
169     free(mask1);
170     free(mask2);
171 }
172 
173 
174