• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2023 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 that autoframing can adjust fov to include all faces with different
15skin tones."""
16
17
18import logging
19import os.path
20
21from mobly import test_runner
22
23import its_base_test
24import camera_properties_utils
25import capture_request_utils
26import image_processing_utils
27import its_session_utils
28import opencv_processing_utils
29
30_CV2_FACE_SCALE_FACTOR = 1.05  # 5% step for resizing image to find face
31_CV2_FACE_MIN_NEIGHBORS = 4  # recommended 3-6: higher for less faces
32_NUM_TEST_FRAMES = 20
33_NUM_FACES = 3
34_W, _H = 640, 480
35
36
37class AutoframingTest(its_base_test.ItsBaseTest):
38  """Test autoframing for faces with different skin tones.
39  """
40
41  def test_autoframing(self):
42    """Test if fov gets adjusted to accommodate all the faces in the frame.
43
44    Do a large zoom on scene2_a using do_3a so that none of that faces are
45    visible initially, trigger autoframing, wait for the state to converge and
46    make sure all the faces are found.
47    """
48    with its_session_utils.ItsSession(
49        device_id=self.dut.serial,
50        camera_id=self.camera_id,
51        hidden_physical_id=self.hidden_physical_id) as cam:
52      props = cam.get_camera_properties()
53      props = cam.override_with_hidden_physical_camera_props(props)
54
55      # Load chart for scene
56      its_session_utils.load_scene(
57          cam, props, self.scene, self.tablet, self.chart_distance,
58          log_path=self.log_path)
59
60      # Check SKIP conditions
61      # Don't run autoframing if face detection or autoframing is not supported
62      camera_properties_utils.skip_unless(
63          camera_properties_utils.face_detect(props) and
64          camera_properties_utils.autoframing(props))
65
66      # Do max-ish zoom with the help of do_3a, keeping all the 'A's off. This
67      # zooms into the scene so that none of the faces are in the view
68      # initially - which gives room for autoframing to take place.
69      max_zoom_ratio = camera_properties_utils.get_max_digital_zoom(props)
70      cam.do_3a(do_af=False, zoom_ratio=max_zoom_ratio)
71      cam.do_autoframing(zoom_ratio=max_zoom_ratio)
72
73      req = capture_request_utils.auto_capture_request(
74          do_autoframing=True, zoom_ratio=max_zoom_ratio)
75      req['android.statistics.faceDetectMode'] = 1  # Simple
76      fmt = {'format': 'yuv', 'width': _W, 'height': _H}
77      caps = cam.do_capture([req]*_NUM_TEST_FRAMES, fmt)
78      for i, cap in enumerate(caps):
79        faces = cap['metadata']['android.statistics.faces']
80        # Face detection and autoframing could take several frames to warm up,
81        # but should detect the correct number of faces in last frame
82        if i == _NUM_TEST_FRAMES - 1:
83          num_faces_found = len(faces)
84          if num_faces_found != _NUM_FACES:
85            raise AssertionError('Wrong num of faces found! Found: '
86                                 f'{num_faces_found}, expected: {_NUM_FACES}')
87
88          # Also check the faces with open cv to make sure the scene is not
89          # distored or anything.
90          img = image_processing_utils.convert_capture_to_rgb_image(
91              cap, props=props)
92          opencv_faces = opencv_processing_utils.find_opencv_faces(
93              img, _CV2_FACE_SCALE_FACTOR, _CV2_FACE_MIN_NEIGHBORS)
94          num_opencv_faces = len(opencv_faces)
95          if num_opencv_faces != _NUM_FACES:
96            raise AssertionError('Wrong num of faces found with OpenCV! Found: '
97                                 f'{num_opencv_faces}, expected: {_NUM_FACES}')
98
99        if not faces:
100          continue
101        logging.debug('Frame %d face metadata:', i)
102        logging.debug('Faces: %s', str(faces))
103
104
105if __name__ == '__main__':
106  test_runner.main()
107