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
16import its.caps
17import its.device
18import its.image
19import its.objects
20import numpy as np
21
22# android.control.availableEffects
23EFFECTS = {0: 'OFF',
24           1: 'MONO',
25           2: 'NEGATIVE',
26           3: 'SOLARIZE',
27           4: 'SEPIA',
28           5: 'POSTERIZE',
29           6: 'WHITEBOARD',
30           7: 'BLACKBOARD',
31           8: 'AQUA'}
32MONO_UV_SPREAD_MAX = 2  # max spread for U & V channels [0:255] for mono image
33NAME = os.path.basename(__file__).split('.')[0]
34W, H = 640, 480
35YUV_MAX = 255.0  # normalization number for YUV images [0:1] --> [0:255]
36YUV_UV_SPREAD_MIN = 10  # min spread for U & V channels [0:255] for color image
37YUV_Y_SPREAD_MIN = 50  # min spread for Y channel [0:255] for color image
38
39
40def main():
41    """Test effects.
42
43    Test: capture frame for supported camera effects and check if generated
44    correctly. Note we only check effects OFF and MONO currently, but save
45    images for all supported effects.
46    """
47
48    print '\nStarting %s' % NAME
49    with its.device.ItsSession() as cam:
50        props = cam.get_camera_properties()
51        mono_camera = its.caps.mono_camera(props)
52        effects = props['android.control.availableEffects']
53        its.caps.skip_unless(effects != [0])
54        cam.do_3a(mono_camera=mono_camera)
55        print 'Supported effects:', effects
56        failed = []
57        for effect in effects:
58            req = its.objects.auto_capture_request()
59            req['android.control.effectMode'] = effect
60            fmt = {'format': 'yuv', 'width': W, 'height': H}
61            cap = cam.do_capture(req, fmt)
62
63            # Save image
64            img = its.image.convert_capture_to_rgb_image(cap, props=props)
65            its.image.write_image(img, '%s_%s.jpg' % (NAME, EFFECTS[effect]))
66
67            # Simple checks
68            if effect is 0:
69                print 'Checking effects OFF...'
70                y, u, v = its.image.convert_capture_to_planes(cap, props)
71                y_min, y_max = np.amin(y)*YUV_MAX, np.amax(y)*YUV_MAX
72                msg = 'Y_range:%.f,%.f THRESH:%d, ' % (
73                        y_min, y_max, YUV_Y_SPREAD_MIN)
74                if (y_max-y_min) < YUV_Y_SPREAD_MIN:
75                    failed.append({'effect': EFFECTS[effect], 'error': msg})
76                if not mono_camera:
77                    u_min, u_max = np.amin(u)*YUV_MAX, np.amax(u)*YUV_MAX
78                    v_min, v_max = np.amin(v)*YUV_MAX, np.amax(v)*YUV_MAX
79                    msg += 'U_range:%.f,%.f THRESH:%d, ' % (
80                            u_min, u_max, YUV_UV_SPREAD_MIN)
81                    msg += 'V_range:%.f,%.f THRESH:%d' % (
82                            v_min, v_max, YUV_UV_SPREAD_MIN)
83                    if ((u_max-u_min) < YUV_UV_SPREAD_MIN or
84                                (v_max-v_min) < YUV_UV_SPREAD_MIN):
85                        failed.append({'effect': EFFECTS[effect], 'error': msg})
86            if effect is 1:
87                print 'Checking MONO effect...'
88                _, u, v = its.image.convert_capture_to_planes(cap, props)
89                u_min, u_max = np.amin(u)*YUV_MAX, np.amax(u)*YUV_MAX
90                v_min, v_max = np.amin(v)*YUV_MAX, np.amax(v)*YUV_MAX
91                msg = 'U_range:%.f,%.f, ' % (u_min, u_max)
92                msg += 'V_range:%.f,%.f, TOL:%d' % (
93                        v_min, v_max, MONO_UV_SPREAD_MAX)
94                if ((u_max-u_min) > MONO_UV_SPREAD_MAX or
95                            (v_max-v_min) > MONO_UV_SPREAD_MAX):
96                    failed.append({'effect': EFFECTS[effect], 'error': msg})
97        if failed:
98            print 'Failed effects:'
99            for fail in failed:
100                print ' %s: %s' % (fail['effect'], fail['error'])
101        assert not failed
102
103
104if __name__ == '__main__':
105    main()
106