• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 os.path
20import numpy
21import matplotlib.pyplot
22
23# Required for 3d plot to work
24import mpl_toolkits.mplot3d
25
26def main():
27    """Test that valid data comes back in CaptureResult objects.
28    """
29    global NAME, auto_req, manual_req, w_map, h_map
30    global manual_tonemap, manual_transform, manual_gains, manual_region
31    global manual_exp_time, manual_sensitivity, manual_gains_ok
32
33    NAME = os.path.basename(__file__).split(".")[0]
34
35    with its.device.ItsSession() as cam:
36        props = cam.get_camera_properties()
37        its.caps.skip_unless(its.caps.manual_sensor(props) and
38                             its.caps.manual_post_proc(props) and
39                             its.caps.per_frame_control(props))
40
41        manual_tonemap = [0,0, 1,1] # Linear
42        manual_transform = its.objects.float_to_rational(
43                [-1.5,-1.0,-0.5, 0.0,0.5,1.0, 1.5,2.0,3.0])
44        manual_gains = [1,1.5,2.0,3.0]
45        manual_region = [{"x":8,"y":8,"width":128,"height":128,"weight":1}]
46        manual_exp_time = min(props['android.sensor.info.exposureTimeRange'])
47        manual_sensitivity = min(props['android.sensor.info.sensitivityRange'])
48
49        # The camera HAL may not support different gains for two G channels.
50        manual_gains_ok = [[1,1.5,2.0,3.0],[1,1.5,1.5,3.0],[1,2.0,2.0,3.0]]
51
52        auto_req = its.objects.auto_capture_request()
53        auto_req["android.statistics.lensShadingMapMode"] = 1
54
55        manual_req = {
56            "android.control.mode": 0,
57            "android.control.aeMode": 0,
58            "android.control.awbMode": 0,
59            "android.control.afMode": 0,
60            "android.sensor.sensitivity": manual_sensitivity,
61            "android.sensor.exposureTime": manual_exp_time,
62            "android.colorCorrection.mode": 0,
63            "android.colorCorrection.transform": manual_transform,
64            "android.colorCorrection.gains": manual_gains,
65            "android.tonemap.mode": 0,
66            "android.tonemap.curve": {"red": manual_tonemap,
67                                      "green": manual_tonemap,
68                                      "blue": manual_tonemap},
69            "android.control.aeRegions": manual_region,
70            "android.control.afRegions": manual_region,
71            "android.control.awbRegions": manual_region,
72            "android.statistics.lensShadingMapMode":1
73            }
74
75        print "Testing auto capture results"
76        lsc_map_auto = test_auto(cam, props)
77        print "Testing manual capture results"
78        test_manual(cam, lsc_map_auto, props)
79        print "Testing auto capture results again"
80        test_auto(cam, props)
81
82# A very loose definition for two floats being close to each other;
83# there may be different interpolation and rounding used to get the
84# two values, and all this test is looking at is whether there is
85# something obviously broken; it's not looking for a perfect match.
86def is_close_float(n1, n2):
87    return abs(n1 - n2) < 0.05
88
89def is_close_rational(n1, n2):
90    return is_close_float(its.objects.rational_to_float(n1),
91                          its.objects.rational_to_float(n2))
92
93def draw_lsc_plot(w_map, h_map, lsc_map, name):
94    for ch in range(4):
95        fig = matplotlib.pyplot.figure()
96        ax = fig.gca(projection='3d')
97        xs = numpy.array([range(w_map)] * h_map).reshape(h_map, w_map)
98        ys = numpy.array([[i]*w_map for i in range(h_map)]).reshape(
99                h_map, w_map)
100        zs = numpy.array(lsc_map[ch::4]).reshape(h_map, w_map)
101        ax.plot_wireframe(xs, ys, zs)
102        matplotlib.pyplot.savefig("%s_plot_lsc_%s_ch%d.png"%(NAME,name,ch))
103
104def test_auto(cam, props):
105    # Get 3A lock first, so the auto values in the capture result are
106    # populated properly.
107    rect = [[0,0,1,1,1]]
108    mono_camera = its.caps.mono_camera(props)
109    cam.do_3a(rect, rect, rect, do_af=False, mono_camera=mono_camera)
110
111    cap = cam.do_capture(auto_req)
112    cap_res = cap["metadata"]
113
114    gains = cap_res["android.colorCorrection.gains"]
115    transform = cap_res["android.colorCorrection.transform"]
116    exp_time = cap_res['android.sensor.exposureTime']
117    lsc_obj = cap_res["android.statistics.lensShadingCorrectionMap"]
118    lsc_map = lsc_obj["map"]
119    w_map = lsc_obj["width"]
120    h_map = lsc_obj["height"]
121    ctrl_mode = cap_res["android.control.mode"]
122
123    print "Control mode:", ctrl_mode
124    print "Gains:", gains
125    print "Transform:", [its.objects.rational_to_float(t)
126                         for t in transform]
127    if props["android.control.maxRegionsAe"] > 0:
128        print "AE region:", cap_res['android.control.aeRegions']
129    if props["android.control.maxRegionsAf"] > 0:
130        print "AF region:", cap_res['android.control.afRegions']
131    if props["android.control.maxRegionsAwb"] > 0:
132        print "AWB region:", cap_res['android.control.awbRegions']
133    print "LSC map:", w_map, h_map, lsc_map[:8]
134
135    assert(ctrl_mode == 1)
136
137    # Color correction gain and transform must be valid.
138    assert(len(gains) == 4)
139    assert(len(transform) == 9)
140    assert(all([g > 0 for g in gains]))
141    assert(all([t["denominator"] != 0 for t in transform]))
142
143    # Color correction should not match the manual settings.
144    assert(any([not is_close_float(gains[i], manual_gains[i])
145                for i in xrange(4)]))
146    assert(any([not is_close_rational(transform[i], manual_transform[i])
147                for i in xrange(9)]))
148
149    # Exposure time must be valid.
150    assert(exp_time > 0)
151
152    # Lens shading map must be valid.
153    assert(w_map > 0 and h_map > 0 and w_map * h_map * 4 == len(lsc_map))
154    assert(all([m >= 1 for m in lsc_map]))
155
156    draw_lsc_plot(w_map, h_map, lsc_map, "auto")
157
158    return lsc_map
159
160def test_manual(cam, lsc_map_auto, props):
161    cap = cam.do_capture(manual_req)
162    cap_res = cap["metadata"]
163
164    gains = cap_res["android.colorCorrection.gains"]
165    transform = cap_res["android.colorCorrection.transform"]
166    curves = [cap_res["android.tonemap.curve"]["red"],
167              cap_res["android.tonemap.curve"]["green"],
168              cap_res["android.tonemap.curve"]["blue"]]
169    exp_time = cap_res['android.sensor.exposureTime']
170    lsc_obj = cap_res["android.statistics.lensShadingCorrectionMap"]
171    lsc_map = lsc_obj["map"]
172    w_map = lsc_obj["width"]
173    h_map = lsc_obj["height"]
174    ctrl_mode = cap_res["android.control.mode"]
175
176    print "Control mode:", ctrl_mode
177    print "Gains:", gains
178    print "Transform:", [its.objects.rational_to_float(t)
179                         for t in transform]
180    print "Tonemap:", curves[0][1::16]
181    if props["android.control.maxRegionsAe"] > 0:
182        print "AE region:", cap_res['android.control.aeRegions']
183    if props["android.control.maxRegionsAf"] > 0:
184        print "AF region:", cap_res['android.control.afRegions']
185    if props["android.control.maxRegionsAwb"] > 0:
186        print "AWB region:", cap_res['android.control.awbRegions']
187    print "LSC map:", w_map, h_map, lsc_map[:8]
188
189    assert(ctrl_mode == 0)
190
191    # Color correction gain and transform must be valid.
192    # Color correction gains and transform should be the same size and
193    # values as the manually set values.
194    assert(len(gains) == 4)
195    assert(len(transform) == 9)
196    assert( all([is_close_float(gains[i], manual_gains_ok[0][i])
197                 for i in xrange(4)]) or
198            all([is_close_float(gains[i], manual_gains_ok[1][i])
199                 for i in xrange(4)]) or
200            all([is_close_float(gains[i], manual_gains_ok[2][i])
201                 for i in xrange(4)]))
202    assert(all([is_close_rational(transform[i], manual_transform[i])
203                for i in xrange(9)]))
204
205    # Tonemap must be valid.
206    # The returned tonemap must be linear.
207    for c in curves:
208        assert(len(c) > 0)
209        assert(all([is_close_float(c[i], c[i+1])
210                    for i in xrange(0,len(c),2)]))
211
212    # Exposure time must be close to the requested exposure time.
213    assert(is_close_float(exp_time/1000000.0, manual_exp_time/1000000.0))
214
215    # Lens shading map must be valid.
216    assert(w_map > 0 and h_map > 0 and w_map * h_map * 4 == len(lsc_map))
217    assert(all([m >= 1 for m in lsc_map]))
218
219    draw_lsc_plot(w_map, h_map, lsc_map, "manual")
220
221if __name__ == '__main__':
222    main()
223
224