15d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)/* 22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Copyright (C) 2012 The Android Open Source Project 32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * 42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Licensed under the Apache License, Version 2.0 (the "License"); 55d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * you may not use this file except in compliance with the License. 62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * You may obtain a copy of the License at 7868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) * 82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * http://www.apache.org/licenses/LICENSE-2.0 92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * 102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * Unless required by applicable law or agreed to in writing, software 112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * distributed under the License is distributed on an "AS IS" BASIS, 12effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * See the License for the specific language governing permissions and 142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * limitations under the License. 152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */ 162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Extract histogram from image. 182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)package androidx.media.filterpacks.histogram; 202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import androidx.media.filterfw.Filter; 222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import androidx.media.filterfw.Frame; 234e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)import androidx.media.filterfw.FrameBuffer2D; 242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import androidx.media.filterfw.FrameType; 252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import androidx.media.filterfw.InputPort; 264e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)import androidx.media.filterfw.MffContext; 272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import androidx.media.filterfw.OutputPort; 282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import androidx.media.filterfw.Signature; 292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import java.nio.ByteBuffer; 312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import java.nio.ByteOrder; 322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)import java.nio.FloatBuffer; 332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)/** 354e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) * ChromaHistogramFilter takes in an image in HSVA format and computes a 2-D histogram with a 362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) * 2 dimensional chroma histogram based on hue (column) and saturation (row) at the top and 375d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * a 1-D value histogram in the last row. The number of bin in the value histogram equals to 385d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) * the number of bins in hue. 392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) */ 40effb81e5f8246d0db0270817048dc992db66e9fbBen Murdochpublic final class NewChromaHistogramFilter extends Filter { 41effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch 42effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch private int mHueBins = 6; 434e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) private int mSaturationBins = 3; 444e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) private int mValueBins; 454e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) 464e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) private int mSaturationThreshold = 26; // 255 * 0.1 474e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) private int mValueThreshold = 51; // 255 * 0.2 485d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 495d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) public NewChromaHistogramFilter(MffContext context, String name) { 502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) super(context, name); 515d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 5323730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) @Override 54effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch public Signature getSignature() { 55a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) FrameType imageIn = FrameType.image2D(FrameType.ELEMENT_RGBA8888, FrameType.READ_CPU); 56effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch FrameType dataOut = FrameType.buffer2D(FrameType.ELEMENT_FLOAT32); 575d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 585d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) return new Signature() 595d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) .addInputPort("image", Signature.PORT_REQUIRED, imageIn) 605d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) .addInputPort("huebins", Signature.PORT_OPTIONAL, FrameType.single(int.class)) 6123730a6e56a168d1879203e4b3819bb36e3d8f1fTorne (Richard Coles) .addInputPort("saturationbins", Signature.PORT_OPTIONAL, FrameType.single(int.class)) 62effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch .addInputPort("saturationthreshold", Signature.PORT_OPTIONAL, 63a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles) FrameType.single(int.class)) 64effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch .addInputPort("valuethreshold", Signature.PORT_OPTIONAL, FrameType.single(int.class)) 654e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) .addOutputPort("histogram", Signature.PORT_REQUIRED, dataOut) 665d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) .disallowOtherPorts(); 674e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles) } 682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 69effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch @Override 702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) public void onInputPortOpen(InputPort port) { 712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (port.getName().equals("huebins")) { 725d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) port.bindToFieldNamed("mHueBins"); 735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) port.setAutoPullEnabled(true); 742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else if (port.getName().equals("saturationbins")) { 755d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) port.bindToFieldNamed("mSaturationBins"); 765d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) port.setAutoPullEnabled(true); 772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else if (port.getName().equals("saturationthreshold")) { 785d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) port.bindToFieldNamed("mSaturationThreshold"); 795d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) port.setAutoPullEnabled(true); 802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else if (port.getName().equals("valuethreshold")) { 812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) port.bindToFieldNamed("mValueThreshold"); 822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) port.setAutoPullEnabled(true); 832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 855d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 865d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) @Override 872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) protected void onProcess() { 885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) FrameBuffer2D imageFrame = getConnectedInputPort("image").pullFrame().asFrameImage2D(); 895d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) OutputPort outPort = getConnectedOutputPort("histogram"); 902a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 915d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) mValueBins = mHueBins; 925d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) int[] outDims = new int[] {mHueBins, mSaturationBins + 1}; 932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FrameBuffer2D histogramFrame = outPort.fetchAvailableFrame(outDims).asFrameBuffer2D(); 945d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) 955d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) ByteBuffer imageBuffer = imageFrame.lockBytes(Frame.MODE_READ); 962a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) ByteBuffer histogramBuffer = histogramFrame.lockBytes(Frame.MODE_READ); 972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) histogramBuffer.order(ByteOrder.nativeOrder()); 982a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FloatBuffer floatHistogram = histogramBuffer.asFloatBuffer(); 992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // Run native method 1015d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) extractChromaHistogram(imageBuffer, floatHistogram, mHueBins, mSaturationBins, mValueBins, 1025d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) mSaturationThreshold, mValueThreshold); 1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1045d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) imageFrame.unlock(); 1055d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) histogramFrame.unlock(); 1062a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1075d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) outPort.pushFrame(histogramFrame); 1085d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) } 1092a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) private static native void extractChromaHistogram(ByteBuffer imageBuffer, 1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FloatBuffer histogramBuffer, int hueBins, int saturationBins, int valueBins, 1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) int saturationThreshold, int valueThreshold); 1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1145d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) static { 1155d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) System.loadLibrary("smartcamera_jni"); 1162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1175d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)} 1185d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)