1227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks/*
2227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Copyright (C) 2012 The Android Open Source Project
3227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks *
4227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Licensed under the Apache License, Version 2.0 (the "License");
5227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * you may not use this file except in compliance with the License.
6227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * You may obtain a copy of the License at
7227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks *
8227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks *      http://www.apache.org/licenses/LICENSE-2.0
9227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks *
10227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Unless required by applicable law or agreed to in writing, software
11227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * distributed under the License is distributed on an "AS IS" BASIS,
12227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * See the License for the specific language governing permissions and
14227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * limitations under the License.
15227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */
16227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
17227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks// Native function to extract histogram from image (handed down as ByteBuffer).
18227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
19227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks#include "sobeloperator.h"
20227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
21227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks#include <math.h>
22227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks#include <string.h>
23227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks#include <jni.h>
24227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks#include <unistd.h>
25227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks#include <android/log.h>
26227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
27227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks#include "imgprocutil.h"
28227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
29227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks/*
30227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Perform 1d convolution on 3 channel image either horizontally or vertically.
31227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks * Parameters:
32227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks *  inputHead: pointer to input image
33227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks *  length: the length of image in the chosen axis.
34227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks *  fragments: number of lines of the image in the chosen axis.
35227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks *  step: the 1d pixel distance between adjacent pixels in the chosen axis.
36227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks *  shift: the 1d pixel distance between adjacent lines in the chosen axis.
37227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks *  filter: pointer to 1d filter
38227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks *  halfSize: the length of filter is supposed to be (2 * halfSize + 1)
39227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks *  outputHead: pointer to output image
40227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks */
41227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
42227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksvoid computeGradient(unsigned char* dataPtr, int width, int height, short* gxPtr, short* gyPtr) {
43227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  for (int i = 0; i < height; i++) {
44227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    for (int j = 0; j < width; j++) {
45227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks      const int left = (j > 0)? -4 : 0;
46227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks      const int right = (j < width - 1) ? 4 : 0;
47227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks      const int curr = (i * width + j) * 4;
48227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks      const int above = (i > 0) ? curr - 4 * width : curr;
49227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks      const int below = (i < height - 1) ? curr + 4 * width : curr;
50227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks      const int offset = (i * width + j) * 3;
51227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks      for (int c = 0; c < 3; c++) {
52227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        *(gxPtr + offset + c) =
53227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            (*(dataPtr + curr + c + right) - *(dataPtr + curr + c + left)) * 2 +
54227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            *(dataPtr + above + c + right) - *(dataPtr + above + c + left) +
55227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            *(dataPtr + below + c + right) - *(dataPtr + below + c + left);
56227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        *(gyPtr + offset + c) =
57227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            (*(dataPtr + c + below) - *(dataPtr + c + above)) * 2 +
58227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            *(dataPtr + left + c + below) - *(dataPtr + left + c + above) +
59227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            *(dataPtr + right + c + below) - *(dataPtr + right + c + above);
60227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks      }
61227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
62227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  }
63227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks}
64227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
65227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksjboolean Java_androidx_media_filterpacks_image_SobelFilter_sobelOperator(
66227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    JNIEnv* env, jclass clazz, jint width, jint height, jobject imageBuffer,
67227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    jobject magBuffer, jobject dirBuffer) {
68227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
69227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  if (imageBuffer == 0) {
70227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    return JNI_FALSE;
71227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  }
72227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  unsigned char* srcPtr = static_cast<unsigned char*>(env->GetDirectBufferAddress(imageBuffer));
73227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  unsigned char* magPtr = (magBuffer == 0) ?
74227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks      0 : static_cast<unsigned char*>(env->GetDirectBufferAddress(magBuffer));
75227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  unsigned char* dirPtr = (dirBuffer == 0) ?
76227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks      0 : static_cast<unsigned char*>(env->GetDirectBufferAddress(dirBuffer));
77227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
78227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  int numPixels = width * height;
79227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  // TODO: avoid creating and deleting these buffers within this native function.
80227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  short* gxPtr = new short[3 * numPixels];
81227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  short* gyPtr = new short[3 * numPixels];
82227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  computeGradient(srcPtr, width, height, gxPtr, gyPtr);
83227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
84227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  unsigned char* mag = magPtr;
85227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  unsigned char* dir = dirPtr;
86227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  for (int i = 0; i < numPixels; ++i) {
87227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    for (int c = 0; c < 3; c++) {
88227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks      int gx = static_cast<int>(*(gxPtr + 3 * i + c) / 8 + 127.5);
89227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks      int gy = static_cast<int>(*(gyPtr + 3 * i + c) / 8 + 127.5);
90227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
91227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks      // emulate arithmetic in GPU.
92227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks      gx = 2 * gx - 255;
93227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks      gy = 2 * gy - 255;
94227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks      if (magPtr != 0) {
95227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        double value = sqrt(gx * gx + gy * gy);
96227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        *(magPtr + 4 * i + c) = static_cast<unsigned char>(value);
97227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks      }
98227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks      if (dirPtr != 0) {
99227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks        *(dirPtr + 4 * i + c) = static_cast<unsigned char>(
100227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks            (atan(static_cast<double>(gy)/static_cast<double>(gx)) + 3.14) / 6.28);
101227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks      }
102227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
103227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    //setting alpha change to 1.0 (255)
104227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    if (magPtr != 0) {
105227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks      *(magPtr + 4 * i + 3) = 255;
106227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
107227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    if (dirPtr != 0) {
108227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks      *(dirPtr + 4 * i + 3) = 255;
109227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks    }
110227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  }
111227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
112227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  delete[] gxPtr;
113227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  delete[] gyPtr;
114227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks
115227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks  return JNI_TRUE;
116227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks}
117