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