test_capture_result.py revision 87b68b020dd72c4cdcf3b8c1f9196c060f947991
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 15import its.image 16import its.device 17import its.objects 18import os.path 19import pprint 20import math 21import numpy 22import matplotlib.pyplot 23import mpl_toolkits.mplot3d 24 25def main(): 26 """Test that valid data comes back in CaptureResult objects. 27 """ 28 NAME = os.path.basename(__file__).split(".")[0] 29 30 # TODO: Query the allowable tonemap curve sizes; here, it's hardcoded to 31 # a length=64 list of tuples. The max allowed length should be inside the 32 # camera properties object. 33 L = 32 34 LM1 = float(L-1) 35 36 manual_tonemap = sum([[i/LM1, i/LM1] for i in range(L)], []) 37 manual_transform = its.objects.int_to_rational([1,2,3, 4,5,6, 7,8,9]) 38 manual_gains = [1,2,3,4] 39 manual_region = [8,8,128,128] 40 manual_exp_time = 100*1000*1000 41 manual_sensitivity = 100 42 43 auto_req = its.objects.capture_request( { 44 "android.control.mode": 1, 45 "android.control.aeMode": 1, 46 "android.control.awbMode": 1, 47 "android.control.afMode": 1, 48 "android.colorCorrection.mode": 1, 49 "android.tonemap.mode": 1, 50 "android.statistics.lensShadingMapMode":1 51 }) 52 53 manual_req = its.objects.capture_request( { 54 "android.control.mode": 0, 55 "android.control.aeMode": 0, 56 "android.control.awbMode": 0, 57 "android.control.afMode": 0, 58 "android.sensor.frameDuration": 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.curveRed": manual_tonemap, 66 "android.tonemap.curveGreen": manual_tonemap, 67 "android.tonemap.curveBlue": 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 def r2f(r): 75 return float(r["numerator"]) / float(r["denominator"]) 76 77 # A very loose definition for two floats being close to each other; 78 # there may be different interpolation and rounding used to get the 79 # two values, and all this test is looking at is whether there is 80 # something obviously broken; it's not looking for a perfect match. 81 def is_close_float(n1, n2): 82 return abs(n1 - n2) < 0.05 83 84 def is_close_rational(n1, n2): 85 return is_close_float(r2f(n1), r2f(n2)) 86 87 def draw_lsc_plot(w_map, h_map, lsc_map, name): 88 fig = matplotlib.pyplot.figure() 89 ax = fig.gca(projection='3d') 90 xs = numpy.array([range(h_map)] * w_map).reshape(w_map, h_map) 91 ys = numpy.array([[i]*h_map for i in range(w_map)]).reshape(w_map, h_map) 92 for ch in range(4): 93 size = w_map*h_map 94 start = ch * size 95 zs = numpy.array(lsc_map[start:start+size]).reshape(w_map, h_map) 96 ax.plot_wireframe(xs, ys, zs) 97 matplotlib.pyplot.savefig("%s_plot_lsc_%s.png" % (NAME, name)) 98 99 def test_auto(cam, w_map, h_map): 100 fname, w, h, md_obj = cam.do_capture(auto_req) 101 cap_res = md_obj["captureResult"] 102 gains = cap_res["android.colorCorrection.gains"] 103 transform = cap_res["android.colorCorrection.transform"] 104 curves = [cap_res["android.tonemap.curveRed"], 105 cap_res["android.tonemap.curveGreen"], 106 cap_res["android.tonemap.curveBlue"]] 107 exp_time = cap_res['android.sensor.exposureTime'] 108 lsc_map = cap_res["android.statistics.lensShadingMap"] 109 110 print "Gains:", gains 111 print "Transform:", [r2f(t) for t in transform] 112 print "Tonemap:", curves[0][1::16] 113 print "AE region:", cap_res['android.control.aeRegions'] 114 print "AF region:", cap_res['android.control.afRegions'] 115 print "AWB region:", cap_res['android.control.awbRegions'] 116 print "LSC map:", w_map, h_map, lsc_map[:8] 117 118 # Color correction gain and transform must be valid. 119 assert(len(gains) == 4) 120 assert(len(transform) == 9) 121 assert(all([g > 0 for g in gains])) 122 assert(all([t["denominator"] != 0 for t in transform])) 123 124 # Color correction should not match the manual settings. 125 assert(any([not is_close_float(gains[i], manual_gains[i]) 126 for i in xrange(4)])) 127 assert(any([not is_close_rational(transform[i], manual_transform[i]) 128 for i in xrange(9)])) 129 130 # Tonemap need not be valid, but if it is, it should hold useful values. 131 if any([len(c) > 0 for c in curves]): 132 assert(all([len(c) > 0 for c in curves])) 133 134 # Exposure time must be valid. 135 assert(exp_time > 0) 136 137 # 3A regions must be valid. 138 assert(len(cap_res['android.control.aeRegions']) == 5) 139 assert(len(cap_res['android.control.afRegions']) == 5) 140 assert(len(cap_res['android.control.awbRegions']) == 5) 141 142 # Lens shading map must be valid. 143 assert(w_map > 0 and h_map > 0 and w_map * h_map * 4 == len(lsc_map)) 144 assert(all([m >= 1 for m in lsc_map])) 145 146 draw_lsc_plot(w_map, h_map, lsc_map, "auto") 147 148 return lsc_map 149 150 def test_manual(cam, w_map, h_map, lsc_map_auto): 151 fname, w, h, md_obj = cam.do_capture(manual_req) 152 cap_res = md_obj["captureResult"] 153 gains = cap_res["android.colorCorrection.gains"] 154 transform = cap_res["android.colorCorrection.transform"] 155 curves = [cap_res["android.tonemap.curveRed"], 156 cap_res["android.tonemap.curveGreen"], 157 cap_res["android.tonemap.curveBlue"]] 158 exp_time = cap_res['android.sensor.exposureTime'] 159 lsc_map = cap_res["android.statistics.lensShadingMap"] 160 161 print "Gains:", gains 162 print "Transform:", [r2f(t) for t in transform] 163 print "Tonemap:", curves[0][1::16] 164 print "AE region:", cap_res['android.control.aeRegions'] 165 print "AF region:", cap_res['android.control.afRegions'] 166 print "AWB region:", cap_res['android.control.awbRegions'] 167 print "LSC map:", w_map, h_map, lsc_map[:8] 168 169 # Color correction gain and transform must be valid. 170 # Color correction gains and transform should be the same size and 171 # values as the manually set values. 172 assert(len(gains) == 4) 173 assert(len(transform) == 9) 174 assert(all([is_close_float(gains[i], manual_gains[i]) 175 for i in xrange(4)])) 176 assert(all([is_close_rational(transform[i], manual_transform[i]) 177 for i in xrange(9)])) 178 179 # Tonemap must be valid. 180 # The returned tonemap can be interpolated from the provided values. 181 for c in curves: 182 assert(len(c) > 0) 183 for i, val in enumerate(c): 184 ii = int(math.floor( 185 ((i+0.5) / float(len(c))*float(len(manual_tonemap))))) 186 assert(is_close_float(c[i], manual_tonemap[ii])) 187 188 # Exposure time must be close to the requested exposure time. 189 assert(is_close_float(exp_time/1000000.0, manual_exp_time/1000000.0)) 190 191 # 3A regions must be valid, and must match the manual regions. 192 # TODO: Uncomment these assertions once the bug is fixed. 193 #assert(cap_res['android.control.aeRegions'][:4] == manual_region) 194 #assert(cap_res['android.control.afRegions'][:4] == manual_region) 195 #assert(cap_res['android.control.awbRegions'][:4] == manual_region) 196 197 # Lens shading map must be valid. 198 assert(w_map > 0 and h_map > 0 and w_map * h_map * 4 == len(lsc_map)) 199 assert(all([m >= 1 for m in lsc_map])) 200 201 # Lens shading map must take into account the manual color correction 202 # settings. Test this by ensuring that the map is different between 203 # the auto and manual test cases. 204 # TODO: Uncomment these assertions once the bug is fixed. 205 #assert(lsc_map != lsc_map_auto) 206 207 draw_lsc_plot(w_map, h_map, lsc_map, "manual") 208 209 with its.device.ItsSession() as cam: 210 props = cam.get_camera_properties() 211 w_map = props["android.lens.info.shadingMapSize"]["width"] 212 h_map = props["android.lens.info.shadingMapSize"]["height"] 213 214 print "Testing auto capture results" 215 lsc_map_auto = test_auto(cam, w_map, h_map) 216 print "Testing manual capture results" 217 test_manual(cam, w_map, h_map, lsc_map_auto) 218 print "Testing auto capture results again" 219 test_auto(cam, w_map, h_map) 220 221if __name__ == '__main__': 222 main() 223 224