1# Copyright 2016 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
16import cv2
17
18import its.caps
19import its.cv2image
20import its.device
21import its.image
22import its.objects
23import numpy as np
24
25NAME = os.path.basename(__file__).split('.')[0]
26CHART_FILE = os.path.join(os.environ['CAMERA_ITS_TOP'], 'pymodules', 'its',
27                          'test_images', 'ISO12233.png')
28CHART_ORIENTATIONS = ['nominal', 'flip', 'mirror', 'rotate']
29VGA_WIDTH = 640
30VGA_HEIGHT = 480
31(X_CROP, Y_CROP) = (0.5, 0.5)  # crop center area of ISO12233 chart
32
33
34def test_flip_mirror(cam, props, fmt, chart):
35    """Return if image is flipped or mirrored.
36
37    Args:
38        cam (class): An open device session
39        props (class): Properties of cam
40        fmt (dict): Capture format
41        chart (class): Object with chart properties
42
43    Returns:
44        boolean: True if flipped, False if not
45    """
46
47    # determine if monochrome camera
48    mono_camera = its.caps.mono_camera(props)
49
50    # determine if in debug mode
51    debug = its.caps.debug_mode()
52
53    # get a local copy of the chart template
54    template = cv2.imread(CHART_FILE, cv2.IMREAD_ANYDEPTH)
55
56    # take img, crop chart, scale and prep for cv2 template match
57    s, e, _, _, fd = cam.do_3a(get_results=True, mono_camera=mono_camera)
58    req = its.objects.manual_capture_request(s, e, fd)
59    cap = cam.do_capture(req, fmt)
60    y, _, _ = its.image.convert_capture_to_planes(cap, props)
61    y = its.image.rotate_img_per_argv(y)
62    patch = its.image.get_image_patch(y, chart.xnorm, chart.ynorm,
63                                      chart.wnorm, chart.hnorm)
64    patch = 255 * its.cv2image.gray_scale_img(patch)
65    patch = its.cv2image.scale_img(patch.astype(np.uint8), chart.scale)
66
67    # validity check on image
68    assert np.max(patch)-np.min(patch) > 255/8
69
70    # save full images if in debug
71    if debug:
72        its.image.write_image(template[:, :, np.newaxis]/255.0,
73                              '%s_template.jpg' % NAME)
74
75    # save patch
76    its.image.write_image(patch[:, :, np.newaxis]/255.0,
77                          '%s_scene_patch.jpg' % NAME)
78
79    # crop center areas and strip off any extra rows/columns
80    template = its.image.get_image_patch(template, (1-X_CROP)/2, (1-Y_CROP)/2,
81                                         X_CROP, Y_CROP)
82    patch = its.image.get_image_patch(patch, (1-X_CROP)/2,
83                                      (1-Y_CROP)/2, X_CROP, Y_CROP)
84    patch = patch[0:min(patch.shape[0], template.shape[0]),
85                  0:min(patch.shape[1], template.shape[1])]
86    comp_chart = patch
87
88    # determine optimum orientation
89    opts = []
90    for orientation in CHART_ORIENTATIONS:
91        if orientation == 'flip':
92            comp_chart = np.flipud(patch)
93        elif orientation == 'mirror':
94            comp_chart = np.fliplr(patch)
95        elif orientation == 'rotate':
96            comp_chart = np.flipud(np.fliplr(patch))
97        correlation = cv2.matchTemplate(comp_chart, template, cv2.TM_CCOEFF)
98        _, opt_val, _, _ = cv2.minMaxLoc(correlation)
99        if debug:
100            cv2.imwrite('%s_%s.jpg' % (NAME, orientation), comp_chart)
101        print ' %s correlation value: %d' % (orientation, opt_val)
102        opts.append(opt_val)
103
104    # determine if 'nominal' or 'rotated' is best orientation
105    assert_flag = (opts[0] == max(opts) or opts[3] == max(opts))
106    assert assert_flag, ('Optimum orientation is %s' %
107                         CHART_ORIENTATIONS[np.argmax(opts)])
108    # print warning if rotated
109    if opts[3] == max(opts):
110        print 'Image is rotated 180 degrees. Try "rotate" flag.'
111
112
113def main():
114    """Test if image is properly oriented."""
115
116    print '\nStarting test_flip_mirror.py'
117
118    # check skip conditions
119    with its.device.ItsSession() as cam:
120        props = cam.get_camera_properties()
121        its.caps.skip_unless(its.caps.read_3a(props))
122    # initialize chart class and locate chart in scene
123    chart = its.cv2image.Chart()
124
125    with its.device.ItsSession() as cam:
126        fmt = {'format': 'yuv', 'width': VGA_WIDTH, 'height': VGA_HEIGHT}
127
128        # test that image is not flipped, mirrored, or rotated
129        test_flip_mirror(cam, props, fmt, chart)
130
131
132if __name__ == '__main__':
133    main()
134