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 "histogram.h"
20
21 #include <string.h>
22 #include <jni.h>
23 #include <unistd.h>
24 #include <android/log.h>
25
26 #include "imgprocutil.h"
27
addPixelToHistogram(unsigned char * & pImg,int * pHist,int numBins)28 inline void addPixelToHistogram(unsigned char*& pImg, int* pHist, int numBins) {
29 int R = *(pImg++);
30 int G = *(pImg++);
31 int B = *(pImg++);
32 ++pImg;
33 int i = getIntensityFast(R, G, B);
34 int bin = clamp(0, static_cast<int>(static_cast<float>(i * numBins) / 255.0f), numBins - 1);
35 ++pHist[bin];
36 }
37
Java_androidx_media_filterpacks_histogram_GrayHistogramFilter_extractHistogram(JNIEnv * env,jclass clazz,jobject imageBuffer,jobject maskBuffer,jobject histogramBuffer)38 void Java_androidx_media_filterpacks_histogram_GrayHistogramFilter_extractHistogram(
39 JNIEnv* env, jclass clazz, jobject imageBuffer, jobject maskBuffer, jobject histogramBuffer )
40 {
41 unsigned char* pImg = static_cast<unsigned char*>(env->GetDirectBufferAddress(imageBuffer));
42 int* pHist = static_cast<int*>(env->GetDirectBufferAddress(histogramBuffer));
43 int numPixels = env->GetDirectBufferCapacity(imageBuffer) / 4; // 4 bytes per pixel
44 int numBins = env->GetDirectBufferCapacity(histogramBuffer);
45
46 unsigned char* pMask = NULL;
47 if(maskBuffer != NULL) {
48 pMask = static_cast<unsigned char*>(env->GetDirectBufferAddress(maskBuffer));
49 }
50
51 for(int i = 0; i < numBins; ++i) pHist[i] = 0;
52
53 if(pMask == NULL) {
54 for( ; numPixels > 0; --numPixels) {
55 addPixelToHistogram(pImg, pHist, numBins);
56 }
57 } else {
58 for( ; numPixels > 0; --numPixels) {
59 if(*pMask == 0){
60 pMask += 4;
61 pImg += 4; // Note that otherwise addPixelToHistogram advances pImg by 4
62 continue;
63 }
64 pMask += 4;
65 addPixelToHistogram(pImg, pHist, numBins);
66 }
67 }
68 }
69
Java_androidx_media_filterpacks_histogram_ChromaHistogramFilter_extractChromaHistogram(JNIEnv * env,jclass clazz,jobject imageBuffer,jobject histogramBuffer,jint hBins,jint sBins)70 void Java_androidx_media_filterpacks_histogram_ChromaHistogramFilter_extractChromaHistogram(
71 JNIEnv* env, jclass clazz, jobject imageBuffer, jobject histogramBuffer, jint hBins, jint sBins)
72 {
73 unsigned char* pixelIn = static_cast<unsigned char*>(env->GetDirectBufferAddress(imageBuffer));
74 float* histOut = static_cast<float*>(env->GetDirectBufferAddress(histogramBuffer));
75 int numPixels = env->GetDirectBufferCapacity(imageBuffer) / 4; // 4 bytes per pixel
76
77 for (int i = 0; i < hBins * sBins; ++i) histOut[i] = 0.0f;
78
79 int h, s, v;
80 float hScaler = hBins / 256.0f;
81 float sScaler = sBins / 256.0f;
82 for( ; numPixels > 0; --numPixels) {
83 h = *(pixelIn++);
84 s = *(pixelIn++);
85 v = *(pixelIn++);
86 pixelIn++;
87
88 int index = static_cast<int>(s * sScaler) * hBins + static_cast<int>(h * hScaler);
89 histOut[index] += 1.0f;
90 }
91 }
92
Java_androidx_media_filterpacks_histogram_NewChromaHistogramFilter_extractChromaHistogram(JNIEnv * env,jclass clazz,jobject imageBuffer,jobject histogramBuffer,jint hueBins,jint saturationBins,jint valueBins,jint saturationThreshold,jint valueThreshold)93 void Java_androidx_media_filterpacks_histogram_NewChromaHistogramFilter_extractChromaHistogram(
94 JNIEnv* env, jclass clazz, jobject imageBuffer, jobject histogramBuffer,
95 jint hueBins, jint saturationBins, jint valueBins,
96 jint saturationThreshold, jint valueThreshold) {
97 unsigned char* pixelIn = static_cast<unsigned char*>(env->GetDirectBufferAddress(imageBuffer));
98 float* histOut = static_cast<float*>(env->GetDirectBufferAddress(histogramBuffer));
99 int numPixels = env->GetDirectBufferCapacity(imageBuffer) / 4; // 4 bytes per pixel
100
101 // TODO: add check on the size of histOut
102 for (int i = 0; i < (hueBins * saturationBins + valueBins); ++i) {
103 histOut[i] = 0.0f;
104 }
105
106 for( ; numPixels > 0; --numPixels) {
107 int h = *(pixelIn++);
108 int s = *(pixelIn++);
109 int v = *(pixelIn++);
110
111 pixelIn++;
112 // If a pixel that is either too dark (less than valueThreshold) or colorless
113 // (less than saturationThreshold), if will be put in a 1-D value histogram instead.
114
115 int index;
116 if (s > saturationThreshold && v > valueThreshold) {
117 int sIndex = s * saturationBins / 256;
118
119 // Shifting hue index by 0.5 such that peaks of red, yellow, green, cyan, blue, pink
120 // will be at the center of some bins.
121 int hIndex = ((h * hueBins + 128) / 256) % hueBins;
122 index = sIndex * hueBins + hIndex;
123 } else {
124 index = hueBins * saturationBins + (v * valueBins / 256);
125 }
126 histOut[index] += 1.0f;
127 }
128 }
129