1/*
2 * Copyright 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 */
16package android.hardware.camera2.cts.rs;
17
18import android.graphics.Bitmap;
19import android.graphics.Color;
20import android.renderscript.Allocation;
21import android.renderscript.Element;
22import android.renderscript.RenderScript;
23import android.renderscript.ScriptIntrinsicHistogram;
24
25/**
26 * Utility class providing methods for various pixel-wise ARGB bitmap operations.
27 */
28public class BitmapUtils {
29    private static final String TAG = "BitmapUtils";
30    private static final int COLOR_BIT_DEPTH = 256;
31
32    public static int A = 3;
33    public static int R = 0;
34    public static int G = 1;
35    public static int B = 2;
36    public static int NUM_CHANNELS = 4;
37
38    /**
39     * Return the histograms for each color channel (interleaved).
40     *
41     * @param rs a {@link RenderScript} context to use.
42     * @param bmap a {@link Bitmap} to generate the histograms for.
43     * @return an array containing NUM_CHANNELS * COLOR_BIT_DEPTH histogram bucket values, with
44     * the color channels interleaved.
45     */
46    public static int[] calcHistograms(RenderScript rs, Bitmap bmap) {
47        ScriptIntrinsicHistogram hist = ScriptIntrinsicHistogram.create(rs, Element.U8_4(rs));
48        Allocation sums = Allocation.createSized(rs, Element.I32_4(rs), COLOR_BIT_DEPTH);
49
50        // Setup input allocation (ARGB 8888 bitmap).
51        Allocation input = Allocation.createFromBitmap(rs, bmap);
52
53        hist.setOutput(sums);
54        hist.forEach(input);
55        int[] output = new int[COLOR_BIT_DEPTH * NUM_CHANNELS];
56        sums.copyTo(output);
57        return output;
58    }
59
60    /**
61     * Find the difference between two bitmaps using average of per-pixel differences.
62     *
63     * @param a first {@link android.graphics.Bitmap}.
64     * @param b second {@link android.graphics.Bitmap}.
65     * @return the difference.
66     */
67    public static double calcDifferenceMetric(Bitmap a, Bitmap b) {
68        if (a.getWidth() != b.getWidth() || a.getHeight() != b.getHeight()) {
69            throw new IllegalArgumentException("Bitmap dimensions for arguments do not match a=" +
70                    a.getWidth() + "x" + a.getHeight() + ", b=" + b.getWidth() + "x" +
71                    b.getHeight());
72        }
73        // TODO: Optimize this in renderscript to avoid copy.
74        int[] aPixels = new int[a.getHeight() * a.getWidth()];
75        int[] bPixels = new int[aPixels.length];
76        a.getPixels(aPixels, /*offset*/0, /*stride*/a.getWidth(), /*x*/0, /*y*/0, a.getWidth(),
77                a.getHeight());
78        b.getPixels(bPixels, /*offset*/0, /*stride*/b.getWidth(), /*x*/0, /*y*/0, b.getWidth(),
79                b.getHeight());
80        double diff = 0;
81        for (int i = 0; i < aPixels.length; i++) {
82            int aPix = aPixels[i];
83            int bPix = bPixels[i];
84
85            diff += Math.abs(Color.red(aPix) - Color.red(bPix)); // red
86            diff += Math.abs(Color.green(aPix) - Color.green(bPix)); // green
87            diff += Math.abs(Color.blue(aPix) - Color.blue(bPix)); // blue
88        }
89        diff /= (aPixels.length * 3);
90        return diff;
91    }
92
93}
94