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 // Native function to extract histogram from image (handed down as ByteBuffer).
18
19 #include "sobeloperator.h"
20
21 #include <math.h>
22 #include <string.h>
23 #include <jni.h>
24 #include <unistd.h>
25 #include <android/log.h>
26
27 #include "imgprocutil.h"
28
29 /*
30 * Perform 1d convolution on 3 channel image either horizontally or vertically.
31 * Parameters:
32 * inputHead: pointer to input image
33 * length: the length of image in the chosen axis.
34 * fragments: number of lines of the image in the chosen axis.
35 * step: the 1d pixel distance between adjacent pixels in the chosen axis.
36 * shift: the 1d pixel distance between adjacent lines in the chosen axis.
37 * filter: pointer to 1d filter
38 * halfSize: the length of filter is supposed to be (2 * halfSize + 1)
39 * outputHead: pointer to output image
40 */
41
computeGradient(unsigned char * dataPtr,int width,int height,short * gxPtr,short * gyPtr)42 void computeGradient(unsigned char* dataPtr, int width, int height, short* gxPtr, short* gyPtr) {
43 for (int i = 0; i < height; i++) {
44 for (int j = 0; j < width; j++) {
45 const int left = (j > 0)? -4 : 0;
46 const int right = (j < width - 1) ? 4 : 0;
47 const int curr = (i * width + j) * 4;
48 const int above = (i > 0) ? curr - 4 * width : curr;
49 const int below = (i < height - 1) ? curr + 4 * width : curr;
50 const int offset = (i * width + j) * 3;
51 for (int c = 0; c < 3; c++) {
52 *(gxPtr + offset + c) =
53 (*(dataPtr + curr + c + right) - *(dataPtr + curr + c + left)) * 2 +
54 *(dataPtr + above + c + right) - *(dataPtr + above + c + left) +
55 *(dataPtr + below + c + right) - *(dataPtr + below + c + left);
56 *(gyPtr + offset + c) =
57 (*(dataPtr + c + below) - *(dataPtr + c + above)) * 2 +
58 *(dataPtr + left + c + below) - *(dataPtr + left + c + above) +
59 *(dataPtr + right + c + below) - *(dataPtr + right + c + above);
60 }
61 }
62 }
63 }
64
Java_androidx_media_filterpacks_image_SobelFilter_sobelOperator(JNIEnv * env,jclass clazz,jint width,jint height,jobject imageBuffer,jobject magBuffer,jobject dirBuffer)65 jboolean Java_androidx_media_filterpacks_image_SobelFilter_sobelOperator(
66 JNIEnv* env, jclass clazz, jint width, jint height, jobject imageBuffer,
67 jobject magBuffer, jobject dirBuffer) {
68
69 if (imageBuffer == 0) {
70 return JNI_FALSE;
71 }
72 unsigned char* srcPtr = static_cast<unsigned char*>(env->GetDirectBufferAddress(imageBuffer));
73 unsigned char* magPtr = (magBuffer == 0) ?
74 0 : static_cast<unsigned char*>(env->GetDirectBufferAddress(magBuffer));
75 unsigned char* dirPtr = (dirBuffer == 0) ?
76 0 : static_cast<unsigned char*>(env->GetDirectBufferAddress(dirBuffer));
77
78 int numPixels = width * height;
79 // TODO: avoid creating and deleting these buffers within this native function.
80 short* gxPtr = new short[3 * numPixels];
81 short* gyPtr = new short[3 * numPixels];
82 computeGradient(srcPtr, width, height, gxPtr, gyPtr);
83
84 for (int i = 0; i < numPixels; ++i) {
85 for (int c = 0; c < 3; c++) {
86 int gx = static_cast<int>(*(gxPtr + 3 * i + c) / 8 + 127.5);
87 int gy = static_cast<int>(*(gyPtr + 3 * i + c) / 8 + 127.5);
88
89 // emulate arithmetic in GPU.
90 gx = 2 * gx - 255;
91 gy = 2 * gy - 255;
92 if (magPtr != 0) {
93 double value = sqrt(gx * gx + gy * gy);
94 *(magPtr + 4 * i + c) = static_cast<unsigned char>(value);
95 }
96 if (dirPtr != 0) {
97 *(dirPtr + 4 * i + c) = static_cast<unsigned char>(
98 (atan(static_cast<double>(gy)/static_cast<double>(gx)) + 3.14) / 6.28);
99 }
100 }
101 //setting alpha change to 1.0 (255)
102 if (magPtr != 0) {
103 *(magPtr + 4 * i + 3) = 255;
104 }
105 if (dirPtr != 0) {
106 *(dirPtr + 4 * i + 3) = 255;
107 }
108 }
109
110 delete[] gxPtr;
111 delete[] gyPtr;
112
113 return JNI_TRUE;
114 }
115