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