Home | History | Annotate | Download | only in scene1
      1 # Copyright 2016 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.image
     18 import its.objects
     19 import its.target
     20 import os.path
     21 import pylab
     22 import matplotlib
     23 import matplotlib.pyplot
     24 
     25 def main():
     26     """Capture a set of raw/yuv images with different
     27         sensitivity/post Raw sensitivity boost combination
     28         and check if the output pixel mean matches request settings
     29     """
     30     NAME = os.path.basename(__file__).split(".")[0]
     31 
     32     # Each raw image
     33     RATIO_THRESHOLD = 0.1
     34     # Waive the check if raw pixel value is below this level (signal too small
     35     # that small black level error converts to huge error in percentage)
     36     RAW_PIXEL_VAL_THRESHOLD = 0.03
     37 
     38     with its.device.ItsSession() as cam:
     39         props = cam.get_camera_properties()
     40         its.caps.skip_unless(its.caps.raw_output(props) and
     41                              its.caps.post_raw_sensitivity_boost(props) and
     42                              its.caps.compute_target_exposure(props) and
     43                              its.caps.per_frame_control(props))
     44 
     45         w,h = its.objects.get_available_output_sizes(
     46                 "yuv", props, (1920, 1080))[0]
     47 
     48         if its.caps.raw16(props):
     49             raw_format = 'raw'
     50         elif its.caps.raw10(props):
     51             raw_format = 'raw10'
     52         elif its.caps.raw12(props):
     53             raw_format = 'raw12'
     54         else: # should not reach here
     55             raise its.error.Error('Cannot find available RAW output format')
     56 
     57         out_surfaces = [{"format": raw_format},
     58                         {"format": "yuv", "width": w, "height": h}]
     59 
     60         sens_min, sens_max = props['android.sensor.info.sensitivityRange']
     61         sens_boost_min, sens_boost_max = \
     62                 props['android.control.postRawSensitivityBoostRange']
     63 
     64 
     65         e_target, s_target = \
     66                 its.target.get_target_exposure_combos(cam)["midSensitivity"]
     67 
     68         reqs = []
     69         settings = []
     70         s_boost = sens_boost_min
     71         while s_boost <= sens_boost_max:
     72             s_raw = int(round(s_target * 100.0 / s_boost))
     73             if s_raw < sens_min or s_raw > sens_max:
     74                 break
     75             req = its.objects.manual_capture_request(s_raw, e_target)
     76             req['android.control.postRawSensitivityBoost'] = s_boost
     77             reqs.append(req)
     78             settings.append((s_raw, s_boost))
     79             if s_boost == sens_boost_max:
     80                 break
     81             s_boost *= 2
     82             # Always try to test maximum sensitivity boost value
     83             if s_boost > sens_boost_max:
     84                 s_boost = sens_boost_max
     85 
     86         caps = cam.do_capture(reqs, out_surfaces)
     87 
     88         raw_rgb_means = []
     89         yuv_rgb_means = []
     90         raw_caps, yuv_caps = caps
     91         if not isinstance(raw_caps, list):
     92             raw_caps = [raw_caps]
     93         if not isinstance(yuv_caps, list):
     94             yuv_caps = [yuv_caps]
     95         for i in xrange(len(reqs)):
     96             (s, s_boost) = settings[i]
     97             raw_cap = raw_caps[i]
     98             yuv_cap = yuv_caps[i]
     99             raw_rgb = its.image.convert_capture_to_rgb_image(raw_cap, props=props)
    100             yuv_rgb = its.image.convert_capture_to_rgb_image(yuv_cap)
    101             raw_tile = its.image.get_image_patch(raw_rgb, 0.45,0.45,0.1,0.1)
    102             yuv_tile = its.image.get_image_patch(yuv_rgb, 0.45,0.45,0.1,0.1)
    103             raw_rgb_means.append(its.image.compute_image_means(raw_tile))
    104             yuv_rgb_means.append(its.image.compute_image_means(yuv_tile))
    105             its.image.write_image(raw_tile,
    106                     "%s_raw_s=%04d_boost=%04d.jpg" % (NAME,s,s_boost))
    107             its.image.write_image(yuv_tile,
    108                     "%s_yuv_s=%04d_boost=%04d.jpg" % (NAME,s,s_boost))
    109             print "s=%d, s_boost=%d: raw_means %s, yuv_means %s"%(
    110                     s,s_boost,raw_rgb_means[-1], yuv_rgb_means[-1])
    111 
    112         xs = range(len(reqs))
    113         pylab.plot(xs, [rgb[0] for rgb in raw_rgb_means], 'r')
    114         pylab.plot(xs, [rgb[1] for rgb in raw_rgb_means], 'g')
    115         pylab.plot(xs, [rgb[2] for rgb in raw_rgb_means], 'b')
    116         pylab.ylim([0,1])
    117         matplotlib.pyplot.savefig("%s_raw_plot_means.png" % (NAME))
    118         pylab.clf()
    119         pylab.plot(xs, [rgb[0] for rgb in yuv_rgb_means], 'r')
    120         pylab.plot(xs, [rgb[1] for rgb in yuv_rgb_means], 'g')
    121         pylab.plot(xs, [rgb[2] for rgb in yuv_rgb_means], 'b')
    122         pylab.ylim([0,1])
    123         matplotlib.pyplot.savefig("%s_yuv_plot_means.png" % (NAME))
    124 
    125         rgb_str = ["R", "G", "B"]
    126         # Test that raw means is about 2x brighter than next step
    127         for step in range(1, len(reqs)):
    128             (s_prev, s_boost_prev) = settings[step - 1]
    129             (s, s_boost) = settings[step]
    130             expect_raw_ratio = s_prev / float(s)
    131             raw_thres_min = expect_raw_ratio * (1 - RATIO_THRESHOLD)
    132             raw_thres_max = expect_raw_ratio * (1 + RATIO_THRESHOLD)
    133             for rgb in range(3):
    134                 ratio = raw_rgb_means[step - 1][rgb] / raw_rgb_means[step][rgb]
    135                 print ("Step (%d,%d) %s channel: %f, %f, ratio %f," +
    136                        " threshold_min %f, threshold_max %f") % (
    137                         step-1, step, rgb_str[rgb],
    138                         raw_rgb_means[step - 1][rgb],
    139                         raw_rgb_means[step][rgb],
    140                         ratio, raw_thres_min, raw_thres_max)
    141                 if (raw_rgb_means[step][rgb] <= RAW_PIXEL_VAL_THRESHOLD):
    142                     continue
    143                 assert(raw_thres_min < ratio < raw_thres_max)
    144 
    145         # Test that each yuv step is about the same bright as their mean
    146         yuv_thres_min = 1 - RATIO_THRESHOLD
    147         yuv_thres_max = 1 + RATIO_THRESHOLD
    148         for rgb in range(3):
    149             vals = [val[rgb] for val in yuv_rgb_means]
    150             for step in range(len(reqs)):
    151                 if (raw_rgb_means[step][rgb] <= RAW_PIXEL_VAL_THRESHOLD):
    152                     vals = vals[:step]
    153             mean = sum(vals) / len(vals)
    154             print "%s channel vals %s mean %f"%(rgb_str[rgb], vals, mean)
    155             for step in range(len(vals)):
    156                 ratio = vals[step] / mean
    157                 assert(yuv_thres_min < ratio < yuv_thres_max)
    158 
    159 if __name__ == '__main__':
    160     main()
    161