• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2018 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 android.control.availableEffects that are supported."""
15
16
17import logging
18import os.path
19from mobly import test_runner
20import numpy as np
21
22import its_base_test
23import camera_properties_utils
24import capture_request_utils
25import image_processing_utils
26import its_session_utils
27
28# android.control.availableEffects possible values
29EFFECTS = {0: 'OFF',
30           1: 'MONO',
31           2: 'NEGATIVE',
32           3: 'SOLARIZE',
33           4: 'SEPIA',
34           5: 'POSTERIZE',
35           6: 'WHITEBOARD',
36           7: 'BLACKBOARD',
37           8: 'AQUA'}
38MONO_UV_SPREAD_MAX = 2  # max spread for U & V channels [0:255] for mono image
39NAME = os.path.splitext(os.path.basename(__file__))[0]
40VGA_W, VGA_H = 640, 480
41YUV_MAX = 255  # normalization number for YUV images [0:1] --> [0:255]
42YUV_UV_SPREAD_ATOL = 10  # min spread for U & V channels [0:255] for color image
43YUV_Y_SPREAD_ATOL = 50  # min spread for Y channel [0:255] for color image
44
45
46class EffectsTest(its_base_test.ItsBaseTest):
47  """Test effects.
48
49  Test: capture frame for supported camera effects and check if generated
50  correctly. Note we only check effects OFF and MONO currently. Other effects
51  do not have standardized definitions, so they are not tested.
52  However, the test saves images for all supported effects.
53  """
54
55  def test_effects(self):
56    logging.debug('Starting %s', NAME)
57    with its_session_utils.ItsSession(
58        device_id=self.dut.serial,
59        camera_id=self.camera_id,
60        hidden_physical_id=self.hidden_physical_id) as cam:
61      props = cam.get_camera_properties()
62      props = cam.override_with_hidden_physical_camera_props(props)
63      mono_camera = camera_properties_utils.mono_camera(props)
64
65      # Load chart for scene.
66      its_session_utils.load_scene(
67          cam, props, self.scene, self.tablet, self.chart_distance)
68
69      # Determine available effects and run test(s)
70      effects = props['android.control.availableEffects']
71      camera_properties_utils.skip_unless(effects != [0])
72      cam.do_3a(mono_camera=mono_camera)
73      logging.debug('Supported effects: %s', str(effects))
74      failed = []
75      for effect in effects:
76        req = capture_request_utils.auto_capture_request()
77        req['android.control.effectMode'] = effect
78        fmt = {'format': 'yuv', 'width': VGA_W, 'height': VGA_H}
79        cap = cam.do_capture(req, fmt)
80
81        # Save image of each effect
82        img = image_processing_utils.convert_capture_to_rgb_image(
83            cap, props=props)
84        img_name = '%s_%s.jpg' % (os.path.join(self.log_path,
85                                               NAME), EFFECTS[effect])
86        image_processing_utils.write_image(img, img_name)
87
88        # Simple checks
89        if effect == 0:
90          logging.debug('Checking effects OFF...')
91          y, u, v = image_processing_utils.convert_capture_to_planes(cap, props)
92          y_min, y_max = np.amin(y)*YUV_MAX, np.amax(y)*YUV_MAX
93          e_msg = 'Y_range: %.2f,%.2f THRESH: %d; ' % (
94              y_min, y_max, YUV_Y_SPREAD_ATOL)
95          if (y_max-y_min) < YUV_Y_SPREAD_ATOL:
96            failed.append({'effect': EFFECTS[effect], 'error': e_msg})
97          if not mono_camera:
98            u_min, u_max = np.amin(u) * YUV_MAX, np.amax(u) * YUV_MAX
99            v_min, v_max = np.amin(v) * YUV_MAX, np.amax(v) * YUV_MAX
100            e_msg += 'U_range: %.2f,%.2f THRESH: %d; ' % (
101                u_min, u_max, YUV_UV_SPREAD_ATOL)
102            e_msg += 'V_range: %.2f,%.2f THRESH: %d' % (
103                v_min, v_max, YUV_UV_SPREAD_ATOL)
104            if ((u_max - u_min) < YUV_UV_SPREAD_ATOL or
105                (v_max - v_min) < YUV_UV_SPREAD_ATOL):
106              failed.append({'effect': EFFECTS[effect], 'error': e_msg})
107        elif effect == 1:
108          logging.debug('Checking MONO effect...')
109          _, u, v = image_processing_utils.convert_capture_to_planes(cap, props)
110          u_min, u_max = np.amin(u)*YUV_MAX, np.amax(u)*YUV_MAX
111          v_min, v_max = np.amin(v)*YUV_MAX, np.amax(v)*YUV_MAX
112          e_msg = 'U_range: %.2f,%.2f; V_range: %.2f,%.2f; TOL: %d' % (
113              u_min, u_max, v_min, v_max, MONO_UV_SPREAD_MAX)
114          if ((u_max - u_min) > MONO_UV_SPREAD_MAX or
115              (v_max - v_min) > MONO_UV_SPREAD_MAX):
116            failed.append({'effect': EFFECTS[effect], 'error': e_msg})
117      if failed:
118        logging.debug('Failed effects:')
119        for fail in failed:
120          logging.debug(' %s: %s', fail['effect'], fail['error'])
121        raise AssertionError(f'{NAME} failed. See test_log.DEBUG for errors.')
122
123if __name__ == '__main__':
124  test_runner.main()
125