1# Copyright 2018 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 16 17import its.caps 18import its.device 19import its.image 20import its.objects 21import numpy as np 22 23NAME = os.path.basename(__file__).split('.')[0] 24PATTERN = 2 # Note scene0/test_test_patterns must PASS 25COLOR_BARS = ['WHITE', 'YELLOW', 'CYAN', 'GREEN', 'MAGENTA', 'RED', 26 'BLUE', 'BLACK'] 27COLOR_CHECKER = {'BLACK': [0, 0, 0], 'RED': [1, 0, 0], 'GREEN': [0, 1, 0], 28 'BLUE': [0, 0, 1], 'MAGENTA': [1, 0, 1], 'CYAN': [0, 1, 1], 29 'YELLOW': [1, 1, 0], 'WHITE': [1, 1, 1]} 30DELTA = 0.0005 # crop on edge of color bars 31RAW_TOL = 0.001 # 1 DN in [0:1] (1/(1023-64) 32RGB_VAR_TOL = 0.0039 # 1/255 33RGB_MEAN_TOL = 0.1 34TONEMAP_MAX = 0.5 35 36 37def check_raw_pattern(img_raw): 38 """Check for RAW capture matches color bar pattern. 39 40 Args: 41 img_raw: RAW image 42 """ 43 44 print 'Checking RAW/PATTERN match' 45 n_bars = len(COLOR_BARS) 46 color_match = [] 47 for i in range(n_bars): 48 print 'patch:', i, 49 raw_patch = its.image.get_image_patch( 50 img_raw, float(i)/n_bars+DELTA, 0.0, 1.0/n_bars-2*DELTA, 1.0) 51 raw_means = its.image.compute_image_means(raw_patch) 52 for color in COLOR_BARS: 53 if np.allclose(COLOR_CHECKER[color], raw_means, atol=RAW_TOL): 54 color_match.append(color) 55 print '%s' % color 56 assert set(color_match) == set(COLOR_BARS), 'RAW does not have all colors' 57 58 59def check_yuv_vs_raw(img_raw, img_yuv): 60 """Check for YUV vs RAW match in 8 patches. 61 62 Check for correct values and color consistency 63 64 Args: 65 img_raw: RAW image 66 img_yuv: YUV image 67 """ 68 69 print 'Checking YUV/RAW match' 70 n_bars = len(COLOR_BARS) 71 color_match_errs = [] 72 color_variance_errs = [] 73 for i in range(n_bars): 74 raw_patch = its.image.get_image_patch( 75 img_raw, float(i)/n_bars+DELTA, 0.0, 1.0/n_bars-2*DELTA, 1.0) 76 yuv_patch = its.image.get_image_patch( 77 img_yuv, float(i)/n_bars+DELTA, 0.0, 1.0/n_bars-2*DELTA, 1.0) 78 raw_means = np.array(its.image.compute_image_means(raw_patch)) 79 raw_vars = np.array(its.image.compute_image_variances(raw_patch)) 80 yuv_means = np.array(its.image.compute_image_means(yuv_patch)) 81 yuv_means /= TONEMAP_MAX # Normalize to tonemap max 82 yuv_vars = np.array(its.image.compute_image_variances(yuv_patch)) 83 if not np.allclose(raw_means, yuv_means, atol=RGB_MEAN_TOL): 84 color_match_errs.append('RAW: %s, RGB(norm): %s, ATOL: %.2f' % ( 85 str(raw_means), str(np.round(yuv_means, 3)), RGB_MEAN_TOL)) 86 if not np.allclose(raw_vars, yuv_vars, atol=RGB_VAR_TOL): 87 color_variance_errs.append('RAW: %s, RGB: %s, ATOL: %.4f' % ( 88 str(raw_vars), str(yuv_vars), RGB_VAR_TOL)) 89 if color_match_errs: 90 print '\nColor match errors' 91 for err in color_match_errs: 92 print err 93 if color_variance_errs: 94 print '\nColor variance errors' 95 for err in color_variance_errs: 96 print err 97 assert not color_match_errs 98 assert not color_variance_errs 99 100 101def test_tonemap_curve(cam, props): 102 """test tonemap curve with sensor test pattern. 103 104 Args: 105 cam: An open device session. 106 props: Properties of cam 107 """ 108 109 avail_patterns = props['android.sensor.availableTestPatternModes'] 110 print 'avail_patterns: ', avail_patterns 111 sens_min, _ = props['android.sensor.info.sensitivityRange'] 112 exp = min(props['android.sensor.info.exposureTimeRange']) 113 114 # Linear tonemap with maximum of 0.5 115 tmap = sum([[i/63.0, i/126.0] for i in range(64)], []) 116 117 if PATTERN in avail_patterns: 118 # RAW image 119 req_raw = its.objects.manual_capture_request(int(sens_min), exp) 120 req_raw['android.sensor.testPatternMode'] = PATTERN 121 fmt_raw = {'format': 'raw'} 122 cap_raw = cam.do_capture(req_raw, fmt_raw) 123 img_raw = its.image.convert_capture_to_rgb_image( 124 cap_raw, props=props) 125 126 # Save RAW pattern 127 its.image.write_image(img_raw, '%s_raw_%d.jpg' % ( 128 NAME, PATTERN), True) 129 check_raw_pattern(img_raw) 130 131 # YUV image 132 req_yuv = its.objects.manual_capture_request(int(sens_min), exp) 133 req_yuv['android.sensor.testPatternMode'] = PATTERN 134 req_yuv['android.distortionCorrection.mode'] = 0 135 req_yuv['android.tonemap.mode'] = 0 136 req_yuv['android.tonemap.curve'] = { 137 'red': tmap, 'green': tmap, 'blue': tmap} 138 fmt_yuv = {'format': 'yuv', 'width': 640, 'height': 480} 139 cap_yuv = cam.do_capture(req_yuv, fmt_yuv) 140 img_yuv = its.image.convert_capture_to_rgb_image(cap_yuv, True) 141 142 # Save YUV pattern 143 its.image.write_image(img_yuv, '%s_yuv_%d.jpg' % ( 144 NAME, PATTERN), True) 145 146 # Check pattern for correctness 147 check_yuv_vs_raw(img_raw, img_yuv) 148 else: 149 print 'Pattern not in android.sensor.availableTestPatternModes.' 150 assert 0 151 152 153def main(): 154 """Test conversion of test pattern from RAW to YUV. 155 156 android.sensor.testPatternMode 157 2: COLOR_BARS 158 """ 159 160 print '\nStarting %s' % NAME 161 with its.device.ItsSession() as cam: 162 props = cam.get_camera_properties() 163 its.caps.skip_unless(its.caps.raw16(props) and 164 its.caps.manual_sensor(props) and 165 its.caps.per_frame_control(props) and 166 its.caps.manual_post_proc(props)) 167 168 test_tonemap_curve(cam, props) 169 170if __name__ == '__main__': 171 main() 172