| /* |
| * Copyright (C) 2012 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| // Native function to extract histogram from image (handed down as ByteBuffer). |
| |
| #include "histogram.h" |
| |
| #include <string.h> |
| #include <jni.h> |
| #include <unistd.h> |
| #include <android/log.h> |
| |
| #include "imgprocutil.h" |
| |
| inline void addPixelToHistogram(unsigned char*& pImg, int* pHist, int numBins) { |
| int R = *(pImg++); |
| int G = *(pImg++); |
| int B = *(pImg++); |
| ++pImg; |
| int i = getIntensityFast(R, G, B); |
| int bin = clamp(0, static_cast<int>(static_cast<float>(i * numBins) / 255.0f), numBins - 1); |
| ++pHist[bin]; |
| } |
| |
| void Java_androidx_media_filterpacks_histogram_GrayHistogramFilter_extractHistogram( |
| JNIEnv* env, jclass clazz, jobject imageBuffer, jobject maskBuffer, jobject histogramBuffer ) |
| { |
| unsigned char* pImg = static_cast<unsigned char*>(env->GetDirectBufferAddress(imageBuffer)); |
| int* pHist = static_cast<int*>(env->GetDirectBufferAddress(histogramBuffer)); |
| int numPixels = env->GetDirectBufferCapacity(imageBuffer) / 4; // 4 bytes per pixel |
| int numBins = env->GetDirectBufferCapacity(histogramBuffer); |
| |
| unsigned char* pMask = NULL; |
| if(maskBuffer != NULL) { |
| pMask = static_cast<unsigned char*>(env->GetDirectBufferAddress(maskBuffer)); |
| } |
| |
| for(int i = 0; i < numBins; ++i) pHist[i] = 0; |
| |
| if(pMask == NULL) { |
| for( ; numPixels > 0; --numPixels) { |
| addPixelToHistogram(pImg, pHist, numBins); |
| } |
| } else { |
| for( ; numPixels > 0; --numPixels) { |
| if(*pMask == 0){ |
| pMask += 4; |
| pImg += 4; // Note that otherwise addPixelToHistogram advances pImg by 4 |
| continue; |
| } |
| pMask += 4; |
| addPixelToHistogram(pImg, pHist, numBins); |
| } |
| } |
| } |
| |
| void Java_androidx_media_filterpacks_histogram_ChromaHistogramFilter_extractChromaHistogram( |
| JNIEnv* env, jclass clazz, jobject imageBuffer, jobject histogramBuffer, jint hBins, jint sBins) |
| { |
| unsigned char* pixelIn = static_cast<unsigned char*>(env->GetDirectBufferAddress(imageBuffer)); |
| float* histOut = static_cast<float*>(env->GetDirectBufferAddress(histogramBuffer)); |
| int numPixels = env->GetDirectBufferCapacity(imageBuffer) / 4; // 4 bytes per pixel |
| |
| for (int i = 0; i < hBins * sBins; ++i) histOut[i] = 0.0f; |
| |
| int h, s, v; |
| float hScaler = hBins / 256.0f; |
| float sScaler = sBins / 256.0f; |
| for( ; numPixels > 0; --numPixels) { |
| h = *(pixelIn++); |
| s = *(pixelIn++); |
| v = *(pixelIn++); |
| pixelIn++; |
| |
| int index = static_cast<int>(s * sScaler) * hBins + static_cast<int>(h * hScaler); |
| histOut[index] += 1.0f; |
| } |
| } |
| |
| void 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) { |
| unsigned char* pixelIn = static_cast<unsigned char*>(env->GetDirectBufferAddress(imageBuffer)); |
| float* histOut = static_cast<float*>(env->GetDirectBufferAddress(histogramBuffer)); |
| int numPixels = env->GetDirectBufferCapacity(imageBuffer) / 4; // 4 bytes per pixel |
| |
| // TODO: add check on the size of histOut |
| for (int i = 0; i < (hueBins * saturationBins + valueBins); ++i) { |
| histOut[i] = 0.0f; |
| } |
| |
| for( ; numPixels > 0; --numPixels) { |
| int h = *(pixelIn++); |
| int s = *(pixelIn++); |
| int v = *(pixelIn++); |
| |
| pixelIn++; |
| // If a pixel that is either too dark (less than valueThreshold) or colorless |
| // (less than saturationThreshold), if will be put in a 1-D value histogram instead. |
| |
| int index; |
| if (s > saturationThreshold && v > valueThreshold) { |
| int sIndex = s * saturationBins / 256; |
| |
| // Shifting hue index by 0.5 such that peaks of red, yellow, green, cyan, blue, pink |
| // will be at the center of some bins. |
| int hIndex = ((h * hueBins + 128) / 256) % hueBins; |
| index = sIndex * hueBins + hIndex; |
| } else { |
| index = hueBins * saturationBins + (v * valueBins / 256); |
| } |
| histOut[index] += 1.0f; |
| } |
| } |