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
15import os.path
16
17import its.caps
18import its.device
19import its.image
20import its.objects
21import its.target
22
23import numpy as np
24NAME = os.path.basename(__file__).split('.')[0]
25PATCH_SIZE = 0.0625  # 1/16 x 1/16 in center of image
26PATCH_LOC = (1-PATCH_SIZE)/2
27THRESH_DIFF = 0.06
28THRESH_GAIN = 0.1
29THRESH_EXP = 0.05
30
31
32def main():
33    """Test both cameras give similar RBG values for gray patch."""
34
35    yuv_sizes = {}
36    with its.device.ItsSession() as cam:
37        props = cam.get_camera_properties()
38        its.caps.skip_unless(its.caps.compute_target_exposure(props) and
39                             its.caps.per_frame_control(props) and
40                             its.caps.logical_multi_camera(props) and
41                             its.caps.raw16(props) and
42                             its.caps.manual_sensor(props))
43        ids = its.caps.logical_multi_camera_physical_ids(props)
44        s, e, _, _, f = cam.do_3a(get_results=True)
45        req = its.objects.manual_capture_request(s, e, f)
46        max_raw_size = its.objects.get_available_output_sizes('raw', props)[0]
47        for i in ids:
48            physical_props = cam.get_camera_properties_by_id(i)
49            yuv_sizes[i] = its.objects.get_available_output_sizes(
50                    'yuv', physical_props, match_ar_size=max_raw_size)
51            if i == ids[0]:
52                yuv_match_sizes = yuv_sizes[i]
53            else:
54                list(set(yuv_sizes[i]).intersection(yuv_match_sizes))
55        yuv_match_sizes.sort()
56        w = yuv_match_sizes[-1][0]
57        h = yuv_match_sizes[-1][1]
58        print 'RAW size: (%d, %d)' % (max_raw_size[0], max_raw_size[1])
59        print 'YUV size: (%d, %d)' % (w, h)
60
61        # capture YUVs
62        out_surfaces = [{'format': 'raw'},
63                        {'format': 'yuv', 'width': w, 'height': h,
64                         'physicalCamera': ids[0]},
65                        {'format': 'yuv', 'width': w, 'height': h,
66                         'physicalCamera': ids[1]}]
67        cap_raw, cap_yuv1, cap_yuv2 = cam.do_capture(req, out_surfaces)
68
69        img_raw = its.image.convert_capture_to_rgb_image(cap_raw, props=props)
70        its.image.write_image(img_raw, '%s_raw.jpg' % NAME)
71        rgb_means_raw = its.image.compute_image_means(
72                its.image.get_image_patch(img_raw, PATCH_LOC, PATCH_LOC,
73                                          PATCH_SIZE, PATCH_SIZE))
74
75        img_yuv1 = its.image.convert_capture_to_rgb_image(
76                cap_yuv1, props=props)
77        its.image.write_image(img_yuv1, '%s_yuv1.jpg' % NAME)
78        y1, _, _ = its.image.convert_capture_to_planes(
79                cap_yuv1, props=props)
80        y1_mean = its.image.compute_image_means(
81                its.image.get_image_patch(y1, PATCH_LOC, PATCH_LOC,
82                                          PATCH_SIZE, PATCH_SIZE))[0]
83
84        img_yuv2 = its.image.convert_capture_to_rgb_image(
85                cap_yuv2, props=props)
86        its.image.write_image(img_yuv2, '%s_yuv2.jpg' % NAME)
87        y2, _, _ = its.image.convert_capture_to_planes(
88                cap_yuv2, props=props)
89        y2_mean = its.image.compute_image_means(
90                its.image.get_image_patch(y2, PATCH_LOC, PATCH_LOC,
91                                          PATCH_SIZE, PATCH_SIZE))[0]
92        print 'rgb_raw:', rgb_means_raw
93        print 'y1_mean:', y1_mean
94        print 'y2_mean:', y2_mean
95
96        # assert gain/exp values are near written values
97        s_yuv1 = cap_yuv1['metadata']['android.sensor.sensitivity']
98        e_yuv1 = cap_yuv1['metadata']['android.sensor.exposureTime']
99        msg = 'yuv_gain(write): %d, (read): %d' % (s, s_yuv1)
100        assert 0 <= s - s_yuv1 < s * THRESH_GAIN, msg
101        msg = 'yuv_exp(write): %.3fms, (read): %.3fms' % (e*1E6, e_yuv1*1E6)
102        assert 0 <= e - e_yuv1 < e * THRESH_EXP, msg
103
104        # compare YUVs
105        msg = 'y1: %.3f, y2: %.3f, TOL=%.5f' % (y1_mean, y2_mean, THRESH_DIFF)
106        assert np.isclose(y1_mean, y2_mean, rtol=THRESH_DIFF), msg
107
108
109if __name__ == '__main__':
110    main()
111