1/*
2 * Copyright (C) 2013 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
17package android.renderscript;
18
19/**
20 * Intrinsic Histogram filter.
21 *
22 *
23 **/
24public final class ScriptIntrinsicHistogram extends ScriptIntrinsic {
25    private Allocation mOut;
26
27    private ScriptIntrinsicHistogram(long id, RenderScript rs) {
28        super(id, rs);
29    }
30
31    /**
32     * Create an intrinsic for calculating the histogram of an uchar
33     * or uchar4 image.
34     *
35     * Supported elements types are
36     * {@link Element#U8_4}, {@link Element#U8_3},
37     * {@link Element#U8_2}, {@link Element#U8}
38     *
39     * @param rs The RenderScript context
40     * @param e Element type for inputs
41     *
42     * @return ScriptIntrinsicHistogram
43     */
44    public static ScriptIntrinsicHistogram create(RenderScript rs, Element e) {
45        if ((!e.isCompatible(Element.U8_4(rs))) &&
46            (!e.isCompatible(Element.U8_3(rs))) &&
47            (!e.isCompatible(Element.U8_2(rs))) &&
48            (!e.isCompatible(Element.U8(rs)))) {
49            throw new RSIllegalArgumentException("Unsuported element type.");
50        }
51        long id = rs.nScriptIntrinsicCreate(9, e.getID(rs));
52        ScriptIntrinsicHistogram sib = new ScriptIntrinsicHistogram(id, rs);
53        return sib;
54    }
55
56    /**
57     * Process an input buffer and place the histogram into the
58     * output allocation. The output allocation may be a narrower
59     * vector size than the input. In this case the vector size of
60     * the output is used to determine how many of the input
61     * channels are used in the computation. This is useful if you
62     * have an RGBA input buffer but only want the histogram for
63     * RGB.
64     *
65     * 1D and 2D input allocations are supported.
66     *
67     * @param ain The input image
68     */
69    public void forEach(Allocation ain) {
70        forEach(ain, null);
71    }
72
73    /**
74     * Process an input buffer and place the histogram into the
75     * output allocation. The output allocation may be a narrower
76     * vector size than the input. In this case the vector size of
77     * the output is used to determine how many of the input
78     * channels are used in the computation. This is useful if you
79     * have an RGBA input buffer but only want the histogram for
80     * RGB.
81     *
82     * 1D and 2D input allocations are supported.
83     *
84     * @param ain The input image
85     * @param opt LaunchOptions for clipping
86     */
87    public void forEach(Allocation ain, Script.LaunchOptions opt) {
88        if (ain.getType().getElement().getVectorSize() <
89            mOut.getType().getElement().getVectorSize()) {
90
91            throw new RSIllegalArgumentException(
92                "Input vector size must be >= output vector size.");
93        }
94        if (!ain.getType().getElement().isCompatible(Element.U8(mRS)) &&
95            !ain.getType().getElement().isCompatible(Element.U8_2(mRS)) &&
96            !ain.getType().getElement().isCompatible(Element.U8_3(mRS)) &&
97            !ain.getType().getElement().isCompatible(Element.U8_4(mRS))) {
98            throw new RSIllegalArgumentException("Input type must be U8, U8_1, U8_2 or U8_4.");
99        }
100
101        forEach(0, ain, null, null, opt);
102    }
103
104
105
106    /**
107     * Set the coefficients used for the RGBA to Luminocity
108     * calculation. The default is {0.299f, 0.587f, 0.114f, 0.f}.
109     *
110     * Coefficients must be >= 0 and sum to 1.0 or less.
111     *
112     * @param r Red coefficient
113     * @param g Green coefficient
114     * @param b Blue coefficient
115     * @param a Alpha coefficient
116     */
117    public void setDotCoefficients(float r, float g, float b, float a) {
118        if ((r < 0.f) || (g < 0.f) || (b < 0.f) || (a < 0.f)) {
119            throw new RSIllegalArgumentException("Coefficient may not be negative.");
120        }
121        if ((r + g + b + a) > 1.f) {
122            throw new RSIllegalArgumentException("Sum of coefficients must be 1.0 or less.");
123        }
124
125        FieldPacker fp = new FieldPacker(16);
126        fp.addF32(r);
127        fp.addF32(g);
128        fp.addF32(b);
129        fp.addF32(a);
130        setVar(0, fp);
131    }
132
133    /**
134     * Set the output of the histogram.  32 bit integer types are
135     * supported.
136     *
137     * @param aout The output allocation
138     */
139    public void setOutput(Allocation aout) {
140        mOut = aout;
141        if (mOut.getType().getElement() != Element.U32(mRS) &&
142            mOut.getType().getElement() != Element.U32_2(mRS) &&
143            mOut.getType().getElement() != Element.U32_3(mRS) &&
144            mOut.getType().getElement() != Element.U32_4(mRS) &&
145            mOut.getType().getElement() != Element.I32(mRS) &&
146            mOut.getType().getElement() != Element.I32_2(mRS) &&
147            mOut.getType().getElement() != Element.I32_3(mRS) &&
148            mOut.getType().getElement() != Element.I32_4(mRS)) {
149
150            throw new RSIllegalArgumentException("Output type must be U32 or I32.");
151        }
152        if ((mOut.getType().getX() != 256) ||
153            (mOut.getType().getY() != 0) ||
154            mOut.getType().hasMipmaps() ||
155            (mOut.getType().getYuv() != 0)) {
156
157            throw new RSIllegalArgumentException("Output must be 1D, 256 elements.");
158        }
159        setVar(1, aout);
160    }
161
162
163    /**
164     * Process an input buffer and place the histogram into the
165     * output allocation. The dot product of the input channel and
166     * the coefficients from 'setDotCoefficients' are used to
167     * calculate the output values.
168     *
169     * 1D and 2D input allocations are supported.
170     *
171     * @param ain The input image
172     */
173    public void forEach_Dot(Allocation ain) {
174        forEach_Dot(ain, null);
175    }
176
177    /**
178     * Process an input buffer and place the histogram into the
179     * output allocation. The dot product of the input channel and
180     * the coefficients from 'setDotCoefficients' are used to
181     * calculate the output values.
182     *
183     * 1D and 2D input allocations are supported.
184     *
185     * @param ain The input image
186     * @param opt LaunchOptions for clipping
187     */
188    public void forEach_Dot(Allocation ain, Script.LaunchOptions opt) {
189        if (mOut.getType().getElement().getVectorSize() != 1) {
190            throw new RSIllegalArgumentException("Output vector size must be one.");
191        }
192        if (!ain.getType().getElement().isCompatible(Element.U8(mRS)) &&
193            !ain.getType().getElement().isCompatible(Element.U8_2(mRS)) &&
194            !ain.getType().getElement().isCompatible(Element.U8_3(mRS)) &&
195            !ain.getType().getElement().isCompatible(Element.U8_4(mRS))) {
196            throw new RSIllegalArgumentException("Input type must be U8, U8_1, U8_2 or U8_4.");
197        }
198
199        forEach(1, ain, null, null, opt);
200    }
201
202
203
204    /**
205     * Get a KernelID for this intrinsic kernel.
206     *
207     * @return Script.KernelID The KernelID object.
208     */
209    public Script.KernelID getKernelID_Separate() {
210        return createKernelID(0, 3, null, null);
211    }
212
213    /**
214     * Get a FieldID for the input field of this intrinsic.
215     *
216     * @return Script.FieldID The FieldID object.
217     */
218    public Script.FieldID getFieldID_Input() {
219        return createFieldID(1, null);
220    }
221}
222
223