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 "filters.h"
19 
JNIFUNCF(ImageFilterEdge,nativeApplyFilter,jobject bitmap,jint width,jint height,jfloat p)20 void JNIFUNCF(ImageFilterEdge, nativeApplyFilter, jobject bitmap, jint width, jint height, jfloat p)
21 {
22     uint8_t* destination = 0;
23     AndroidBitmap_lockPixels(env, bitmap, (void**) &destination);
24 
25     // using contrast function:
26     // f(v) = exp(-alpha * v^beta)
27     // use beta ~ 1
28 
29     float const alpha = 5.0f;
30     float const beta = p;
31     float const c_min = 100.0f;
32     float const c_max = 500.0f;
33 
34     // pixels must be 4 bytes
35     uint8_t* dst = destination;
36 
37     int j, k;
38     uint8_t* ptr = destination;
39     int row_stride = 4 * width;
40 
41     // set 2 row buffer (avoids bitmap copy)
42     int buf_len = 2 * row_stride;
43     uint8_t buf[buf_len];
44     int buf_row_ring = 0;
45 
46     // set initial buffer to black
47     memset(buf, 0, buf_len * sizeof(char));
48     for (j = 3; j < buf_len; j+=4) {
49         *(buf + j) = 255;  // set initial alphas
50     }
51 
52     // apply sobel filter
53     for (j = 1; j < height - 1; j++) {
54 
55         for (k = 1; k < width - 1; k++){
56             int loc = j * row_stride + k * 4;
57 
58             float bestx = 0.0f;
59             int l;
60             for (l = 0; l < 3; l++) {
61                 float tmp = 0.0f;
62                 tmp += *(ptr + (loc - row_stride + 4 + l));
63                 tmp += *(ptr + (loc + 4 + l)) * 2.0f;
64                 tmp += *(ptr + (loc + row_stride + 4 + l));
65                 tmp -= *(ptr + (loc - row_stride - 4 + l));
66                 tmp -= *(ptr + (loc - 4 + l)) * 2.0f;
67                 tmp -= *(ptr + (loc + row_stride - 4 + l));
68                 if (fabs(tmp) > fabs(bestx)) {
69                     bestx = tmp;
70                 }
71             }
72 
73             float besty = 0.0f;
74             for (l = 0; l < 3; l++) {
75                 float tmp = 0.0f;
76                 tmp -= *(ptr + (loc - row_stride - 4 + l));
77                 tmp -= *(ptr + (loc - row_stride + l)) * 2.0f;
78                 tmp -= *(ptr + (loc - row_stride + 4 + l));
79                 tmp += *(ptr + (loc + row_stride - 4 + l));
80                 tmp += *(ptr + (loc + row_stride + l)) * 2.0f;
81                 tmp += *(ptr + (loc + row_stride + 4 + l));
82                 if (fabs(tmp) > fabs(besty)) {
83                     besty = tmp;
84                 }
85             }
86 
87             // compute gradient magnitude
88             float mag = sqrt(bestx * bestx + besty * besty);
89 
90             // clamp
91             mag = MIN(MAX(c_min, mag), c_max);
92 
93             // scale to [0, 1]
94             mag = (mag - c_min) / (c_max - c_min);
95 
96             float ret = 1.0f - exp (- alpha * pow(mag, beta));
97             ret = 255 * ret;
98 
99             int off = k * 4;
100             *(buf + buf_row_ring + off) = ret;
101             *(buf + buf_row_ring + off + 1) = ret;
102             *(buf + buf_row_ring + off + 2) = ret;
103             *(buf + buf_row_ring + off + 3) = *(ptr + loc + 3);
104         }
105 
106         buf_row_ring += row_stride;
107         buf_row_ring %= buf_len;
108 
109         if (j - 1 >= 0) {
110             memcpy((dst + row_stride * (j - 1)), (buf + buf_row_ring), row_stride * sizeof(char));
111         }
112 
113     }
114     buf_row_ring += row_stride;
115     buf_row_ring %= buf_len;
116     int second_last_row = row_stride * (height - 2);
117     memcpy((dst + second_last_row), (buf + buf_row_ring), row_stride * sizeof(char));
118 
119     // set last row to black
120     int last_row = row_stride * (height - 1);
121     memset((dst + last_row), 0, row_stride * sizeof(char));
122     for (j = 3; j < row_stride; j+=4) {
123         *(dst + last_row + j) = 255;  // set alphas
124     }
125     AndroidBitmap_unlockPixels(env, bitmap);
126 }
127