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