summaryrefslogtreecommitdiff
path: root/apps/CameraITS/tests/scene1/test_param_shading_mode.py
blob: a5f85ca7a02ddc82cfbbce50a78a2867d16871fc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
# Copyright 2015 The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import os

import its.caps
import its.device
import its.image
import its.objects

import matplotlib
from matplotlib import pylab
import numpy

NAME = os.path.basename(__file__).split('.')[0]
NUM_FRAMES = 4  # number of frames for temporal info to settle
NUM_SHADING_MODE_SWITCH_LOOPS = 3
SHADING_MODES = ['OFF', 'FAST', 'HQ']
THRESHOLD_DIFF_RATIO = 0.15


def main():
    """Test that the android.shading.mode param is applied.

    Switching shading modes and checks that the lens shading maps are
    modified as expected.
    """

    with its.device.ItsSession() as cam:
        props = cam.get_camera_properties()

        its.caps.skip_unless(its.caps.per_frame_control(props) and
                             its.caps.lsc_map(props) and
                             its.caps.lsc_off(props))

        mono_camera = its.caps.mono_camera(props)

        # lsc_off devices should always support OFF(0), FAST(1), and HQ(2)
        assert(props.has_key('android.shading.availableModes') and
               set(props['android.shading.availableModes']) == set([0, 1, 2]))

        # Test 1: Switching shading modes several times and verify:
        #   1. Lens shading maps with mode OFF are all 1.0
        #   2. Lens shading maps with mode FAST are similar after switching
        #      shading modes.
        #   3. Lens shading maps with mode HIGH_QUALITY are similar after
        #      switching shading modes.
        cam.do_3a(mono_camera=mono_camera)

        # Use smallest yuv size matching the aspect ratio of largest yuv size to
        # reduce some USB bandwidth overhead since we are only looking at output
        # metadata in this test.
        largest_yuv_fmt = its.objects.get_largest_yuv_format(props)
        largest_yuv_size = (largest_yuv_fmt['width'], largest_yuv_fmt['height'])
        cap_fmt = its.objects.get_smallest_yuv_format(props, largest_yuv_size)

        # Get the reference lens shading maps for OFF, FAST, and HIGH_QUALITY
        # in different sessions.
        # reference_maps[mode]
        num_shading_modes = len(SHADING_MODES)
        reference_maps = [[] for mode in range(num_shading_modes)]
        num_map_gains = 0
        for mode in range(1, num_shading_modes):
            req = its.objects.auto_capture_request()
            req['android.statistics.lensShadingMapMode'] = 1
            req['android.shading.mode'] = mode
            cap_res = cam.do_capture([req]*NUM_FRAMES, cap_fmt)[NUM_FRAMES-1]['metadata']
            lsc_map = cap_res['android.statistics.lensShadingCorrectionMap']
            assert(lsc_map.has_key('width') and
                   lsc_map.has_key('height') and
                   lsc_map['width'] is not None and
                   lsc_map['height'] is not None)
            if mode == 1:
                num_map_gains = lsc_map['width'] * lsc_map['height'] * 4
                reference_maps[0] = [1.0] * num_map_gains
            reference_maps[mode] = lsc_map['map']

        # Get the lens shading maps while switching modes in one session.
        reqs = []
        for i in range(NUM_SHADING_MODE_SWITCH_LOOPS):
            for mode in range(num_shading_modes):
                for _ in range(NUM_FRAMES):
                    req = its.objects.auto_capture_request()
                    req['android.statistics.lensShadingMapMode'] = 1
                    req['android.shading.mode'] = mode
                    reqs.append(req)

        caps = cam.do_capture(reqs, cap_fmt)

        # shading_maps[mode][loop]
        shading_maps = [[[] for loop in range(NUM_SHADING_MODE_SWITCH_LOOPS)]
                        for mode in range(num_shading_modes)]

        # Get the shading maps out of capture results
        for i in range(len(caps)/NUM_FRAMES):
            shading_maps[i%num_shading_modes][i/NUM_SHADING_MODE_SWITCH_LOOPS] = \
                    caps[(i+1)*NUM_FRAMES-1]['metadata']['android.statistics.lensShadingCorrectionMap']['map']

        # Draw the maps
        for mode in range(num_shading_modes):
            for i in range(NUM_SHADING_MODE_SWITCH_LOOPS):
                pylab.clf()
                pylab.figure(figsize=(5, 5))
                pylab.subplot(2, 1, 1)
                pylab.plot(range(num_map_gains), shading_maps[mode][i], '-r.',
                           label='shading', alpha=0.7)
                pylab.plot(range(num_map_gains), reference_maps[mode], '-g.',
                           label='ref', alpha=0.7)
                pylab.xlim([0, num_map_gains])
                pylab.ylim([0.9, 4.0])
                name = '%s_ls_maps_mode_%d_loop_%d' % (NAME, mode, i)
                pylab.title(name)
                pylab.xlabel('Map gains')
                pylab.ylabel('Lens shading maps')
                pylab.legend(loc='upper center', numpoints=1, fancybox=True)

                pylab.subplot(2, 1, 2)
                shading_ref_ratio = numpy.divide(
                        shading_maps[mode][i], reference_maps[mode])
                pylab.plot(range(num_map_gains), shading_ref_ratio, '-b.',
                           clip_on=False)
                pylab.xlim([0, num_map_gains])
                pylab.ylim([1.0-THRESHOLD_DIFF_RATIO, 1.0+THRESHOLD_DIFF_RATIO])
                pylab.title('Shading/reference Maps Ratio vs Gain')
                pylab.xlabel('Map gains')
                pylab.ylabel('Shading/ref maps ratio')

                pylab.tight_layout()
                matplotlib.pyplot.savefig('%s.png' % name)

        for mode in range(num_shading_modes):
            if mode == 0:
                print 'Verifying lens shading maps with mode %s are all 1.0' % (
                        SHADING_MODES[mode])
            else:
                print 'Verifying lens shading maps with mode %s are similar' % (
                        SHADING_MODES[mode])
            for i in range(NUM_SHADING_MODE_SWITCH_LOOPS):
                e_msg = 'FAIL mode: %s, loop: %d, THRESH: %.2f' % (
                        SHADING_MODES[mode], i, THRESHOLD_DIFF_RATIO)
                assert (numpy.allclose(shading_maps[mode][i],
                                       reference_maps[mode],
                                       rtol=THRESHOLD_DIFF_RATIO)), e_msg

if __name__ == '__main__':
    main()