Home | History | Annotate | Download | only in scene1
      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 
     15 import its.image
     16 import its.caps
     17 import its.device
     18 import its.objects
     19 import its.target
     20 import numpy
     21 import os.path
     22 
     23 def main():
     24     """Test that raw streams are not croppable.
     25     """
     26     NAME = os.path.basename(__file__).split(".")[0]
     27 
     28     DIFF_THRESH = 0.05
     29     CROP_REGION_ERROR_THRESHOLD = 0.01
     30 
     31     with its.device.ItsSession() as cam:
     32         props = cam.get_camera_properties()
     33         its.caps.skip_unless(its.caps.compute_target_exposure(props) and
     34                              its.caps.raw16(props) and
     35                              its.caps.per_frame_control(props))
     36 
     37         # Calculate the active sensor region for a full (non-cropped) image.
     38         a = props['android.sensor.info.activeArraySize']
     39         ax, ay = a["left"], a["top"]
     40         aw, ah = a["right"] - a["left"], a["bottom"] - a["top"]
     41         print "Active sensor region: (%d,%d %dx%d)" % (ax, ay, aw, ah)
     42 
     43         full_region = {
     44             "left": 0,
     45             "top": 0,
     46             "right": aw,
     47             "bottom": ah
     48         }
     49 
     50         # Calculate a center crop region.
     51         zoom = min(3.0, its.objects.get_max_digital_zoom(props))
     52         assert(zoom >= 1)
     53         cropw = aw / zoom
     54         croph = ah / zoom
     55 
     56         crop_region = {
     57             "left": aw / 2 - cropw / 2,
     58             "top": ah / 2 - croph / 2,
     59             "right": aw / 2 + cropw / 2,
     60             "bottom": ah / 2 + croph / 2
     61         }
     62 
     63         # Capture without a crop region.
     64         # Use a manual request with a linear tonemap so that the YUV and RAW
     65         # should look the same (once converted by the its.image module).
     66         e, s = its.target.get_target_exposure_combos(cam)["minSensitivity"]
     67         req = its.objects.manual_capture_request(s,e, True)
     68         cap1_raw, cap1_yuv = cam.do_capture(req, cam.CAP_RAW_YUV)
     69 
     70         # Capture with a crop region.
     71         req["android.scaler.cropRegion"] = crop_region
     72         cap2_raw, cap2_yuv = cam.do_capture(req, cam.CAP_RAW_YUV)
     73 
     74         # Check the metadata related to crop regions.
     75         # When both YUV and RAW are requested, the crop region that's
     76         # applied to YUV should be reported.
     77         # Note that the crop region returned by the cropped captures doesn't
     78         # need to perfectly match the one that was requested.
     79         imgs = {}
     80         for s, cap, cr_expected, err_delta in [
     81                 ("yuv_full",cap1_yuv,full_region,0),
     82                 ("raw_full",cap1_raw,full_region,0),
     83                 ("yuv_crop",cap2_yuv,crop_region,CROP_REGION_ERROR_THRESHOLD),
     84                 ("raw_crop",cap2_raw,crop_region,CROP_REGION_ERROR_THRESHOLD)]:
     85 
     86             # Convert the capture to RGB and dump to a file.
     87             img = its.image.convert_capture_to_rgb_image(cap, props=props)
     88             its.image.write_image(img, "%s_%s.jpg" % (NAME, s))
     89             imgs[s] = img
     90 
     91             # Get the crop region that is reported in the capture result.
     92             cr_reported = cap["metadata"]["android.scaler.cropRegion"]
     93             x, y = cr_reported["left"], cr_reported["top"]
     94             w = cr_reported["right"] - cr_reported["left"]
     95             h = cr_reported["bottom"] - cr_reported["top"]
     96             print "Crop reported on %s: (%d,%d %dx%d)" % (s, x, y, w, h)
     97 
     98             # Test that the reported crop region is the same as the expected
     99             # one, for a non-cropped capture, and is close to the expected one,
    100             # for a cropped capture.
    101             ex = aw * err_delta
    102             ey = ah * err_delta
    103             assert ((abs(cr_expected["left"] - cr_reported["left"]) <= ex) and
    104                     (abs(cr_expected["right"] - cr_reported["right"]) <= ex) and
    105                     (abs(cr_expected["top"] - cr_reported["top"]) <= ey) and
    106                     (abs(cr_expected["bottom"] - cr_reported["bottom"]) <= ey))
    107 
    108         # Also check the image content; 3 of the 4 shots should match.
    109         # Note that all the shots are RGB below; the variable names correspond
    110         # to what was captured.
    111 
    112         # Shrink the YUV images 2x2 -> 1 to account for the size reduction that
    113         # the raw images went through in the RGB conversion.
    114         imgs2 = {}
    115         for s,img in imgs.iteritems():
    116             h,w,ch = img.shape
    117             if s in ["yuv_full", "yuv_crop"]:
    118                 img = img.reshape(h/2,2,w/2,2,3).mean(3).mean(1)
    119                 img = img.reshape(h/2,w/2,3)
    120             imgs2[s] = img
    121 
    122         # Strip any border pixels from the raw shots (since the raw images may
    123         # be larger than the YUV images). Assume a symmetric padded border.
    124         xpad = (imgs2["raw_full"].shape[1] - imgs2["yuv_full"].shape[1]) / 2
    125         ypad = (imgs2["raw_full"].shape[0] - imgs2["yuv_full"].shape[0]) / 2
    126         wyuv = imgs2["yuv_full"].shape[1]
    127         hyuv = imgs2["yuv_full"].shape[0]
    128         imgs2["raw_full"]=imgs2["raw_full"][ypad:ypad+hyuv:,xpad:xpad+wyuv:,::]
    129         imgs2["raw_crop"]=imgs2["raw_crop"][ypad:ypad+hyuv:,xpad:xpad+wyuv:,::]
    130         print "Stripping padding before comparison:", xpad, ypad
    131 
    132         for s,img in imgs2.iteritems():
    133             its.image.write_image(img, "%s_comp_%s.jpg" % (NAME, s))
    134 
    135         # Compute diffs between images of the same type.
    136         # The raw_crop and raw_full shots should be identical (since the crop
    137         # doesn't apply to raw images), and the yuv_crop and yuv_full shots
    138         # should be different.
    139         diff_yuv = numpy.fabs((imgs2["yuv_full"] - imgs2["yuv_crop"])).mean()
    140         diff_raw = numpy.fabs((imgs2["raw_full"] - imgs2["raw_crop"])).mean()
    141         print "YUV diff (crop vs. non-crop):", diff_yuv
    142         print "RAW diff (crop vs. non-crop):", diff_raw
    143 
    144         assert(diff_yuv > DIFF_THRESH)
    145         assert(diff_raw < DIFF_THRESH)
    146 
    147 if __name__ == '__main__':
    148     main()
    149 
    150