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 its.image 16import its.caps 17import its.device 18import its.objects 19import its.target 20import matplotlib 21import matplotlib.pyplot 22import numpy 23import os.path 24from matplotlib import pylab 25 26NR_MODES = [0, 1, 2, 3, 4] # NR modes 0, 1, 2, 3, 4 with high gain 27 28 29def main(): 30 """Test that the android.noiseReduction.mode param is applied when set. 31 32 Capture images with the camera dimly lit. Uses a high analog gain to 33 ensure the captured image is noisy. 34 35 Captures three images, for NR off, "fast", and "high quality". 36 Also captures an image with low gain and NR off, and uses the variance 37 of this as the baseline. 38 """ 39 NAME = os.path.basename(__file__).split(".")[0] 40 41 NUM_SAMPLES_PER_MODE = 4 42 SNR_TOLERANCE = 3 # unit in db 43 # List of SNRs for R,G,B. 44 snrs = [[], [], []] 45 46 # Reference (baseline) SNR for each of R,G,B. 47 ref_snr = [] 48 49 nr_modes_reported = [] 50 51 with its.device.ItsSession() as cam: 52 props = cam.get_camera_properties() 53 its.caps.skip_unless(its.caps.compute_target_exposure(props) and 54 its.caps.per_frame_control(props) and 55 its.caps.noise_reduction_mode(props, 0)) 56 57 # NR mode 0 with low gain 58 e, s = its.target.get_target_exposure_combos(cam)["minSensitivity"] 59 req = its.objects.manual_capture_request(s, e) 60 req["android.noiseReduction.mode"] = 0 61 cap = cam.do_capture(req) 62 rgb_image = its.image.convert_capture_to_rgb_image(cap) 63 its.image.write_image( 64 rgb_image, 65 "%s_low_gain.jpg" % (NAME)) 66 rgb_tile = its.image.get_image_patch(rgb_image, 0.45, 0.45, 0.1, 0.1) 67 ref_snr = its.image.compute_image_snrs(rgb_tile) 68 print "Ref SNRs:", ref_snr 69 70 e, s = its.target.get_target_exposure_combos(cam)["maxSensitivity"] 71 72 for mode in NR_MODES: 73 # Skip unavailable modes 74 if not its.caps.noise_reduction_mode(props, mode): 75 nr_modes_reported.append(mode) 76 for channel in range(3): 77 snrs[channel].append(0) 78 continue 79 80 rgb_snr_list = [] 81 # Capture several images to account for per frame noise variations 82 for n in range(NUM_SAMPLES_PER_MODE): 83 req = its.objects.manual_capture_request(s, e) 84 req["android.noiseReduction.mode"] = mode 85 cap = cam.do_capture(req) 86 rgb_image = its.image.convert_capture_to_rgb_image(cap) 87 if n == 0: 88 nr_modes_reported.append( 89 cap["metadata"]["android.noiseReduction.mode"]) 90 its.image.write_image( 91 rgb_image, 92 "%s_high_gain_nr=%d.jpg" % (NAME, mode)) 93 rgb_tile = its.image.get_image_patch( 94 rgb_image, 0.45, 0.45, 0.1, 0.1) 95 rgb_snrs = its.image.compute_image_snrs(rgb_tile) 96 rgb_snr_list.append(rgb_snrs) 97 98 r_snrs = [rgb[0] for rgb in rgb_snr_list] 99 g_snrs = [rgb[1] for rgb in rgb_snr_list] 100 b_snrs = [rgb[2] for rgb in rgb_snr_list] 101 rgb_snrs = [numpy.mean(r_snrs), numpy.mean(g_snrs), numpy.mean(b_snrs)] 102 print "NR mode", mode, "SNRs:" 103 print " R SNR:", rgb_snrs[0],\ 104 "Min:", min(r_snrs), "Max:", max(r_snrs) 105 print " G SNR:", rgb_snrs[1],\ 106 "Min:", min(g_snrs), "Max:", max(g_snrs) 107 print " B SNR:", rgb_snrs[2],\ 108 "Min:", min(b_snrs), "Max:", max(b_snrs) 109 110 for chan in range(3): 111 snrs[chan].append(rgb_snrs[chan]) 112 113 # Draw a plot. 114 for j in range(3): 115 pylab.plot(NR_MODES, snrs[j], "-"+"rgb"[j]+"o") 116 pylab.xlabel("Noise Reduction Mode") 117 pylab.ylabel("SNR (dB)") 118 pylab.xticks(NR_MODES) 119 matplotlib.pyplot.savefig("%s_plot_SNRs.png" % (NAME)) 120 121 assert nr_modes_reported == NR_MODES 122 123 for j in range(3): 124 # Larger SNR is better 125 # Verify OFF(0) is not better than FAST(1) 126 assert(snrs[j][0] < 127 snrs[j][1] + SNR_TOLERANCE) 128 # Verify FAST(1) is not better than HQ(2) 129 assert(snrs[j][1] < 130 snrs[j][2] + SNR_TOLERANCE) 131 # Verify HQ(2) is better than OFF(0) 132 assert(snrs[j][0] < snrs[j][2]) 133 if its.caps.noise_reduction_mode(props, 3): 134 # Verify OFF(0) is not better than MINIMAL(3) 135 assert(snrs[j][0] < 136 snrs[j][3] + SNR_TOLERANCE) 137 # Verify MINIMAL(3) is not better than HQ(2) 138 assert(snrs[j][3] < 139 snrs[j][2] + SNR_TOLERANCE) 140 if its.caps.noise_reduction_mode(props, 4): 141 # Verify ZSL(4) is close to MINIMAL(3) 142 assert(numpy.isclose(snrs[j][4], snrs[j][3], 143 atol=SNR_TOLERANCE)) 144 elif its.caps.noise_reduction_mode(props, 4): 145 # Verify ZSL(4) is close to OFF(0) 146 assert(numpy.isclose(snrs[j][4], snrs[j][0], 147 atol=SNR_TOLERANCE)) 148 149if __name__ == '__main__': 150 main() 151 152