1# Copyright 2015 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 its.image
16import its.caps
17import its.device
18import its.objects
19import its.target
20import math
21import matplotlib
22import matplotlib.pyplot
23import numpy
24import os.path
25from matplotlib import pylab
26
27
28def test_edge_mode(cam, edge_mode, sensitivity, exp, fd, out_surface,
29                   reprocess_format=None):
30    """Return sharpness of the output image and the capture result metadata
31       for a capture request with the given edge mode, sensitivity, exposure
32       time, focus distance, output surface parameter, and reprocess format
33       (None for a regular request.)
34
35    Args:
36        cam: An open device session.
37        edge_mode: Edge mode for the request as defined in android.edge.mode
38        sensitivity: Sensitivity for the request as defined in
39            android.sensor.sensitivity
40        exp: Exposure time for the request as defined in
41            android.sensor.exposureTime.
42        fd: Focus distance for the request as defined in
43            android.lens.focusDistance
44        output_surface: Specifications of the output image format and size.
45        reprocess_format: (Optional) The reprocessing format. If not None,
46                reprocessing will be enabled.
47
48    Returns:
49        Object containing reported edge mode and the sharpness of the output
50        image, keyed by the following strings:
51            "edge_mode"
52            "sharpness"
53    """
54
55    NAME = os.path.basename(__file__).split(".")[0]
56    NUM_SAMPLES = 4
57
58    req = its.objects.manual_capture_request(sensitivity, exp)
59    req["android.lens.focusDistance"] = fd
60    req["android.edge.mode"] = edge_mode
61    if (reprocess_format != None):
62        req["android.reprocess.effectiveExposureFactor"] = 1.0
63
64    sharpness_list = []
65    for n in range(NUM_SAMPLES):
66        cap = cam.do_capture(req, out_surface, reprocess_format)
67        img = its.image.convert_capture_to_rgb_image(cap)
68        if n == 0:
69            its.image.write_image(img, "%s_reprocess_fmt_%s_edge=%d.jpg" %
70                (NAME, reprocess_format, edge_mode))
71            res_edge_mode = cap["metadata"]["android.edge.mode"]
72        tile = its.image.get_image_patch(img, 0.45, 0.45, 0.1, 0.1)
73        sharpness_list.append(its.image.compute_image_sharpness(tile))
74
75    ret = {}
76    ret["edge_mode"] = res_edge_mode
77    ret["sharpness"] = numpy.mean(sharpness_list)
78
79    return ret
80
81def main():
82    """Test that the android.edge.mode param is applied when set for
83       reprocessing requests.
84
85    Capture non-reprocess images for each edge mode and calculate their
86    sharpness as a baseline.
87
88    Capture reprocessed images for each supported reprocess format and edge_mode
89    mode. Calculate the sharpness of reprocessed images and compare them against
90    the sharpess of non-reprocess images.
91    """
92
93    THRESHOLD_RELATIVE_SHARPNESS_DIFF = 0.15
94
95    with its.device.ItsSession() as cam:
96        props = cam.get_camera_properties()
97
98        its.caps.skip_unless(its.caps.read_3a(props) and
99                             its.caps.per_frame_control(props) and
100                             its.caps.edge_mode(props, 0) and
101                             (its.caps.yuv_reprocess(props) or
102                              its.caps.private_reprocess(props)))
103
104        # If reprocessing is supported, ZSL EE mode must be avaiable.
105        assert(its.caps.edge_mode(props, 3))
106
107        reprocess_formats = []
108        if (its.caps.yuv_reprocess(props)):
109            reprocess_formats.append("yuv")
110        if (its.caps.private_reprocess(props)):
111            reprocess_formats.append("private")
112
113        size = its.objects.get_available_output_sizes("jpg", props)[0]
114        out_surface = {"width":size[0], "height":size[1], "format":"jpg"}
115
116        # Get proper sensitivity, exposure time, and focus distance.
117        s,e,_,_,fd = cam.do_3a(get_results=True)
118
119        # Get the sharpness for each edge mode for regular requests
120        sharpness_regular = []
121        edge_mode_reported_regular = []
122        for edge_mode in range(4):
123            # Skip unavailable modes
124            if not its.caps.edge_mode(props, edge_mode):
125                edge_mode_reported_regular.append(edge_mode)
126                sharpness_regular.append(0)
127                continue
128            ret = test_edge_mode(cam, edge_mode, s, e, fd, out_surface)
129            edge_mode_reported_regular.append(ret["edge_mode"])
130            sharpness_regular.append(ret["sharpness"])
131
132        print "Reported edge modes:", edge_mode_reported_regular
133        print "Sharpness with EE mode [0,1,2,3]:", sharpness_regular
134
135        # Get the sharpness for each reprocess format and edge mode for
136        # reprocess requests.
137        sharpnesses_reprocess = []
138        edge_mode_reported_reprocess = []
139
140        for reprocess_format in reprocess_formats:
141            # List of sharpness
142            sharpnesses = []
143            edge_mode_reported = []
144            for edge_mode in range(4):
145                # Skip unavailable modes
146                if not its.caps.edge_mode(props, edge_mode):
147                    edge_mode_reported.append(edge_mode)
148                    sharpnesses.append(0)
149                    continue
150
151                ret = test_edge_mode(cam, edge_mode, s, e, fd, out_surface,
152                    reprocess_format)
153                edge_mode_reported.append(ret["edge_mode"])
154                sharpnesses.append(ret["sharpness"])
155
156            sharpnesses_reprocess.append(sharpnesses)
157            edge_mode_reported_reprocess.append(edge_mode_reported)
158
159            print "Reported edge modes:", edge_mode_reported
160            print "Sharpness with EE mode [0,1,2,3] for %s reprocess:" % \
161                (reprocess_format) , sharpnesses
162
163
164        # Verify HQ(2) is sharper than OFF(0)
165        assert(sharpness_regular[2] > sharpness_regular[0])
166
167        # Verify ZSL(3) is similar to OFF(0)
168        assert(numpy.isclose(sharpness_regular[3], sharpness_regular[0],
169                             THRESHOLD_RELATIVE_SHARPNESS_DIFF))
170
171        # Verify OFF(0) is not sharper than FAST(1)
172        assert(sharpness_regular[1] >
173               sharpness_regular[0] * (1.0 - THRESHOLD_RELATIVE_SHARPNESS_DIFF))
174
175        # Verify FAST(1) is not sharper than HQ(2)
176        assert(sharpness_regular[2] >
177               sharpness_regular[1] * (1.0 - THRESHOLD_RELATIVE_SHARPNESS_DIFF))
178
179        for reprocess_format in range(len(reprocess_formats)):
180            # Verify HQ(2) is sharper than OFF(0)
181            assert(sharpnesses_reprocess[reprocess_format][2] >
182                   sharpnesses_reprocess[reprocess_format][0])
183
184            # Verify ZSL(3) is similar to OFF(0)
185            assert(numpy.isclose(sharpnesses_reprocess[reprocess_format][3],
186                                 sharpnesses_reprocess[reprocess_format][0],
187                                 THRESHOLD_RELATIVE_SHARPNESS_DIFF))
188
189            # Verify OFF(0) is not sharper than FAST(1)
190            assert(sharpnesses_reprocess[reprocess_format][1] >
191                   sharpnesses_reprocess[reprocess_format][0] *
192                   (1.0 - THRESHOLD_RELATIVE_SHARPNESS_DIFF))
193
194            # Verify FAST(1) is not sharper than HQ(2)
195            assert(sharpnesses_reprocess[reprocess_format][2] >
196                   sharpnesses_reprocess[reprocess_format][1] *
197                   (1.0 - THRESHOLD_RELATIVE_SHARPNESS_DIFF))
198
199            # Verify reprocessing HQ(2) is similar to regular HQ(2) relative to
200            # OFF(0)
201            assert(numpy.isclose(sharpnesses_reprocess[reprocess_format][2] /
202                                    sharpnesses_reprocess[reprocess_format][0],
203                                 sharpness_regular[2] / sharpness_regular[0],
204                                 THRESHOLD_RELATIVE_SHARPNESS_DIFF))
205
206if __name__ == '__main__':
207    main()
208
209