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// Extract histogram from image.
18
19package androidx.media.filterpacks.histogram;
20
21import androidx.media.filterfw.Filter;
22import androidx.media.filterfw.Frame;
23import androidx.media.filterfw.FrameBuffer2D;
24import androidx.media.filterfw.FrameType;
25import androidx.media.filterfw.InputPort;
26import androidx.media.filterfw.MffContext;
27import androidx.media.filterfw.OutputPort;
28import androidx.media.filterfw.Signature;
29
30import java.nio.ByteBuffer;
31import java.nio.ByteOrder;
32import java.nio.FloatBuffer;
33
34/**
35 * ChromaHistogramFilter takes in an image in HSVA format and computes a 2-D histogram with a
36 * 2 dimensional chroma histogram based on hue (column) and saturation (row) at the top and
37 * a 1-D value histogram in the last row. The number of bin in the value histogram equals to
38 * the number of bins in hue.
39 */
40public final class NewChromaHistogramFilter extends Filter {
41
42    private int mHueBins = 6;
43    private int mSaturationBins = 3;
44    private int mValueBins;
45
46    private int mSaturationThreshold = 26; // 255 * 0.1
47    private int mValueThreshold = 51; // 255 * 0.2
48
49    public NewChromaHistogramFilter(MffContext context, String name) {
50        super(context, name);
51    }
52
53    @Override
54    public Signature getSignature() {
55        FrameType imageIn = FrameType.image2D(FrameType.ELEMENT_RGBA8888, FrameType.READ_CPU);
56        FrameType dataOut = FrameType.buffer2D(FrameType.ELEMENT_FLOAT32);
57
58        return new Signature()
59            .addInputPort("image", Signature.PORT_REQUIRED, imageIn)
60            .addInputPort("huebins", Signature.PORT_OPTIONAL, FrameType.single(int.class))
61            .addInputPort("saturationbins", Signature.PORT_OPTIONAL, FrameType.single(int.class))
62            .addInputPort("saturationthreshold", Signature.PORT_OPTIONAL,
63                    FrameType.single(int.class))
64            .addInputPort("valuethreshold", Signature.PORT_OPTIONAL, FrameType.single(int.class))
65            .addOutputPort("histogram", Signature.PORT_REQUIRED, dataOut)
66            .disallowOtherPorts();
67    }
68
69    @Override
70    public void onInputPortOpen(InputPort port) {
71        if (port.getName().equals("huebins")) {
72            port.bindToFieldNamed("mHueBins");
73            port.setAutoPullEnabled(true);
74        } else if (port.getName().equals("saturationbins")) {
75            port.bindToFieldNamed("mSaturationBins");
76            port.setAutoPullEnabled(true);
77        } else if (port.getName().equals("saturationthreshold")) {
78            port.bindToFieldNamed("mSaturationThreshold");
79            port.setAutoPullEnabled(true);
80        } else if (port.getName().equals("valuethreshold")) {
81            port.bindToFieldNamed("mValueThreshold");
82            port.setAutoPullEnabled(true);
83        }
84    }
85
86    @Override
87    protected void onProcess() {
88        FrameBuffer2D imageFrame = getConnectedInputPort("image").pullFrame().asFrameImage2D();
89        OutputPort outPort = getConnectedOutputPort("histogram");
90
91        mValueBins = mHueBins;
92        int[] outDims = new int[] {mHueBins, mSaturationBins + 1};
93        FrameBuffer2D histogramFrame = outPort.fetchAvailableFrame(outDims).asFrameBuffer2D();
94
95        ByteBuffer imageBuffer  = imageFrame.lockBytes(Frame.MODE_READ);
96        ByteBuffer histogramBuffer = histogramFrame.lockBytes(Frame.MODE_READ);
97        histogramBuffer.order(ByteOrder.nativeOrder());
98        FloatBuffer floatHistogram = histogramBuffer.asFloatBuffer();
99
100        // Run native method
101        extractChromaHistogram(imageBuffer, floatHistogram, mHueBins, mSaturationBins, mValueBins,
102                mSaturationThreshold, mValueThreshold);
103
104        imageFrame.unlock();
105        histogramFrame.unlock();
106
107        outPort.pushFrame(histogramFrame);
108    }
109
110    private static native void extractChromaHistogram(ByteBuffer imageBuffer,
111            FloatBuffer histogramBuffer, int hueBins, int saturationBins, int valueBins,
112            int saturationThreshold, int valueThreshold);
113
114    static {
115        System.loadLibrary("smartcamera_jni");
116    }
117}
118