Home | History | Annotate | Download | only in scene1
      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 os.path
     16 
     17 import its.caps
     18 import its.device
     19 import its.image
     20 import its.objects
     21 import its.target
     22 
     23 import matplotlib
     24 from matplotlib import pylab
     25 import numpy
     26 
     27 NAME = os.path.basename(__file__).split(".")[0]
     28 NR_MODES = [0, 1, 2, 3, 4]
     29 NUM_FRAMES = 4
     30 SNR_TOLERANCE = 3  # unit in dB
     31 
     32 
     33 def main():
     34     """Test android.noiseReduction.mode is applied for reprocessing requests.
     35 
     36     Capture reprocessed images with the camera dimly lit. Uses a high analog
     37     gain to ensure the captured image is noisy.
     38 
     39     Captures three reprocessed images, for NR off, "fast", and "high quality".
     40     Also captures a reprocessed image with low gain and NR off, and uses the
     41     variance of this as the baseline.
     42     """
     43 
     44     with its.device.ItsSession() as cam:
     45         props = cam.get_camera_properties()
     46 
     47         its.caps.skip_unless(its.caps.compute_target_exposure(props) and
     48                              its.caps.per_frame_control(props) and
     49                              its.caps.noise_reduction_mode(props, 0) and
     50                              (its.caps.yuv_reprocess(props) or
     51                               its.caps.private_reprocess(props)))
     52 
     53         # If reprocessing is supported, ZSL NR mode must be avaiable.
     54         assert its.caps.noise_reduction_mode(props, 4)
     55 
     56         reprocess_formats = []
     57         if its.caps.yuv_reprocess(props):
     58             reprocess_formats.append("yuv")
     59         if its.caps.private_reprocess(props):
     60             reprocess_formats.append("private")
     61 
     62         for reprocess_format in reprocess_formats:
     63             print "\nreprocess format:", reprocess_format
     64             # List of variances for R, G, B.
     65             snrs = [[], [], []]
     66             nr_modes_reported = []
     67 
     68             # NR mode 0 with low gain
     69             e, s = its.target.get_target_exposure_combos(cam)["minSensitivity"]
     70             req = its.objects.manual_capture_request(s, e)
     71             req["android.noiseReduction.mode"] = 0
     72 
     73             # Test reprocess_format->JPEG reprocessing
     74             # TODO: Switch to reprocess_format->YUV when YUV reprocessing is
     75             #       supported.
     76             size = its.objects.get_available_output_sizes("jpg", props)[0]
     77             out_surface = {"width": size[0], "height": size[1], "format": "jpg"}
     78             cap = cam.do_capture(req, out_surface, reprocess_format)
     79             img = its.image.decompress_jpeg_to_rgb_image(cap["data"])
     80             its.image.write_image(img, "%s_low_gain_fmt=jpg.jpg" % NAME)
     81             tile = its.image.get_image_patch(img, 0.45, 0.45, 0.1, 0.1)
     82             ref_snr = its.image.compute_image_snrs(tile)
     83             print "Ref SNRs:", ref_snr
     84 
     85             e, s = its.target.get_target_exposure_combos(cam)["maxSensitivity"]
     86             for nr_mode in NR_MODES:
     87                 # Skip unavailable modes
     88                 if not its.caps.noise_reduction_mode(props, nr_mode):
     89                     nr_modes_reported.append(nr_mode)
     90                     for channel in range(3):
     91                         snrs[channel].append(0)
     92                     continue
     93 
     94                 rgb_snr_list = []
     95                 # Capture several images to account for per frame noise
     96                 # variations
     97                 req = its.objects.manual_capture_request(s, e)
     98                 req["android.noiseReduction.mode"] = nr_mode
     99                 caps = cam.do_capture(
    100                         [req]*NUM_FRAMES, out_surface, reprocess_format)
    101                 for n in range(NUM_FRAMES):
    102                     img = its.image.decompress_jpeg_to_rgb_image(
    103                             caps[n]["data"])
    104                     if n == 0:
    105                         its.image.write_image(
    106                                 img, "%s_high_gain_nr=%d_fmt=jpg.jpg" % (
    107                                         NAME, nr_mode))
    108                         nr_modes_reported.append(
    109                                 caps[n]["metadata"]["android.noiseReduction.mode"])
    110 
    111                     tile = its.image.get_image_patch(img, 0.45, 0.45, 0.1, 0.1)
    112                     # Get the variances for R, G, and B channels
    113                     rgb_snrs = its.image.compute_image_snrs(tile)
    114                     rgb_snr_list.append(rgb_snrs)
    115 
    116                 r_snrs = [rgb[0] for rgb in rgb_snr_list]
    117                 g_snrs = [rgb[1] for rgb in rgb_snr_list]
    118                 b_snrs = [rgb[2] for rgb in rgb_snr_list]
    119                 rgb_snrs = [numpy.mean(r_snrs),
    120                             numpy.mean(g_snrs),
    121                             numpy.mean(b_snrs)]
    122                 print "NR mode", nr_mode, "SNRs:"
    123                 print "    R SNR:", rgb_snrs[0],
    124                 print "Min:", min(r_snrs), "Max:", max(r_snrs)
    125                 print "    G SNR:", rgb_snrs[1],
    126                 print "Min:", min(g_snrs), "Max:", max(g_snrs)
    127                 print "    B SNR:", rgb_snrs[2],
    128                 print "Min:", min(b_snrs), "Max:", max(b_snrs)
    129 
    130                 for chan in range(3):
    131                     snrs[chan].append(rgb_snrs[chan])
    132 
    133             # Draw a plot.
    134             pylab.figure(reprocess_format)
    135             for channel in range(3):
    136                 pylab.plot(NR_MODES, snrs[channel], "-"+"rgb"[channel]+"o")
    137 
    138             pylab.title(NAME + ", reprocess_fmt=" + reprocess_format)
    139             pylab.xlabel("Noise Reduction Mode")
    140             pylab.ylabel("SNR (dB)")
    141             pylab.xticks(NR_MODES)
    142             matplotlib.pyplot.savefig("%s_plot_%s_SNRs.png" %
    143                                       (NAME, reprocess_format))
    144 
    145             assert nr_modes_reported == NR_MODES
    146 
    147             for j in range(3):
    148                 # Verify OFF(0) is not better than FAST(1)
    149                 msg = "FAST(1): %.2f, OFF(0): %.2f, TOL: %f" % (
    150                         snrs[j][1], snrs[j][0], SNR_TOLERANCE)
    151                 assert snrs[j][0] < snrs[j][1] + SNR_TOLERANCE, msg
    152                 # Verify FAST(1) is not better than HQ(2)
    153                 msg = "HQ(2): %.2f, FAST(1): %.2f, TOL: %f" % (
    154                         snrs[j][2], snrs[j][1], SNR_TOLERANCE)
    155                 assert snrs[j][1] < snrs[j][2] + SNR_TOLERANCE, msg
    156                 # Verify HQ(2) is better than OFF(0)
    157                 msg = "HQ(2): %.2f, OFF(0): %.2f" % (snrs[j][2], snrs[j][0])
    158                 assert snrs[j][0] < snrs[j][2], msg
    159                 if its.caps.noise_reduction_mode(props, 3):
    160                     # Verify OFF(0) is not better than MINIMAL(3)
    161                     msg = "MINIMAL(3): %.2f, OFF(0): %.2f, TOL: %f" % (
    162                             snrs[j][3], snrs[j][0], SNR_TOLERANCE)
    163                     assert snrs[j][0] < snrs[j][3] + SNR_TOLERANCE, msg
    164                     # Verify MINIMAL(3) is not better than HQ(2)
    165                     msg = "MINIMAL(3): %.2f, HQ(2): %.2f, TOL: %f" % (
    166                             snrs[j][3], snrs[j][2], SNR_TOLERANCE)
    167                     assert snrs[j][3] < snrs[j][2] + SNR_TOLERANCE, msg
    168                     # Verify ZSL(4) is close to MINIMAL(3)
    169                     msg = "ZSL(4): %.2f, MINIMAL(3): %.2f, TOL: %f" % (
    170                             snrs[j][4], snrs[j][3], SNR_TOLERANCE)
    171                     assert numpy.isclose(snrs[j][4], snrs[j][3],
    172                                          atol=SNR_TOLERANCE), msg
    173                 else:
    174                     # Verify ZSL(4) is close to OFF(0)
    175                     msg = "ZSL(4): %.2f, OFF(0): %.2f, TOL: %f" % (
    176                             snrs[j][4], snrs[j][0], SNR_TOLERANCE)
    177                     assert numpy.isclose(snrs[j][4], snrs[j][0],
    178                                          atol=SNR_TOLERANCE), msg
    179 
    180 if __name__ == "__main__":
    181     main()
    182 
    183