• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2014 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"""Verifies manual burst capture consistency."""
15
16
17import logging
18import os.path
19from matplotlib import pylab
20import matplotlib.pyplot
21from mobly import test_runner
22import numpy as np
23
24import its_base_test
25import camera_properties_utils
26import capture_request_utils
27import image_processing_utils
28import its_session_utils
29import target_exposure_utils
30
31API_LEVEL_30 = 30
32BURST_LEN = 50
33COLORS = ['R', 'G', 'B']
34NAME = os.path.splitext(os.path.basename(__file__))[0]
35NUM_BURSTS = 5
36PATCH_H = 0.1  # center 10%
37PATCH_W = 0.1
38PATCH_X = 0.5 - PATCH_W/2
39PATCH_Y = 0.5 - PATCH_H/2
40SPREAD_THRESH = 0.03
41SPREAD_THRESH_API_LEVEL_30 = 0.02
42
43NUM_FRAMES = BURST_LEN * NUM_BURSTS
44
45
46class BurstSamenessManualTest(its_base_test.ItsBaseTest):
47  """Take long bursts of images and check that they're all identical.
48
49  Assumes a static scene. Can be used to idenfity if there are sporadic
50  frames that are processed differently or have artifacts. Uses manual
51  capture settings.
52  """
53
54  def test_burst_sameness_manual(self):
55    logging.debug('Starting %s', NAME)
56    with its_session_utils.ItsSession(
57        device_id=self.dut.serial,
58        camera_id=self.camera_id,
59        hidden_physical_id=self.hidden_physical_id) as cam:
60      props = cam.get_camera_properties()
61      props = cam.override_with_hidden_physical_camera_props(props)
62      log_path = self.log_path
63
64      # check SKIP conditions
65      camera_properties_utils.skip_unless(
66          camera_properties_utils.compute_target_exposure(props) and
67          camera_properties_utils.per_frame_control(props))
68
69      # Load chart for scene
70      its_session_utils.load_scene(
71          cam, props, self.scene, self.tablet, self.chart_distance)
72
73      # Capture at the smallest resolution
74      _, fmt = capture_request_utils.get_fastest_manual_capture_settings(props)
75      e, s = target_exposure_utils.get_target_exposure_combos(
76          log_path, cam)['minSensitivity']
77      req = capture_request_utils.manual_capture_request(s, e)
78      w, h = fmt['width'], fmt['height']
79
80      # Capture bursts of YUV shots.
81      # Get the mean values of a center patch for each.
82      # Also build a 4D array, imgs, which is an array of all RGB images.
83      r_means = []
84      g_means = []
85      b_means = []
86      imgs = np.empty([NUM_FRAMES, h, w, 3])
87      for j in range(NUM_BURSTS):
88        caps = cam.do_capture([req]*BURST_LEN, [fmt])
89        for i, cap in enumerate(caps):
90          n = j*BURST_LEN + i
91          imgs[n] = image_processing_utils.convert_capture_to_rgb_image(cap)
92          patch = image_processing_utils.get_image_patch(
93              imgs[n], PATCH_X, PATCH_Y, PATCH_W, PATCH_H)
94          means = image_processing_utils.compute_image_means(patch)
95          r_means.append(means[0])
96          g_means.append(means[1])
97          b_means.append(means[2])
98
99      # Save first frame for setup debug
100      image_processing_utils.write_image(
101          imgs[0], '%s_frame000.jpg' % os.path.join(log_path, NAME))
102
103      # Save all frames if debug
104      if self.debug_mode:
105        logging.debug('Dumping all images')
106        for i in range(1, NUM_FRAMES):
107          image_processing_utils.write_image(
108              imgs[i], '%s_frame%03d.jpg'%(os.path.join(log_path, NAME), i))
109
110      # Plot RGB means vs frames
111      frames = range(NUM_FRAMES)
112      pylab.figure(NAME)
113      pylab.title(NAME)
114      pylab.plot(frames, r_means, '-ro')
115      pylab.plot(frames, g_means, '-go')
116      pylab.plot(frames, b_means, '-bo')
117      pylab.ylim([0, 1])
118      pylab.xlabel('frame number')
119      pylab.ylabel('RGB avg [0, 1]')
120      matplotlib.pyplot.savefig(
121          '%s_plot_means.png' % os.path.join(log_path, NAME))
122
123      # determine spread_thresh
124      spread_thresh = SPREAD_THRESH
125      if its_session_utils.get_first_api_level(self.dut.serial) >= API_LEVEL_30:
126        spread_thresh = SPREAD_THRESH_API_LEVEL_30
127
128      # PASS/FAIL based on center patch similarity.
129      for plane, means in enumerate([r_means, g_means, b_means]):
130        spread = max(means) - min(means)
131        msg = '%s spread: %.5f, spread_thresh: %.2f' % (
132            COLORS[plane], spread, spread_thresh)
133        logging.debug('%s', msg)
134        assert spread < spread_thresh, msg
135
136if __name__ == '__main__':
137  test_runner.main()
138
139