Home | History | Annotate | Download | only in tests
      1 # Copyright 2013 The Android Open Source Project
      2 #
      3 # Licensed under the Apache License, Version 2.0 (the "License");
      4 # you may not use this file except in compliance with the License.
      5 # You may obtain a copy of the License at
      6 #
      7 #      http://www.apache.org/licenses/LICENSE-2.0
      8 #
      9 # Unless required by applicable law or agreed to in writing, software
     10 # distributed under the License is distributed on an "AS IS" BASIS,
     11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 # See the License for the specific language governing permissions and
     13 # limitations under the License.
     14 
     15 import its.image
     16 import its.device
     17 import its.objects
     18 import os.path
     19 import pprint
     20 import math
     21 import numpy
     22 import matplotlib.pyplot
     23 import mpl_toolkits.mplot3d
     24 
     25 def main():
     26     """Test that valid data comes back in CaptureResult objects.
     27     """
     28     NAME = os.path.basename(__file__).split(".")[0]
     29 
     30     manual_tonemap = [0,0, 1,1] # Linear
     31     manual_transform = its.objects.int_to_rational([1,2,3, 4,5,6, 7,8,9])
     32     manual_gains = [1,2,3,4]
     33     manual_region = [8,8,128,128]
     34     manual_exp_time = 100*1000*1000
     35     manual_sensitivity = 100
     36 
     37     auto_req = its.objects.auto_capture_request()
     38     auto_req["android.statistics.lensShadingMapMode"] = 1
     39 
     40     manual_req = {
     41         "android.control.mode": 0,
     42         "android.control.aeMode": 0,
     43         "android.control.awbMode": 0,
     44         "android.control.afMode": 0,
     45         "android.sensor.frameDuration": 0,
     46         "android.sensor.sensitivity": manual_sensitivity,
     47         "android.sensor.exposureTime": manual_exp_time,
     48         "android.colorCorrection.mode": 0,
     49         "android.colorCorrection.transform": manual_transform,
     50         "android.colorCorrection.gains": manual_gains,
     51         "android.tonemap.mode": 0,
     52         "android.tonemap.curveRed": manual_tonemap,
     53         "android.tonemap.curveGreen": manual_tonemap,
     54         "android.tonemap.curveBlue": manual_tonemap,
     55         "android.control.aeRegions": manual_region,
     56         "android.control.afRegions": manual_region,
     57         "android.control.awbRegions": manual_region,
     58         "android.statistics.lensShadingMapMode":1
     59         }
     60 
     61     def r2f(r):
     62         return float(r["numerator"]) / float(r["denominator"])
     63 
     64     # A very loose definition for two floats being close to each other;
     65     # there may be different interpolation and rounding used to get the
     66     # two values, and all this test is looking at is whether there is
     67     # something obviously broken; it's not looking for a perfect match.
     68     def is_close_float(n1, n2):
     69         return abs(n1 - n2) < 0.05
     70 
     71     def is_close_rational(n1, n2):
     72         return is_close_float(r2f(n1), r2f(n2))
     73 
     74     def draw_lsc_plot(w_map, h_map, lsc_map, name):
     75         fig = matplotlib.pyplot.figure()
     76         ax = fig.gca(projection='3d')
     77         xs = numpy.array([range(h_map)] * w_map).reshape(w_map, h_map)
     78         ys = numpy.array([[i]*h_map for i in range(w_map)]).reshape(w_map, h_map)
     79         for ch in range(4):
     80             size = w_map*h_map
     81             start = ch * size
     82             zs = numpy.array(lsc_map[start:start+size]).reshape(w_map, h_map)
     83             ax.plot_wireframe(xs, ys, zs)
     84         matplotlib.pyplot.savefig("%s_plot_lsc_%s.png" % (NAME, name))
     85 
     86     def test_auto(cam, w_map, h_map):
     87         # Get 3A lock first, so the auto values in the capture result are
     88         # populated properly.
     89         rect = [0,0,1,1]
     90         cam.do_3a(rect, rect, rect, True, True, False)
     91 
     92         cap = cam.do_capture(auto_req)
     93         cap_res = cap["metadata"]
     94 
     95         gains = cap_res["android.colorCorrection.gains"]
     96         transform = cap_res["android.colorCorrection.transform"]
     97         exp_time = cap_res['android.sensor.exposureTime']
     98         lsc_map = cap_res["android.statistics.lensShadingMap"]
     99         ctrl_mode = cap_res["android.control.mode"]
    100 
    101         print "Control mode:", ctrl_mode
    102         print "Gains:", gains
    103         print "Transform:", [r2f(t) for t in transform]
    104         print "AE region:", cap_res['android.control.aeRegions']
    105         print "AF region:", cap_res['android.control.afRegions']
    106         print "AWB region:", cap_res['android.control.awbRegions']
    107         print "LSC map:", w_map, h_map, lsc_map[:8]
    108 
    109         assert(ctrl_mode == 1)
    110 
    111         # Color correction gain and transform must be valid.
    112         assert(len(gains) == 4)
    113         assert(len(transform) == 9)
    114         assert(all([g > 0 for g in gains]))
    115         assert(all([t["denominator"] != 0 for t in transform]))
    116 
    117         # Color correction should not match the manual settings.
    118         assert(any([not is_close_float(gains[i], manual_gains[i])
    119                     for i in xrange(4)]))
    120         assert(any([not is_close_rational(transform[i], manual_transform[i])
    121                     for i in xrange(9)]))
    122 
    123         # Exposure time must be valid.
    124         assert(exp_time > 0)
    125 
    126         # 3A regions must be valid.
    127         assert(len(cap_res['android.control.aeRegions']) == 5)
    128         assert(len(cap_res['android.control.afRegions']) == 5)
    129         assert(len(cap_res['android.control.awbRegions']) == 5)
    130 
    131         # Lens shading map must be valid.
    132         assert(w_map > 0 and h_map > 0 and w_map * h_map * 4 == len(lsc_map))
    133         assert(all([m >= 1 for m in lsc_map]))
    134 
    135         draw_lsc_plot(w_map, h_map, lsc_map, "auto")
    136 
    137         return lsc_map
    138 
    139     def test_manual(cam, w_map, h_map, lsc_map_auto):
    140         cap = cam.do_capture(auto_req)
    141         cap_res = cap["metadata"]
    142 
    143         gains = cap_res["android.colorCorrection.gains"]
    144         transform = cap_res["android.colorCorrection.transform"]
    145         curves = [cap_res["android.tonemap.curveRed"],
    146                   cap_res["android.tonemap.curveGreen"],
    147                   cap_res["android.tonemap.curveBlue"]]
    148         exp_time = cap_res['android.sensor.exposureTime']
    149         lsc_map = cap_res["android.statistics.lensShadingMap"]
    150         ctrl_mode = cap_res["android.control.mode"]
    151 
    152         print "Control mode:", ctrl_mode
    153         print "Gains:", gains
    154         print "Transform:", [r2f(t) for t in transform]
    155         print "Tonemap:", curves[0][1::16]
    156         print "AE region:", cap_res['android.control.aeRegions']
    157         print "AF region:", cap_res['android.control.afRegions']
    158         print "AWB region:", cap_res['android.control.awbRegions']
    159         print "LSC map:", w_map, h_map, lsc_map[:8]
    160 
    161         assert(ctrl_mode == 0)
    162 
    163         # Color correction gain and transform must be valid.
    164         # Color correction gains and transform should be the same size and
    165         # values as the manually set values.
    166         assert(len(gains) == 4)
    167         assert(len(transform) == 9)
    168         assert(all([is_close_float(gains[i], manual_gains[i])
    169                     for i in xrange(4)]))
    170         assert(all([is_close_rational(transform[i], manual_transform[i])
    171                     for i in xrange(9)]))
    172 
    173         # Tonemap must be valid.
    174         # The returned tonemap must be linear.
    175         for c in curves:
    176             assert(len(c) > 0)
    177             assert(all([is_close_float(c[i], c[i+1])
    178                         for i in xrange(0,len(c),2)]))
    179 
    180         # Exposure time must be close to the requested exposure time.
    181         assert(is_close_float(exp_time/1000000.0, manual_exp_time/1000000.0))
    182 
    183         # 3A regions must be valid. They don't need to actually match what was
    184         # requesed, since the SOC may not support those regions exactly.
    185         assert(len(cap_res['android.control.aeRegions']) == 5)
    186         assert(len(cap_res['android.control.afRegions']) == 5)
    187         assert(len(cap_res['android.control.awbRegions']) == 5)
    188 
    189         # Lens shading map must be valid.
    190         assert(w_map > 0 and h_map > 0 and w_map * h_map * 4 == len(lsc_map))
    191         assert(all([m >= 1 for m in lsc_map]))
    192 
    193         # Lens shading map must take into account the manual color correction
    194         # settings. Test this by ensuring that the map is different between
    195         # the auto and manual test cases.
    196         assert(lsc_map != lsc_map_auto)
    197 
    198         draw_lsc_plot(w_map, h_map, lsc_map, "manual")
    199 
    200     with its.device.ItsSession() as cam:
    201         props = cam.get_camera_properties()
    202         w_map = props["android.lens.info.shadingMapSize"]["width"]
    203         h_map = props["android.lens.info.shadingMapSize"]["height"]
    204 
    205         print "Testing auto capture results"
    206         lsc_map_auto = test_auto(cam, w_map, h_map)
    207         print "Testing manual capture results"
    208         test_manual(cam, w_map, h_map, lsc_map_auto)
    209         print "Testing auto capture results again"
    210         test_auto(cam, w_map, h_map)
    211 
    212 if __name__ == '__main__':
    213     main()
    214 
    215