1 # Copyright 2014 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.caps 18 import its.objects 19 import os.path 20 import pylab 21 import matplotlib 22 import matplotlib.pyplot 23 import numpy 24 25 def main(): 26 """Tests that EV compensation is applied. 27 """ 28 NAME = os.path.basename(__file__).split(".")[0] 29 30 MAX_LUMA_DELTA_THRESH = 0.02 31 32 with its.device.ItsSession() as cam: 33 props = cam.get_camera_properties() 34 its.caps.skip_unless(its.caps.manual_sensor(props) and 35 its.caps.manual_post_proc(props) and 36 its.caps.per_frame_control(props) and 37 its.caps.ev_compensation(props)) 38 39 ev_compensation_range = props['android.control.aeCompensationRange'] 40 range_min = ev_compensation_range[0] 41 range_max = ev_compensation_range[1] 42 ev_per_step = its.objects.rational_to_float( 43 props['android.control.aeCompensationStep']) 44 steps_per_ev = int(1.0 / ev_per_step) 45 evs = range(range_min, range_max + 1, steps_per_ev) 46 lumas = [] 47 for ev in evs: 48 # Re-converge 3A, and lock AE once converged. skip AF trigger as 49 # dark/bright scene could make AF convergence fail and this test 50 # doesn't care the image sharpness. 51 cam.do_3a(ev_comp=ev, lock_ae=True, do_af=False) 52 53 # Capture a single shot with the same EV comp and locked AE. 54 req = its.objects.auto_capture_request() 55 req['android.control.aeExposureCompensation'] = ev 56 req["android.control.aeLock"] = True 57 # Use linear tone curve to avoid brightness being impacted 58 # by tone curves. 59 req["android.tonemap.mode"] = 0 60 req["android.tonemap.curveRed"] = [0.0,0.0, 1.0,1.0] 61 req["android.tonemap.curveGreen"] = [0.0,0.0, 1.0,1.0] 62 req["android.tonemap.curveBlue"] = [0.0,0.0, 1.0,1.0] 63 cap = cam.do_capture(req) 64 y = its.image.convert_capture_to_planes(cap)[0] 65 tile = its.image.get_image_patch(y, 0.45,0.45,0.1,0.1) 66 lumas.append(its.image.compute_image_means(tile)[0]) 67 68 luma_increase_per_step = pow(2, ev_per_step) 69 print "ev_step_size_in_stops", ev_per_step 70 imid = len(lumas) / 2 71 expected_lumas = [lumas[imid] / pow(luma_increase_per_step, i) 72 for i in range(imid , 0, -1)] + \ 73 [lumas[imid] * pow(luma_increase_per_step, i-imid) 74 for i in range(imid, len(evs))] 75 76 pylab.plot(evs, lumas, 'r') 77 pylab.plot(evs, expected_lumas, 'b') 78 matplotlib.pyplot.savefig("%s_plot_means.png" % (NAME)) 79 80 luma_diffs = [expected_lumas[i] - lumas[i] for i in range(len(evs))] 81 max_diff = max(abs(i) for i in luma_diffs) 82 avg_diff = abs(numpy.array(luma_diffs)).mean() 83 print "Max delta between modeled and measured lumas:", max_diff 84 print "Avg delta between modeled and measured lumas:", avg_diff 85 assert(max_diff < MAX_LUMA_DELTA_THRESH) 86 87 if __name__ == '__main__': 88 main() 89