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