Zhijun He | 6137f21 | 2014-11-20 13:47:11 -0800 | [diff] [blame] | 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 |
Zhijun He | 503da80 | 2015-02-04 14:35:38 -0800 | [diff] [blame^] | 36 | its.caps.per_frame_control(props) and |
| 37 | its.caps.ev_compensation(props)) |
Zhijun He | 6137f21 | 2014-11-20 13:47:11 -0800 | [diff] [blame] | 38 | |
| 39 | evs = range(-4,5) |
| 40 | lumas = [] |
| 41 | for ev in evs: |
| 42 | # Re-converge 3A, and lock AE once converged. skip AF trigger as |
| 43 | # dark/bright scene could make AF convergence fail and this test |
| 44 | # doesn't care the image sharpness. |
| 45 | cam.do_3a(ev_comp=ev, lock_ae=True, do_af=False) |
| 46 | |
| 47 | # Capture a single shot with the same EV comp and locked AE. |
| 48 | req = its.objects.auto_capture_request() |
| 49 | req['android.control.aeExposureCompensation'] = ev |
| 50 | req["android.control.aeLock"] = True |
| 51 | # Use linear tone curve to avoid brightness being impacted |
| 52 | # by tone curves. |
| 53 | req["android.tonemap.mode"] = 0 |
| 54 | req["android.tonemap.curveRed"] = [0.0,0.0, 1.0,1.0] |
| 55 | req["android.tonemap.curveGreen"] = [0.0,0.0, 1.0,1.0] |
| 56 | req["android.tonemap.curveBlue"] = [0.0,0.0, 1.0,1.0] |
| 57 | cap = cam.do_capture(req) |
| 58 | y = its.image.convert_capture_to_planes(cap)[0] |
| 59 | tile = its.image.get_image_patch(y, 0.45,0.45,0.1,0.1) |
| 60 | lumas.append(its.image.compute_image_means(tile)[0]) |
| 61 | |
| 62 | ev_step_size_in_stops = its.objects.rational_to_float( |
| 63 | props['android.control.aeCompensationStep']) |
| 64 | luma_increase_per_step = pow(2, ev_step_size_in_stops) |
| 65 | print "ev_step_size_in_stops", ev_step_size_in_stops |
| 66 | imid = len(lumas) / 2 |
| 67 | expected_lumas = [lumas[imid] / pow(luma_increase_per_step, i) |
| 68 | for i in range(imid , 0, -1)] + \ |
| 69 | [lumas[imid] * pow(luma_increase_per_step, i-imid) |
| 70 | for i in range(imid, len(evs))] |
| 71 | |
| 72 | pylab.plot(evs, lumas, 'r') |
| 73 | pylab.plot(evs, expected_lumas, 'b') |
| 74 | matplotlib.pyplot.savefig("%s_plot_means.png" % (NAME)) |
| 75 | |
| 76 | luma_diffs = [expected_lumas[i] - lumas[i] for i in range(len(evs))] |
| 77 | max_diff = max(abs(i) for i in luma_diffs) |
| 78 | avg_diff = abs(numpy.array(luma_diffs)).mean() |
| 79 | print "Max delta between modeled and measured lumas:", max_diff |
| 80 | print "Avg delta between modeled and measured lumas:", avg_diff |
| 81 | assert(max_diff < MAX_LUMA_DELTA_THRESH) |
| 82 | |
| 83 | if __name__ == '__main__': |
| 84 | main() |