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 "histogram.h" 20227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 21227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks#include <string.h> 22227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks#include <jni.h> 23227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks#include <unistd.h> 24227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks#include <android/log.h> 25227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 26227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks#include "imgprocutil.h" 27227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 28227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksinline void addPixelToHistogram(unsigned char*& pImg, int* pHist, int numBins) { 29227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks int R = *(pImg++); 30227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks int G = *(pImg++); 31227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks int B = *(pImg++); 32227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks ++pImg; 33227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks int i = getIntensityFast(R, G, B); 34227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks int bin = clamp(0, static_cast<int>(static_cast<float>(i * numBins) / 255.0f), numBins - 1); 35227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks ++pHist[bin]; 36227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks} 37227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 38227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksvoid Java_androidx_media_filterpacks_histogram_GrayHistogramFilter_extractHistogram( 39227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks JNIEnv* env, jclass clazz, jobject imageBuffer, jobject maskBuffer, jobject histogramBuffer ) 40227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks{ 41227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks unsigned char* pImg = static_cast<unsigned char*>(env->GetDirectBufferAddress(imageBuffer)); 42227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks int* pHist = static_cast<int*>(env->GetDirectBufferAddress(histogramBuffer)); 43227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks int numPixels = env->GetDirectBufferCapacity(imageBuffer) / 4; // 4 bytes per pixel 44227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks int numBins = env->GetDirectBufferCapacity(histogramBuffer); 45227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 46227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks unsigned char* pMask = NULL; 47227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if(maskBuffer != NULL) { 48227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks pMask = static_cast<unsigned char*>(env->GetDirectBufferAddress(maskBuffer)); 49227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 50227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 51227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks for(int i = 0; i < numBins; ++i) pHist[i] = 0; 52227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 53227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if(pMask == NULL) { 54227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks for( ; numPixels > 0; --numPixels) { 55227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks addPixelToHistogram(pImg, pHist, numBins); 56227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 57227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } else { 58227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks for( ; numPixels > 0; --numPixels) { 59227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if(*pMask == 0){ 60227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks pMask += 4; 61227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks pImg += 4; // Note that otherwise addPixelToHistogram advances pImg by 4 62227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks continue; 63227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 64227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks pMask += 4; 65227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks addPixelToHistogram(pImg, pHist, numBins); 66227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 67227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 68227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks} 69227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 70227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksvoid Java_androidx_media_filterpacks_histogram_ChromaHistogramFilter_extractChromaHistogram( 71227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks JNIEnv* env, jclass clazz, jobject imageBuffer, jobject histogramBuffer, jint hBins, jint sBins) 72227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks{ 73227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks unsigned char* pixelIn = static_cast<unsigned char*>(env->GetDirectBufferAddress(imageBuffer)); 74227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks float* histOut = static_cast<float*>(env->GetDirectBufferAddress(histogramBuffer)); 75227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks int numPixels = env->GetDirectBufferCapacity(imageBuffer) / 4; // 4 bytes per pixel 76227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 77227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks for (int i = 0; i < hBins * sBins; ++i) histOut[i] = 0.0f; 78227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 79227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks int h, s, v; 80227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks float hScaler = hBins / 256.0f; 81227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks float sScaler = sBins / 256.0f; 82227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks for( ; numPixels > 0; --numPixels) { 83227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks h = *(pixelIn++); 84227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks s = *(pixelIn++); 85227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks v = *(pixelIn++); 86227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks pixelIn++; 87227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 88227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks int index = static_cast<int>(s * sScaler) * hBins + static_cast<int>(h * hScaler); 89227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks histOut[index] += 1.0f; 90227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 91227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks} 92227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 93227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricksvoid Java_androidx_media_filterpacks_histogram_NewChromaHistogramFilter_extractChromaHistogram( 94227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks JNIEnv* env, jclass clazz, jobject imageBuffer, jobject histogramBuffer, 95227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks jint hueBins, jint saturationBins, jint valueBins, 96227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks jint saturationThreshold, jint valueThreshold) { 97227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks unsigned char* pixelIn = static_cast<unsigned char*>(env->GetDirectBufferAddress(imageBuffer)); 98227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks float* histOut = static_cast<float*>(env->GetDirectBufferAddress(histogramBuffer)); 99227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks int numPixels = env->GetDirectBufferCapacity(imageBuffer) / 4; // 4 bytes per pixel 100227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 101227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks // TODO: add check on the size of histOut 102227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks for (int i = 0; i < (hueBins * saturationBins + valueBins); ++i) { 103227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks histOut[i] = 0.0f; 104227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 105227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 106227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks for( ; numPixels > 0; --numPixels) { 107227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks int h = *(pixelIn++); 108227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks int s = *(pixelIn++); 109227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks int v = *(pixelIn++); 110227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 111227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks pixelIn++; 112227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks // If a pixel that is either too dark (less than valueThreshold) or colorless 113227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks // (less than saturationThreshold), if will be put in a 1-D value histogram instead. 114227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 115227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks int index; 116227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks if (s > saturationThreshold && v > valueThreshold) { 117227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks int sIndex = s * saturationBins / 256; 118227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks 119227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks // Shifting hue index by 0.5 such that peaks of red, yellow, green, cyan, blue, pink 120227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks // will be at the center of some bins. 121227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks int hIndex = ((h * hueBins + 128) / 256) % hueBins; 122227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks index = sIndex * hueBins + hIndex; 123227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } else { 124227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks index = hueBins * saturationBins + (v * valueBins / 256); 125227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 126227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks histOut[index] += 1.0f; 127227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks } 128227b47625d7482b5b47ad0e4c70ce0a246236adeBenjamin Hendricks} 129