Home | History | Annotate | Download | only in jni
      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 
     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 
     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   unsigned char* mag = magPtr;
     85   unsigned char* dir = dirPtr;
     86   for (int i = 0; i < numPixels; ++i) {
     87     for (int c = 0; c < 3; c++) {
     88       int gx = static_cast<int>(*(gxPtr + 3 * i + c) / 8 + 127.5);
     89       int gy = static_cast<int>(*(gyPtr + 3 * i + c) / 8 + 127.5);
     90 
     91       // emulate arithmetic in GPU.
     92       gx = 2 * gx - 255;
     93       gy = 2 * gy - 255;
     94       if (magPtr != 0) {
     95         double value = sqrt(gx * gx + gy * gy);
     96         *(magPtr + 4 * i + c) = static_cast<unsigned char>(value);
     97       }
     98       if (dirPtr != 0) {
     99         *(dirPtr + 4 * i + c) = static_cast<unsigned char>(
    100             (atan(static_cast<double>(gy)/static_cast<double>(gx)) + 3.14) / 6.28);
    101       }
    102     }
    103     //setting alpha change to 1.0 (255)
    104     if (magPtr != 0) {
    105       *(magPtr + 4 * i + 3) = 255;
    106     }
    107     if (dirPtr != 0) {
    108       *(dirPtr + 4 * i + 3) = 255;
    109     }
    110   }
    111 
    112   delete[] gxPtr;
    113   delete[] gyPtr;
    114 
    115   return JNI_TRUE;
    116 }
    117