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 <stdlib.h>
18 
19 #include "filters.h"
20 
estmateWhite(unsigned char * src,int len,int * wr,int * wb,int * wg)21 void estmateWhite(unsigned char *src, int len, int *wr, int *wb, int *wg) {
22 
23     int STEP = 4;
24     int RANGE = 256;
25     int *histR = (int *) malloc(256*sizeof(int));
26     int *histG = (int *) malloc(256*sizeof(int));
27     int *histB = (int *) malloc(256*sizeof(int));
28     int i;
29     for (i = 0; i < 255; i++) {
30         histR[i] = histG[i] = histB[i] = 0;
31     }
32 
33     for (i = 0; i < len; i+=STEP) {
34         histR[(src[RED])]++;
35         histG[(src[GREEN])]++;
36         histB[(src[BLUE])]++;
37     }
38     int min_r = -1, min_g = -1, min_b = -1;
39     int sum_r = 0, sum_g = 0, sum_b = 0;
40 
41     for (i = 1; i < RANGE-1; i++) {
42         int r = histR[i];
43         int g = histG[i];
44         int b = histB[i];
45         sum_r += r;
46         sum_g += g;
47         sum_b += b;
48 
49         if (r > 0 && min_r < 0) {
50             min_r = i;
51         }
52         if (g > 0 && min_g < 0) {
53             min_g = i;
54         }
55         if (b > 0 && min_b < 0) {
56             min_b = i;
57         }
58     }
59 
60     int sum15r = 0, sum15g = 0, sum15b = 0;
61     int count15r = 0, count15g=0, count15b = 0;
62     int tmp_r = 0, tmp_g = 0, tmp_b = 0;
63 
64     for (i = RANGE-2; i > 0; i--) {
65         int r = histR[i];
66         int g = histG[i];
67         int b = histB[i];
68         tmp_r += r;
69         tmp_g += g;
70         tmp_b += b;
71 
72         if ((tmp_r > sum_r/20) && (tmp_r < sum_r/5)) {
73             sum15r += r*i;
74             count15r += r;
75         }
76         if ((tmp_g > sum_g/20) && (tmp_g < sum_g/5)) {
77             sum15g += g*i;
78             count15g += g;
79         }
80         if ((tmp_b > sum_b/20) && (tmp_b < sum_b/5)) {
81             sum15b += b*i;
82             count15b += b;
83         }
84 
85     }
86     free(histR);
87     free(histG);
88     free(histB);
89 
90     if ((count15r > 0) && (count15g > 0) && (count15b > 0)) {
91         *wr = sum15r/count15r;
92         *wb = sum15g/count15g;
93         *wg = sum15b/count15b;
94     } else {
95         *wg  = *wb = *wr=255;
96     }
97 }
98 
estmateWhiteBox(unsigned char * src,int iw,int ih,int x,int y,int * wr,int * wb,int * wg)99 void estmateWhiteBox(unsigned char *src, int iw, int ih, int x,int y, int *wr, int *wb, int *wg) {
100     int r = 0;
101     int g = 0;
102     int b = 0;
103     int sum = 0;
104     int xp, yp;
105     int bounds = 5;
106     if (x < 0) x = bounds;
107     if (y < 0) y = bounds;
108     if (x >= (iw-bounds)) x = (iw-bounds-1);
109     if (y >= (ih-bounds)) y = (ih-bounds-1);
110     int startx = x - bounds;
111     int starty = y - bounds;
112     int endx = x + bounds;
113     int endy = y + bounds;
114 
115     for (yp = starty; yp < endy; yp++) {
116         for (xp = startx; xp < endx; xp++) {
117             int i = 4*(xp+yp*iw);
118             r += src[RED];
119             g += src[GREEN];
120             b += src[BLUE];
121             sum++;
122         }
123     }
124     *wr = r/sum;
125     *wg = g/sum;
126     *wb = b/sum;
127 }
128 
JNIFUNCF(ImageFilterWBalance,nativeApplyFilter,jobject bitmap,jint width,jint height,int locX,int locY)129 void JNIFUNCF(ImageFilterWBalance, nativeApplyFilter, jobject bitmap, jint width, jint height, int locX,int locY)
130 {
131     char* destination = 0;
132     AndroidBitmap_lockPixels(env, bitmap, (void**) &destination);
133     int i;
134     int len = width * height * 4;
135     unsigned char * rgb = (unsigned char * )destination;
136     int wr;
137     int wg;
138     int wb;
139 
140     if (locX == -1)
141         estmateWhite(rgb,len,&wr,&wg,&wb);
142     else
143         estmateWhiteBox(rgb, width, height,locX,locY,&wr,&wg,&wb);
144 
145     int min = MIN(wr, MIN(wg, wb));
146     int max = MAX(wr, MAX(wg, wb));
147     float avg = (min+max)/2.f;
148     float scaleR =  avg/wr;
149     float scaleG =  avg/wg;
150     float scaleB =  avg/wb;
151 
152     for (i = 0; i < len; i += 4)
153     {
154         int r = rgb[RED];
155         int g = rgb[GREEN];
156         int b = rgb[BLUE];
157 
158         float Rc =  r*scaleR;
159         float Gc =  g*scaleG;
160         float Bc =  b*scaleB;
161 
162         rgb[RED]   = clamp(Rc);
163         rgb[GREEN] = clamp(Gc);
164         rgb[BLUE]  = clamp(Bc);
165     }
166     AndroidBitmap_unlockPixels(env, bitmap);
167 }
168