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.sensitivity": manual_sensitivity,
     61             "android.sensor.exposureTime": manual_exp_time,
     62             "android.colorCorrection.mode": 0,
     63             "android.colorCorrection.transform": manual_transform,
     64             "android.colorCorrection.gains": manual_gains,
     65             "android.tonemap.mode": 0,
     66             "android.tonemap.curve": {"red": manual_tonemap,
     67                                       "green": manual_tonemap,
     68                                       "blue": manual_tonemap},
     69             "android.control.aeRegions": manual_region,
     70             "android.control.afRegions": manual_region,
     71             "android.control.awbRegions": manual_region,
     72             "android.statistics.lensShadingMapMode":1
     73             }
     74 
     75         print "Testing auto capture results"
     76         lsc_map_auto = test_auto(cam, props)
     77         print "Testing manual capture results"
     78         test_manual(cam, lsc_map_auto, props)
     79         print "Testing auto capture results again"
     80         test_auto(cam, props)
     81 
     82 # A very loose definition for two floats being close to each other;
     83 # there may be different interpolation and rounding used to get the
     84 # two values, and all this test is looking at is whether there is
     85 # something obviously broken; it's not looking for a perfect match.
     86 def is_close_float(n1, n2):
     87     return abs(n1 - n2) < 0.05
     88 
     89 def is_close_rational(n1, n2):
     90     return is_close_float(its.objects.rational_to_float(n1),
     91                           its.objects.rational_to_float(n2))
     92 
     93 def draw_lsc_plot(w_map, h_map, lsc_map, name):
     94     for ch in range(4):
     95         fig = matplotlib.pyplot.figure()
     96         ax = fig.gca(projection='3d')
     97         xs = numpy.array([range(w_map)] * h_map).reshape(h_map, w_map)
     98         ys = numpy.array([[i]*w_map for i in range(h_map)]).reshape(
     99                 h_map, w_map)
    100         zs = numpy.array(lsc_map[ch::4]).reshape(h_map, w_map)
    101         ax.plot_wireframe(xs, ys, zs)
    102         matplotlib.pyplot.savefig("%s_plot_lsc_%s_ch%d.png"%(NAME,name,ch))
    103 
    104 def test_auto(cam, props):
    105     # Get 3A lock first, so the auto values in the capture result are
    106     # populated properly.
    107     rect = [[0,0,1,1,1]]
    108     mono_camera = its.caps.mono_camera(props)
    109     cam.do_3a(rect, rect, rect, do_af=False, mono_camera=mono_camera)
    110 
    111     cap = cam.do_capture(auto_req)
    112     cap_res = cap["metadata"]
    113 
    114     gains = cap_res["android.colorCorrection.gains"]
    115     transform = cap_res["android.colorCorrection.transform"]
    116     exp_time = cap_res['android.sensor.exposureTime']
    117     lsc_obj = cap_res["android.statistics.lensShadingCorrectionMap"]
    118     lsc_map = lsc_obj["map"]
    119     w_map = lsc_obj["width"]
    120     h_map = lsc_obj["height"]
    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     if props["android.control.maxRegionsAe"] > 0:
    128         print "AE region:", cap_res['android.control.aeRegions']
    129     if props["android.control.maxRegionsAf"] > 0:
    130         print "AF region:", cap_res['android.control.afRegions']
    131     if props["android.control.maxRegionsAwb"] > 0:
    132         print "AWB region:", cap_res['android.control.awbRegions']
    133     print "LSC map:", w_map, h_map, lsc_map[:8]
    134 
    135     assert(ctrl_mode == 1)
    136 
    137     # Color correction gain and transform must be valid.
    138     assert(len(gains) == 4)
    139     assert(len(transform) == 9)
    140     assert(all([g > 0 for g in gains]))
    141     assert(all([t["denominator"] != 0 for t in transform]))
    142 
    143     # Color correction should not match the manual settings.
    144     assert(any([not is_close_float(gains[i], manual_gains[i])
    145                 for i in xrange(4)]))
    146     assert(any([not is_close_rational(transform[i], manual_transform[i])
    147                 for i in xrange(9)]))
    148 
    149     # Exposure time must be valid.
    150     assert(exp_time > 0)
    151 
    152     # Lens shading map must be valid.
    153     assert(w_map > 0 and h_map > 0 and w_map * h_map * 4 == len(lsc_map))
    154     assert(all([m >= 1 for m in lsc_map]))
    155 
    156     draw_lsc_plot(w_map, h_map, lsc_map, "auto")
    157 
    158     return lsc_map
    159 
    160 def test_manual(cam, lsc_map_auto, props):
    161     cap = cam.do_capture(manual_req)
    162     cap_res = cap["metadata"]
    163 
    164     gains = cap_res["android.colorCorrection.gains"]
    165     transform = cap_res["android.colorCorrection.transform"]
    166     curves = [cap_res["android.tonemap.curve"]["red"],
    167               cap_res["android.tonemap.curve"]["green"],
    168               cap_res["android.tonemap.curve"]["blue"]]
    169     exp_time = cap_res['android.sensor.exposureTime']
    170     lsc_obj = cap_res["android.statistics.lensShadingCorrectionMap"]
    171     lsc_map = lsc_obj["map"]
    172     w_map = lsc_obj["width"]
    173     h_map = lsc_obj["height"]
    174     ctrl_mode = cap_res["android.control.mode"]
    175 
    176     print "Control mode:", ctrl_mode
    177     print "Gains:", gains
    178     print "Transform:", [its.objects.rational_to_float(t)
    179                          for t in transform]
    180     print "Tonemap:", curves[0][1::16]
    181     if props["android.control.maxRegionsAe"] > 0:
    182         print "AE region:", cap_res['android.control.aeRegions']
    183     if props["android.control.maxRegionsAf"] > 0:
    184         print "AF region:", cap_res['android.control.afRegions']
    185     if props["android.control.maxRegionsAwb"] > 0:
    186         print "AWB region:", cap_res['android.control.awbRegions']
    187     print "LSC map:", w_map, h_map, lsc_map[:8]
    188 
    189     assert(ctrl_mode == 0)
    190 
    191     # Color correction gain and transform must be valid.
    192     # Color correction gains and transform should be the same size and
    193     # values as the manually set values.
    194     assert(len(gains) == 4)
    195     assert(len(transform) == 9)
    196     assert( all([is_close_float(gains[i], manual_gains_ok[0][i])
    197                  for i in xrange(4)]) or
    198             all([is_close_float(gains[i], manual_gains_ok[1][i])
    199                  for i in xrange(4)]) or
    200             all([is_close_float(gains[i], manual_gains_ok[2][i])
    201                  for i in xrange(4)]))
    202     assert(all([is_close_rational(transform[i], manual_transform[i])
    203                 for i in xrange(9)]))
    204 
    205     # Tonemap must be valid.
    206     # The returned tonemap must be linear.
    207     for c in curves:
    208         assert(len(c) > 0)
    209         assert(all([is_close_float(c[i], c[i+1])
    210                     for i in xrange(0,len(c),2)]))
    211 
    212     # Exposure time must be close to the requested exposure time.
    213     assert(is_close_float(exp_time/1000000.0, manual_exp_time/1000000.0))
    214 
    215     # Lens shading map must be valid.
    216     assert(w_map > 0 and h_map > 0 and w_map * h_map * 4 == len(lsc_map))
    217     assert(all([m >= 1 for m in lsc_map]))
    218 
    219     draw_lsc_plot(w_map, h_map, lsc_map, "manual")
    220 
    221 if __name__ == '__main__':
    222     main()
    223 
    224