1# Copyright 2014 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 16import its.caps 17import its.device 18import its.image 19import its.objects 20import its.target 21import numpy 22 23NAME = os.path.basename(__file__).split(".")[0] 24# A list of 5 regions, specified in normalized (x,y,w,h) coords. 25# The regions correspond to: TL, TR, BL, BR, CENT 26REGIONS = [(0.0, 0.0, 0.5, 0.5), 27 (0.5, 0.0, 0.5, 0.5), 28 (0.0, 0.5, 0.5, 0.5), 29 (0.5, 0.5, 0.5, 0.5), 30 (0.25, 0.25, 0.5, 0.5)] 31 32 33def main(): 34 """Test that crop regions work.""" 35 36 with its.device.ItsSession() as cam: 37 props = cam.get_camera_properties() 38 its.caps.skip_unless(its.caps.compute_target_exposure(props) and 39 its.caps.freeform_crop(props) and 40 its.caps.per_frame_control(props)) 41 42 a = props["android.sensor.info.activeArraySize"] 43 ax, ay = a["left"], a["top"] 44 aw, ah = a["right"] - a["left"], a["bottom"] - a["top"] 45 e, s = its.target.get_target_exposure_combos(cam)["minSensitivity"] 46 print "Active sensor region (%d,%d %dx%d)" % (ax, ay, aw, ah) 47 48 # Uses a 2x digital zoom. 49 assert its.objects.get_max_digital_zoom(props) >= 2 50 51 # Capture a full frame. 52 req = its.objects.manual_capture_request(s, e) 53 cap_full = cam.do_capture(req) 54 img_full = its.image.convert_capture_to_rgb_image(cap_full) 55 wfull, hfull = cap_full["width"], cap_full["height"] 56 its.image.write_image( 57 img_full, "%s_full_%dx%d.jpg" % (NAME, wfull, hfull)) 58 59 # Capture a burst of crop region frames. 60 # Note that each region is 1/2x1/2 of the full frame, and is digitally 61 # zoomed into the full size output image, so must be downscaled (below) 62 # by 2x when compared to a tile of the full image. 63 reqs = [] 64 for x, y, w, h in REGIONS: 65 req = its.objects.manual_capture_request(s, e) 66 req["android.scaler.cropRegion"] = { 67 "top": int(ah * y), 68 "left": int(aw * x), 69 "right": int(aw * (x + w)), 70 "bottom": int(ah * (y + h))} 71 reqs.append(req) 72 caps_regions = cam.do_capture(reqs) 73 match_failed = False 74 for i, cap in enumerate(caps_regions): 75 a = cap["metadata"]["android.scaler.cropRegion"] 76 ax, ay = a["left"], a["top"] 77 aw, ah = a["right"] - a["left"], a["bottom"] - a["top"] 78 79 # Match this crop image against each of the five regions of 80 # the full image, to find the best match (which should be 81 # the region that corresponds to this crop image). 82 img_crop = its.image.convert_capture_to_rgb_image(cap) 83 img_crop = its.image.downscale_image(img_crop, 2) 84 its.image.write_image(img_crop, "%s_crop%d.jpg" % (NAME, i)) 85 min_diff = None 86 min_diff_region = None 87 for j, (x, y, w, h) in enumerate(REGIONS): 88 tile_full = its.image.get_image_patch(img_full, x, y, w, h) 89 wtest = min(tile_full.shape[1], aw) 90 htest = min(tile_full.shape[0], ah) 91 tile_full = tile_full[0:htest:, 0:wtest:, ::] 92 tile_crop = img_crop[0:htest:, 0:wtest:, ::] 93 its.image.write_image( 94 tile_full, "%s_fullregion%d.jpg" % (NAME, j)) 95 diff = numpy.fabs(tile_full - tile_crop).mean() 96 if min_diff is None or diff < min_diff: 97 min_diff = diff 98 min_diff_region = j 99 if i != min_diff_region: 100 match_failed = True 101 print "Crop image %d (%d,%d %dx%d) best match with region %d"%( 102 i, ax, ay, aw, ah, min_diff_region) 103 104 assert not match_failed 105 106if __name__ == "__main__": 107 main() 108 109