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 os.path 16import its.caps 17import its.device 18import its.image 19import its.objects 20import matplotlib.pyplot 21import mpl_toolkits.mplot3d # Required for 3d plot to work 22import numpy 23 24 25def 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 83def 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 99def 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 104def 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 116def 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 173def 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 235if __name__ == "__main__": 236 main() 237 238