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.caps 17import its.device 18import its.objects 19import os.path 20import numpy 21import matplotlib.pyplot 22 23# Required for 3d plot to work 24import mpl_toolkits.mplot3d 25 26def 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, props) 81 print "Testing manual capture results" 82 test_manual(cam, w_map, h_map, lsc_map_auto, props) 83 print "Testing auto capture results again" 84 test_auto(cam, w_map, h_map, props) 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. 90def is_close_float(n1, n2): 91 return abs(n1 - n2) < 0.05 92 93def is_close_rational(n1, n2): 94 return is_close_float(its.objects.rational_to_float(n1), 95 its.objects.rational_to_float(n2)) 96 97def 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 108def test_auto(cam, w_map, h_map, props): 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 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 160def test_manual(cam, w_map, h_map, 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.curveRed"], 167 cap_res["android.tonemap.curveGreen"], 168 cap_res["android.tonemap.curveBlue"]] 169 exp_time = cap_res['android.sensor.exposureTime'] 170 lsc_map = cap_res["android.statistics.lensShadingMap"] 171 ctrl_mode = cap_res["android.control.mode"] 172 173 print "Control mode:", ctrl_mode 174 print "Gains:", gains 175 print "Transform:", [its.objects.rational_to_float(t) 176 for t in transform] 177 print "Tonemap:", curves[0][1::16] 178 if props["android.control.maxRegionsAe"] > 0: 179 print "AE region:", cap_res['android.control.aeRegions'] 180 if props["android.control.maxRegionsAf"] > 0: 181 print "AF region:", cap_res['android.control.afRegions'] 182 if props["android.control.maxRegionsAwb"] > 0: 183 print "AWB region:", cap_res['android.control.awbRegions'] 184 print "LSC map:", w_map, h_map, lsc_map[:8] 185 186 assert(ctrl_mode == 0) 187 188 # Color correction gain and transform must be valid. 189 # Color correction gains and transform should be the same size and 190 # values as the manually set values. 191 assert(len(gains) == 4) 192 assert(len(transform) == 9) 193 assert( all([is_close_float(gains[i], manual_gains_ok[0][i]) 194 for i in xrange(4)]) or 195 all([is_close_float(gains[i], manual_gains_ok[1][i]) 196 for i in xrange(4)]) or 197 all([is_close_float(gains[i], manual_gains_ok[2][i]) 198 for i in xrange(4)])) 199 assert(all([is_close_rational(transform[i], manual_transform[i]) 200 for i in xrange(9)])) 201 202 # Tonemap must be valid. 203 # The returned tonemap must be linear. 204 for c in curves: 205 assert(len(c) > 0) 206 assert(all([is_close_float(c[i], c[i+1]) 207 for i in xrange(0,len(c),2)])) 208 209 # Exposure time must be close to the requested exposure time. 210 assert(is_close_float(exp_time/1000000.0, manual_exp_time/1000000.0)) 211 212 # Lens shading map must be valid. 213 assert(w_map > 0 and h_map > 0 and w_map * h_map * 4 == len(lsc_map)) 214 assert(all([m >= 1 for m in lsc_map])) 215 216 draw_lsc_plot(w_map, h_map, lsc_map, "manual") 217 218if __name__ == '__main__': 219 main() 220 221