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