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