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