普通文本  |  215行  |  8.2 KB

# Copyright 2013 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import its.image
import its.caps
import its.device
import its.objects
import os.path
import numpy
import matplotlib.pyplot

# Required for 3d plot to work
import mpl_toolkits.mplot3d

def main():
    """Test that valid data comes back in CaptureResult objects.
    """
    global NAME, auto_req, manual_req, w_map, h_map
    global manual_tonemap, manual_transform, manual_gains, manual_region
    global manual_exp_time, manual_sensitivity, manual_gains_ok

    NAME = os.path.basename(__file__).split(".")[0]

    with its.device.ItsSession() as cam:
        props = cam.get_camera_properties()
        if (not its.caps.manual_sensor(props) or
            not its.caps.manual_post_proc(props)):
            print "Test skipped"
            return

        manual_tonemap = [0,0, 1,1] # Linear
        manual_transform = its.objects.int_to_rational([1,2,3, 4,5,6, 7,8,9])
        manual_gains = [1,2,3,4]
        manual_region = [{"x":8,"y":8,"width":128,"height":128,"weight":1}]
        manual_exp_time = min(props['android.sensor.info.exposureTimeRange'])
        manual_sensitivity = min(props['android.sensor.info.sensitivityRange'])

        # The camera HAL may not support different gains for two G channels.
        manual_gains_ok = [[1,2,3,4],[1,2,2,4],[1,3,3,4]]

        auto_req = its.objects.auto_capture_request()
        auto_req["android.statistics.lensShadingMapMode"] = 1

        manual_req = {
            "android.control.mode": 0,
            "android.control.aeMode": 0,
            "android.control.awbMode": 0,
            "android.control.afMode": 0,
            "android.sensor.frameDuration": 0,
            "android.sensor.sensitivity": manual_sensitivity,
            "android.sensor.exposureTime": manual_exp_time,
            "android.colorCorrection.mode": 0,
            "android.colorCorrection.transform": manual_transform,
            "android.colorCorrection.gains": manual_gains,
            "android.tonemap.mode": 0,
            "android.tonemap.curveRed": manual_tonemap,
            "android.tonemap.curveGreen": manual_tonemap,
            "android.tonemap.curveBlue": manual_tonemap,
            "android.control.aeRegions": manual_region,
            "android.control.afRegions": manual_region,
            "android.control.awbRegions": manual_region,
            "android.statistics.lensShadingMapMode":1
            }

        w_map = props["android.lens.info.shadingMapSize"]["width"]
        h_map = props["android.lens.info.shadingMapSize"]["height"]

        print "Testing auto capture results"
        lsc_map_auto = test_auto(cam, w_map, h_map)
        print "Testing manual capture results"
        test_manual(cam, w_map, h_map, lsc_map_auto)
        print "Testing auto capture results again"
        test_auto(cam, w_map, h_map)

# A very loose definition for two floats being close to each other;
# there may be different interpolation and rounding used to get the
# two values, and all this test is looking at is whether there is
# something obviously broken; it's not looking for a perfect match.
def is_close_float(n1, n2):
    return abs(n1 - n2) < 0.05

def is_close_rational(n1, n2):
    return is_close_float(its.objects.rational_to_float(n1),
                          its.objects.rational_to_float(n2))

def draw_lsc_plot(w_map, h_map, lsc_map, name):
    for ch in range(4):
        fig = matplotlib.pyplot.figure()
        ax = fig.gca(projection='3d')
        xs = numpy.array([range(w_map)] * h_map).reshape(h_map, w_map)
        ys = numpy.array([[i]*w_map for i in range(h_map)]).reshape(
                h_map, w_map)
        zs = numpy.array(lsc_map[ch::4]).reshape(h_map, w_map)
        ax.plot_wireframe(xs, ys, zs)
        matplotlib.pyplot.savefig("%s_plot_lsc_%s_ch%d.png"%(NAME,name,ch))

def test_auto(cam, w_map, h_map):
    # Get 3A lock first, so the auto values in the capture result are
    # populated properly.
    rect = [[0,0,1,1,1]]
    cam.do_3a(rect, rect, rect, do_af=False)

    cap = cam.do_capture(auto_req)
    cap_res = cap["metadata"]

    gains = cap_res["android.colorCorrection.gains"]
    transform = cap_res["android.colorCorrection.transform"]
    exp_time = cap_res['android.sensor.exposureTime']
    lsc_map = cap_res["android.statistics.lensShadingMap"]
    ctrl_mode = cap_res["android.control.mode"]

    print "Control mode:", ctrl_mode
    print "Gains:", gains
    print "Transform:", [its.objects.rational_to_float(t)
                         for t in transform]
    print "AE region:", cap_res['android.control.aeRegions']
    print "AF region:", cap_res['android.control.afRegions']
    print "AWB region:", cap_res['android.control.awbRegions']
    print "LSC map:", w_map, h_map, lsc_map[:8]

    assert(ctrl_mode == 1)

    # Color correction gain and transform must be valid.
    assert(len(gains) == 4)
    assert(len(transform) == 9)
    assert(all([g > 0 for g in gains]))
    assert(all([t["denominator"] != 0 for t in transform]))

    # Color correction should not match the manual settings.
    assert(any([not is_close_float(gains[i], manual_gains[i])
                for i in xrange(4)]))
    assert(any([not is_close_rational(transform[i], manual_transform[i])
                for i in xrange(9)]))

    # Exposure time must be valid.
    assert(exp_time > 0)

    # Lens shading map must be valid.
    assert(w_map > 0 and h_map > 0 and w_map * h_map * 4 == len(lsc_map))
    assert(all([m >= 1 for m in lsc_map]))

    draw_lsc_plot(w_map, h_map, lsc_map, "auto")

    return lsc_map

def test_manual(cam, w_map, h_map, lsc_map_auto):
    cap = cam.do_capture(manual_req)
    cap_res = cap["metadata"]

    gains = cap_res["android.colorCorrection.gains"]
    transform = cap_res["android.colorCorrection.transform"]
    curves = [cap_res["android.tonemap.curveRed"],
              cap_res["android.tonemap.curveGreen"],
              cap_res["android.tonemap.curveBlue"]]
    exp_time = cap_res['android.sensor.exposureTime']
    lsc_map = cap_res["android.statistics.lensShadingMap"]
    ctrl_mode = cap_res["android.control.mode"]

    print "Control mode:", ctrl_mode
    print "Gains:", gains
    print "Transform:", [its.objects.rational_to_float(t)
                         for t in transform]
    print "Tonemap:", curves[0][1::16]
    print "AE region:", cap_res['android.control.aeRegions']
    print "AF region:", cap_res['android.control.afRegions']
    print "AWB region:", cap_res['android.control.awbRegions']
    print "LSC map:", w_map, h_map, lsc_map[:8]

    assert(ctrl_mode == 0)

    # Color correction gain and transform must be valid.
    # Color correction gains and transform should be the same size and
    # values as the manually set values.
    assert(len(gains) == 4)
    assert(len(transform) == 9)
    assert( all([is_close_float(gains[i], manual_gains_ok[0][i])
                 for i in xrange(4)]) or
            all([is_close_float(gains[i], manual_gains_ok[1][i])
                 for i in xrange(4)]) or
            all([is_close_float(gains[i], manual_gains_ok[2][i])
                 for i in xrange(4)]))
    assert(all([is_close_rational(transform[i], manual_transform[i])
                for i in xrange(9)]))

    # Tonemap must be valid.
    # The returned tonemap must be linear.
    for c in curves:
        assert(len(c) > 0)
        assert(all([is_close_float(c[i], c[i+1])
                    for i in xrange(0,len(c),2)]))

    # Exposure time must be close to the requested exposure time.
    assert(is_close_float(exp_time/1000000.0, manual_exp_time/1000000.0))

    # Lens shading map must be valid.
    assert(w_map > 0 and h_map > 0 and w_map * h_map * 4 == len(lsc_map))
    assert(all([m >= 1 for m in lsc_map]))

    draw_lsc_plot(w_map, h_map, lsc_map, "manual")

if __name__ == '__main__':
    main()