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 20 void JNIFUNCF(ImageFilterEdge, nativeApplyFilter, jobject bitmap, jint width, jint height, jfloat p) 21 { 22 char* 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 char * dst = destination; 36 37 int j, k; 38 char * 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 char 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