Chien-Yu Chen | 4e1e2cc | 2015-06-08 17:46:52 -0700 | [diff] [blame] | 1 | # Copyright 2015 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.caps |
| 17 | import its.device |
| 18 | import its.objects |
| 19 | import its.target |
| 20 | import math |
| 21 | import matplotlib |
| 22 | import matplotlib.pyplot |
Chien-Yu Chen | 0b7fb8a | 2015-07-15 15:58:27 -0700 | [diff] [blame] | 23 | import numpy |
Chien-Yu Chen | 4e1e2cc | 2015-06-08 17:46:52 -0700 | [diff] [blame] | 24 | import os.path |
| 25 | import pylab |
| 26 | |
| 27 | def main(): |
| 28 | """Test that the android.noiseReduction.mode param is applied when set for |
| 29 | reprocessing requests. |
| 30 | |
| 31 | Capture reprocessed images with the camera dimly lit. Uses a high analog |
| 32 | gain to ensure the captured image is noisy. |
| 33 | |
| 34 | Captures three reprocessed images, for NR off, "fast", and "high quality". |
| 35 | Also captures a reprocessed image with low gain and NR off, and uses the |
| 36 | variance of this as the baseline. |
| 37 | """ |
| 38 | |
| 39 | NAME = os.path.basename(__file__).split(".")[0] |
| 40 | |
Chien-Yu Chen | 0b7fb8a | 2015-07-15 15:58:27 -0700 | [diff] [blame] | 41 | RELATIVE_ERROR_TOLERANCE = 0.1 |
| 42 | |
Chien-Yu Chen | 4e1e2cc | 2015-06-08 17:46:52 -0700 | [diff] [blame] | 43 | with its.device.ItsSession() as cam: |
| 44 | props = cam.get_camera_properties() |
| 45 | |
| 46 | its.caps.skip_unless(its.caps.compute_target_exposure(props) and |
| 47 | its.caps.per_frame_control(props) and |
Chien-Yu Chen | 455b57f | 2015-07-09 12:02:25 -0700 | [diff] [blame] | 48 | its.caps.noise_reduction_mode(props, 0) and |
Chien-Yu Chen | 4e1e2cc | 2015-06-08 17:46:52 -0700 | [diff] [blame] | 49 | (its.caps.yuv_reprocess(props) or |
| 50 | its.caps.private_reprocess(props))) |
| 51 | |
Chien-Yu Chen | 455b57f | 2015-07-09 12:02:25 -0700 | [diff] [blame] | 52 | # If reprocessing is supported, ZSL NR mode must be avaiable. |
| 53 | assert(its.caps.noise_reduction_mode(props, 4)) |
| 54 | |
Chien-Yu Chen | 4e1e2cc | 2015-06-08 17:46:52 -0700 | [diff] [blame] | 55 | reprocess_formats = [] |
| 56 | if (its.caps.yuv_reprocess(props)): |
| 57 | reprocess_formats.append("yuv") |
| 58 | if (its.caps.private_reprocess(props)): |
| 59 | reprocess_formats.append("private") |
| 60 | |
| 61 | for reprocess_format in reprocess_formats: |
| 62 | # List of variances for R, G, B. |
| 63 | variances = [] |
| 64 | nr_modes_reported = [] |
| 65 | |
| 66 | # NR mode 0 with low gain |
| 67 | e, s = its.target.get_target_exposure_combos(cam)["minSensitivity"] |
| 68 | req = its.objects.manual_capture_request(s, e) |
| 69 | req["android.noiseReduction.mode"] = 0 |
| 70 | |
| 71 | # Test reprocess_format->JPEG reprocessing |
| 72 | # TODO: Switch to reprocess_format->YUV when YUV reprocessing is |
| 73 | # supported. |
| 74 | size = its.objects.get_available_output_sizes("jpg", props)[0] |
| 75 | out_surface = {"width":size[0], "height":size[1], "format":"jpg"} |
| 76 | cap = cam.do_capture(req, out_surface, reprocess_format) |
| 77 | img = its.image.decompress_jpeg_to_rgb_image(cap["data"]) |
| 78 | its.image.write_image(img, "%s_low_gain_fmt=jpg.jpg" % (NAME)) |
| 79 | tile = its.image.get_image_patch(img, 0.45, 0.45, 0.1, 0.1) |
| 80 | ref_variance = its.image.compute_image_variances(tile) |
| 81 | print "Ref variances:", ref_variance |
| 82 | |
Chien-Yu Chen | 455b57f | 2015-07-09 12:02:25 -0700 | [diff] [blame] | 83 | for nr_mode in range(5): |
Chien-Yu Chen | 0b7fb8a | 2015-07-15 15:58:27 -0700 | [diff] [blame] | 84 | # Skip unavailable modes |
Chien-Yu Chen | 455b57f | 2015-07-09 12:02:25 -0700 | [diff] [blame] | 85 | if not its.caps.noise_reduction_mode(props, nr_mode): |
| 86 | nr_modes_reported.append(nr_mode) |
| 87 | variances.append(0) |
| 88 | continue |
| 89 | |
| 90 | # NR modes with high gain |
Chien-Yu Chen | 4e1e2cc | 2015-06-08 17:46:52 -0700 | [diff] [blame] | 91 | e, s = its.target.get_target_exposure_combos(cam) \ |
| 92 | ["maxSensitivity"] |
| 93 | req = its.objects.manual_capture_request(s, e) |
| 94 | req["android.noiseReduction.mode"] = nr_mode |
| 95 | cap = cam.do_capture(req, out_surface, reprocess_format) |
| 96 | nr_modes_reported.append( |
| 97 | cap["metadata"]["android.noiseReduction.mode"]) |
| 98 | |
| 99 | img = its.image.decompress_jpeg_to_rgb_image(cap["data"]) |
| 100 | its.image.write_image( |
| 101 | img, "%s_high_gain_nr=%d_fmt=jpg.jpg" % (NAME, nr_mode)) |
| 102 | tile = its.image.get_image_patch(img, 0.45, 0.45, 0.1, 0.1) |
| 103 | # Get the variances for R, G, and B channels |
| 104 | variance = its.image.compute_image_variances(tile) |
| 105 | variances.append( |
| 106 | [variance[chan] / ref_variance[chan] for chan in range(3)]) |
Chien-Yu Chen | 455b57f | 2015-07-09 12:02:25 -0700 | [diff] [blame] | 107 | print "Variances with NR mode [0,1,2,3,4]:", variances |
Chien-Yu Chen | 4e1e2cc | 2015-06-08 17:46:52 -0700 | [diff] [blame] | 108 | |
| 109 | # Draw a plot. |
Chien-Yu Chen | ea057aa | 2015-08-04 17:31:06 -0700 | [diff] [blame] | 110 | for chan in range(3): |
| 111 | line = [] |
| 112 | for nr_mode in range(5): |
| 113 | line.append(variances[nr_mode][chan]) |
| 114 | pylab.plot(range(5), line, "rgb"[chan]) |
| 115 | |
Chien-Yu Chen | 4e1e2cc | 2015-06-08 17:46:52 -0700 | [diff] [blame] | 116 | matplotlib.pyplot.savefig("%s_plot_%s_variances.png" % |
| 117 | (NAME, reprocess_format)) |
| 118 | |
Chien-Yu Chen | 0b7fb8a | 2015-07-15 15:58:27 -0700 | [diff] [blame] | 119 | assert(nr_modes_reported == [0,1,2,3,4]) |
Chien-Yu Chen | 4e1e2cc | 2015-06-08 17:46:52 -0700 | [diff] [blame] | 120 | |
Chien-Yu Chen | 0b7fb8a | 2015-07-15 15:58:27 -0700 | [diff] [blame] | 121 | for j in range(3): |
| 122 | # Smaller variance is better |
| 123 | # Verify OFF(0) is not better than FAST(1) |
| 124 | assert(variances[0][j] > |
| 125 | variances[1][j] * (1.0 - RELATIVE_ERROR_TOLERANCE)) |
| 126 | # Verify FAST(1) is not better than HQ(2) |
| 127 | assert(variances[1][j] > |
| 128 | variances[2][j] * (1.0 - RELATIVE_ERROR_TOLERANCE)) |
| 129 | # Verify HQ(2) is better than OFF(0) |
| 130 | assert(variances[0][j] > variances[2][j]) |
| 131 | if its.caps.noise_reduction_mode(props, 3): |
| 132 | # Verify OFF(0) is not better than MINIMAL(3) |
| 133 | assert(variances[0][j] > |
| 134 | variances[3][j] * (1.0 - RELATIVE_ERROR_TOLERANCE)) |
| 135 | # Verify MINIMAL(3) is not better than HQ(2) |
| 136 | assert(variances[3][j] > |
| 137 | variances[2][j] * (1.0 - RELATIVE_ERROR_TOLERANCE)) |
Chien-Yu Chen | ea057aa | 2015-08-04 17:31:06 -0700 | [diff] [blame] | 138 | # Verify ZSL(4) is close to MINIMAL(3) |
| 139 | assert(numpy.isclose(variances[4][j], variances[3][j], |
| 140 | RELATIVE_ERROR_TOLERANCE)) |
| 141 | else: |
| 142 | # Verify ZSL(4) is close to OFF(0) |
| 143 | assert(numpy.isclose(variances[4][j], variances[0][j], |
| 144 | RELATIVE_ERROR_TOLERANCE)) |
Chien-Yu Chen | 4e1e2cc | 2015-06-08 17:46:52 -0700 | [diff] [blame] | 145 | |
| 146 | if __name__ == '__main__': |
| 147 | main() |
| 148 | |