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.device 16 import its.caps 17 import its.objects 18 import its.image 19 import os.path 20 import pylab 21 import matplotlib 22 import matplotlib.pyplot 23 24 def main(): 25 """Verify that the DNG raw model parameters are correct. 26 """ 27 NAME = os.path.basename(__file__).split(".")[0] 28 29 NUM_STEPS = 4 30 31 # Pass if the difference between expected and computed variances is small, 32 # defined as being within an absolute variance delta of 0.0005, or within 33 # 20% of the expected variance, whichever is larger; this is to allow the 34 # test to pass in the presence of some randomness (since this test is 35 # measuring noise of a small patch) and some imperfect scene conditions 36 # (since ITS doesn't require a perfectly uniformly lit scene). 37 DIFF_THRESH = 0.0005 38 FRAC_THRESH = 0.2 39 40 with its.device.ItsSession() as cam: 41 42 props = cam.get_camera_properties() 43 its.caps.skip_unless(its.caps.raw(props) and 44 its.caps.raw16(props) and 45 its.caps.manual_sensor(props) and 46 its.caps.read_3a(props) and 47 its.caps.per_frame_control(props)) 48 49 white_level = float(props['android.sensor.info.whiteLevel']) 50 black_levels = props['android.sensor.blackLevelPattern'] 51 cfa_idxs = its.image.get_canonical_cfa_order(props) 52 black_levels = [black_levels[i] for i in cfa_idxs] 53 54 # Expose for the scene with min sensitivity 55 sens_min, sens_max = props['android.sensor.info.sensitivityRange'] 56 sens_step = (sens_max - sens_min) / NUM_STEPS 57 s_ae,e_ae,_,_,_ = cam.do_3a(get_results=True) 58 s_e_prod = s_ae * e_ae 59 sensitivities = range(sens_min, sens_max, sens_step) 60 61 var_expected = [[],[],[],[]] 62 var_measured = [[],[],[],[]] 63 for sens in sensitivities: 64 65 # Capture a raw frame with the desired sensitivity. 66 exp = int(s_e_prod / float(sens)) 67 req = its.objects.manual_capture_request(sens, exp) 68 cap = cam.do_capture(req, cam.CAP_RAW) 69 70 # Test each raw color channel (R, GR, GB, B): 71 noise_profile = cap["metadata"]["android.sensor.noiseProfile"] 72 assert((len(noise_profile)) == 4) 73 for ch in range(4): 74 # Get the noise model parameters for this channel of this shot. 75 s,o = noise_profile[cfa_idxs[ch]] 76 77 # Get a center tile of the raw channel, and compute the mean. 78 # Use a very small patch to ensure gross uniformity (i.e. so 79 # non-uniform lighting or vignetting doesn't affect the variance 80 # calculation). 81 plane = its.image.convert_capture_to_planes(cap, props)[ch] 82 plane = (plane * white_level - black_levels[ch]) / ( 83 white_level - black_levels[ch]) 84 tile = its.image.get_image_patch(plane, 0.49,0.49,0.02,0.02) 85 mean = tile.mean() 86 87 # Calculate the expected variance based on the model, and the 88 # measured variance from the tile. 89 var_measured[ch].append( 90 its.image.compute_image_variances(tile)[0]) 91 var_expected[ch].append(s * mean + o) 92 93 for ch in range(4): 94 pylab.plot(sensitivities, var_expected[ch], "rgkb"[ch], 95 label=["R","GR","GB","B"][ch]+" expected") 96 pylab.plot(sensitivities, var_measured[ch], "rgkb"[ch]+"--", 97 label=["R", "GR", "GB", "B"][ch]+" measured") 98 pylab.xlabel("Sensitivity") 99 pylab.ylabel("Center patch variance") 100 pylab.legend(loc=2) 101 matplotlib.pyplot.savefig("%s_plot.png" % (NAME)) 102 103 # Pass/fail check. 104 for ch in range(4): 105 diffs = [var_measured[ch][i] - var_expected[ch][i] 106 for i in range(NUM_STEPS)] 107 print "Diffs (%s):"%(["R","GR","GB","B"][ch]), diffs 108 for i,diff in enumerate(diffs): 109 thresh = max(DIFF_THRESH, FRAC_THRESH * var_expected[ch][i]) 110 assert(diff <= thresh) 111 112 if __name__ == '__main__': 113 main() 114 115