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