1# Copyright 2013 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 matplotlib
21import matplotlib.pyplot
22import numpy
23import os.path
24import pylab
25
26def main():
27    """Test that the android.noiseReduction.mode param is applied when set.
28
29    Capture images with the camera dimly lit. Uses a high analog gain to
30    ensure the captured image is noisy.
31
32    Captures three images, for NR off, "fast", and "high quality".
33    Also captures an image with low gain and NR off, and uses the variance
34    of this as the baseline.
35    """
36    NAME = os.path.basename(__file__).split(".")[0]
37
38    RELATIVE_ERROR_TOLERANCE = 0.1
39
40    # List of variances for Y,U,V.
41    variances = [[],[],[]]
42
43    # Reference (baseline) variance for each of Y,U,V.
44    ref_variance = []
45
46    nr_modes_reported = []
47
48    with its.device.ItsSession() as cam:
49        props = cam.get_camera_properties()
50        its.caps.skip_unless(its.caps.compute_target_exposure(props) and
51                             its.caps.per_frame_control(props) and
52                             its.caps.noise_reduction_mode(props, 0))
53
54        # NR mode 0 with low gain
55        e, s = its.target.get_target_exposure_combos(cam)["minSensitivity"]
56        req = its.objects.manual_capture_request(s, e)
57        req["android.noiseReduction.mode"] = 0
58        cap = cam.do_capture(req)
59        its.image.write_image(
60                its.image.convert_capture_to_rgb_image(cap),
61                "%s_low_gain.jpg" % (NAME))
62        planes = its.image.convert_capture_to_planes(cap)
63        for j in range(3):
64            img = planes[j]
65            tile = its.image.get_image_patch(img, 0.45, 0.45, 0.1, 0.1)
66            ref_variance.append(its.image.compute_image_variances(tile)[0])
67        print "Ref variances:", ref_variance
68
69        # NR modes 0, 1, 2, 3, 4 with high gain
70        for mode in range(5):
71            # Skip unavailable modes
72            if not its.caps.noise_reduction_mode(props, mode):
73                nr_modes_reported.append(mode)
74                for channel in range(3):
75                    variances[channel].append(0)
76                continue;
77
78            e, s = its.target.get_target_exposure_combos(cam)["maxSensitivity"]
79            req = its.objects.manual_capture_request(s, e)
80            req["android.noiseReduction.mode"] = mode
81            cap = cam.do_capture(req)
82            nr_modes_reported.append(
83                    cap["metadata"]["android.noiseReduction.mode"])
84            its.image.write_image(
85                    its.image.convert_capture_to_rgb_image(cap),
86                    "%s_high_gain_nr=%d.jpg" % (NAME, mode))
87            planes = its.image.convert_capture_to_planes(cap)
88            for j in range(3):
89                img = planes[j]
90                tile = its.image.get_image_patch(img, 0.45, 0.45, 0.1, 0.1)
91                variance = its.image.compute_image_variances(tile)[0]
92                variances[j].append(variance / ref_variance[j])
93        print "Variances with NR mode [0,1,2,3,4]:", variances
94
95    # Draw a plot.
96    for j in range(3):
97        pylab.plot(range(5), variances[j], "rgb"[j])
98    matplotlib.pyplot.savefig("%s_plot_variances.png" % (NAME))
99
100    assert(nr_modes_reported == [0,1,2,3,4])
101
102    for j in range(3):
103        # Smaller variance is better
104        # Verify OFF(0) is not better than FAST(1)
105        assert(variances[j][0] >
106               variances[j][1] * (1.0 - RELATIVE_ERROR_TOLERANCE))
107        # Verify FAST(1) is not better than HQ(2)
108        assert(variances[j][1] >
109               variances[j][2] * (1.0 - RELATIVE_ERROR_TOLERANCE))
110        # Verify HQ(2) is better than OFF(0)
111        assert(variances[j][0] > variances[j][2])
112        if its.caps.noise_reduction_mode(props, 3):
113            # Verify OFF(0) is not better than MINIMAL(3)
114            assert(variances[j][0] >
115                   variances[j][3] * (1.0 - RELATIVE_ERROR_TOLERANCE))
116            # Verify MINIMAL(3) is not better than HQ(2)
117            assert(variances[j][3] >
118                   variances[j][2] * (1.0 - RELATIVE_ERROR_TOLERANCE))
119            if its.caps.noise_reduction_mode(props, 4):
120                # Verify ZSL(4) is close to MINIMAL(3)
121                assert(numpy.isclose(variances[j][4], variances[j][3],
122                                     RELATIVE_ERROR_TOLERANCE))
123        elif its.caps.noise_reduction_mode(props, 4):
124            # Verify ZSL(4) is close to OFF(0)
125            assert(numpy.isclose(variances[j][4], variances[j][0],
126                                 RELATIVE_ERROR_TOLERANCE))
127
128if __name__ == '__main__':
129    main()
130
131