Home | History | Annotate | Download | only in scene1
      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.caps
     17 import its.device
     18 import its.objects
     19 import os.path
     20 import numpy
     21 import matplotlib.pyplot
     22 
     23 # Required for 3d plot to work
     24 import mpl_toolkits.mplot3d
     25 
     26 def main():
     27     """Test that valid data comes back in CaptureResult objects.
     28     """
     29     global NAME, auto_req, manual_req, w_map, h_map
     30     global manual_tonemap, manual_transform, manual_gains, manual_region
     31     global manual_exp_time, manual_sensitivity, manual_gains_ok
     32 
     33     NAME = os.path.basename(__file__).split(".")[0]
     34 
     35     with its.device.ItsSession() as cam:
     36         props = cam.get_camera_properties()
     37         its.caps.skip_unless(its.caps.manual_sensor(props) and
     38                              its.caps.manual_post_proc(props) and
     39                              its.caps.per_frame_control(props))
     40 
     41         manual_tonemap = [0,0, 1,1] # Linear
     42         manual_transform = its.objects.float_to_rational(
     43                 [-1.5,-1.0,-0.5, 0.0,0.5,1.0, 1.5,2.0,3.0])
     44         manual_gains = [1,1.5,2.0,3.0]
     45         manual_region = [{"x":8,"y":8,"width":128,"height":128,"weight":1}]
     46         manual_exp_time = min(props['android.sensor.info.exposureTimeRange'])
     47         manual_sensitivity = min(props['android.sensor.info.sensitivityRange'])
     48 
     49         # The camera HAL may not support different gains for two G channels.
     50         manual_gains_ok = [[1,1.5,2.0,3.0],[1,1.5,1.5,3.0],[1,2.0,2.0,3.0]]
     51 
     52         auto_req = its.objects.auto_capture_request()
     53         auto_req["android.statistics.lensShadingMapMode"] = 1
     54 
     55         manual_req = {
     56             "android.control.mode": 0,
     57             "android.control.aeMode": 0,
     58             "android.control.awbMode": 0,
     59             "android.control.afMode": 0,
     60             "android.sensor.frameDuration": 0,
     61             "android.sensor.sensitivity": manual_sensitivity,
     62             "android.sensor.exposureTime": manual_exp_time,
     63             "android.colorCorrection.mode": 0,
     64             "android.colorCorrection.transform": manual_transform,
     65             "android.colorCorrection.gains": manual_gains,
     66             "android.tonemap.mode": 0,
     67             "android.tonemap.curveRed": manual_tonemap,
     68             "android.tonemap.curveGreen": manual_tonemap,
     69             "android.tonemap.curveBlue": manual_tonemap,
     70             "android.control.aeRegions": manual_region,
     71             "android.control.afRegions": manual_region,
     72             "android.control.awbRegions": manual_region,
     73             "android.statistics.lensShadingMapMode":1
     74             }
     75 
     76         w_map = props["android.lens.info.shadingMapSize"]["width"]
     77         h_map = props["android.lens.info.shadingMapSize"]["height"]
     78 
     79         print "Testing auto capture results"
     80         lsc_map_auto = test_auto(cam, w_map, h_map)
     81         print "Testing manual capture results"
     82         test_manual(cam, w_map, h_map, lsc_map_auto)
     83         print "Testing auto capture results again"
     84         test_auto(cam, w_map, h_map)
     85 
     86 # A very loose definition for two floats being close to each other;
     87 # there may be different interpolation and rounding used to get the
     88 # two values, and all this test is looking at is whether there is
     89 # something obviously broken; it's not looking for a perfect match.
     90 def is_close_float(n1, n2):
     91     return abs(n1 - n2) < 0.05
     92 
     93 def is_close_rational(n1, n2):
     94     return is_close_float(its.objects.rational_to_float(n1),
     95                           its.objects.rational_to_float(n2))
     96 
     97 def draw_lsc_plot(w_map, h_map, lsc_map, name):
     98     for ch in range(4):
     99         fig = matplotlib.pyplot.figure()
    100         ax = fig.gca(projection='3d')
    101         xs = numpy.array([range(w_map)] * h_map).reshape(h_map, w_map)
    102         ys = numpy.array([[i]*w_map for i in range(h_map)]).reshape(
    103                 h_map, w_map)
    104         zs = numpy.array(lsc_map[ch::4]).reshape(h_map, w_map)
    105         ax.plot_wireframe(xs, ys, zs)
    106         matplotlib.pyplot.savefig("%s_plot_lsc_%s_ch%d.png"%(NAME,name,ch))
    107 
    108 def test_auto(cam, w_map, h_map):
    109     # Get 3A lock first, so the auto values in the capture result are
    110     # populated properly.
    111     rect = [[0,0,1,1,1]]
    112     cam.do_3a(rect, rect, rect, do_af=False)
    113 
    114     cap = cam.do_capture(auto_req)
    115     cap_res = cap["metadata"]
    116 
    117     gains = cap_res["android.colorCorrection.gains"]
    118     transform = cap_res["android.colorCorrection.transform"]
    119     exp_time = cap_res['android.sensor.exposureTime']
    120     lsc_map = cap_res["android.statistics.lensShadingMap"]
    121     ctrl_mode = cap_res["android.control.mode"]
    122 
    123     print "Control mode:", ctrl_mode
    124     print "Gains:", gains
    125     print "Transform:", [its.objects.rational_to_float(t)
    126                          for t in transform]
    127     print "AE region:", cap_res['android.control.aeRegions']
    128     print "AF region:", cap_res['android.control.afRegions']
    129     print "AWB region:", cap_res['android.control.awbRegions']
    130     print "LSC map:", w_map, h_map, lsc_map[:8]
    131 
    132     assert(ctrl_mode == 1)
    133 
    134     # Color correction gain and transform must be valid.
    135     assert(len(gains) == 4)
    136     assert(len(transform) == 9)
    137     assert(all([g > 0 for g in gains]))
    138     assert(all([t["denominator"] != 0 for t in transform]))
    139 
    140     # Color correction should not match the manual settings.
    141     assert(any([not is_close_float(gains[i], manual_gains[i])
    142                 for i in xrange(4)]))
    143     assert(any([not is_close_rational(transform[i], manual_transform[i])
    144                 for i in xrange(9)]))
    145 
    146     # Exposure time must be valid.
    147     assert(exp_time > 0)
    148 
    149     # Lens shading map must be valid.
    150     assert(w_map > 0 and h_map > 0 and w_map * h_map * 4 == len(lsc_map))
    151     assert(all([m >= 1 for m in lsc_map]))
    152 
    153     draw_lsc_plot(w_map, h_map, lsc_map, "auto")
    154 
    155     return lsc_map
    156 
    157 def test_manual(cam, w_map, h_map, lsc_map_auto):
    158     cap = cam.do_capture(manual_req)
    159     cap_res = cap["metadata"]
    160 
    161     gains = cap_res["android.colorCorrection.gains"]
    162     transform = cap_res["android.colorCorrection.transform"]
    163     curves = [cap_res["android.tonemap.curveRed"],
    164               cap_res["android.tonemap.curveGreen"],
    165               cap_res["android.tonemap.curveBlue"]]
    166     exp_time = cap_res['android.sensor.exposureTime']
    167     lsc_map = cap_res["android.statistics.lensShadingMap"]
    168     ctrl_mode = cap_res["android.control.mode"]
    169 
    170     print "Control mode:", ctrl_mode
    171     print "Gains:", gains
    172     print "Transform:", [its.objects.rational_to_float(t)
    173                          for t in transform]
    174     print "Tonemap:", curves[0][1::16]
    175     print "AE region:", cap_res['android.control.aeRegions']
    176     print "AF region:", cap_res['android.control.afRegions']
    177     print "AWB region:", cap_res['android.control.awbRegions']
    178     print "LSC map:", w_map, h_map, lsc_map[:8]
    179 
    180     assert(ctrl_mode == 0)
    181 
    182     # Color correction gain and transform must be valid.
    183     # Color correction gains and transform should be the same size and
    184     # values as the manually set values.
    185     assert(len(gains) == 4)
    186     assert(len(transform) == 9)
    187     assert( all([is_close_float(gains[i], manual_gains_ok[0][i])
    188                  for i in xrange(4)]) or
    189             all([is_close_float(gains[i], manual_gains_ok[1][i])
    190                  for i in xrange(4)]) or
    191             all([is_close_float(gains[i], manual_gains_ok[2][i])
    192                  for i in xrange(4)]))
    193     assert(all([is_close_rational(transform[i], manual_transform[i])
    194                 for i in xrange(9)]))
    195 
    196     # Tonemap must be valid.
    197     # The returned tonemap must be linear.
    198     for c in curves:
    199         assert(len(c) > 0)
    200         assert(all([is_close_float(c[i], c[i+1])
    201                     for i in xrange(0,len(c),2)]))
    202 
    203     # Exposure time must be close to the requested exposure time.
    204     assert(is_close_float(exp_time/1000000.0, manual_exp_time/1000000.0))
    205 
    206     # Lens shading map must be valid.
    207     assert(w_map > 0 and h_map > 0 and w_map * h_map * 4 == len(lsc_map))
    208     assert(all([m >= 1 for m in lsc_map]))
    209 
    210     draw_lsc_plot(w_map, h_map, lsc_map, "manual")
    211 
    212 if __name__ == '__main__':
    213     main()
    214 
    215