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 # --------------------------------------------------------------------------- # 16 # The Google Python style guide should be used for scripts: # 17 # http://google-styleguide.googlecode.com/svn/trunk/pyguide.html # 18 # --------------------------------------------------------------------------- # 19 20 # The ITS modules that are in the pymodules/its/ directory. To see formatted 21 # docs, use the "pydoc" command: 22 # 23 # > pydoc its.image 24 # 25 import its.image 26 import its.device 27 import its.objects 28 import its.target 29 30 # Standard Python modules. 31 import os.path 32 import pprint 33 import math 34 35 # Modules from the numpy, scipy, and matplotlib libraries. These are used for 36 # the image processing code, and images are represented as numpy arrays. 37 from matplotlib import pylab 38 import numpy 39 import matplotlib 40 import matplotlib.pyplot 41 42 # Each script has a "main" function. 43 def main(): 44 45 # Each script has a string description of what it does. This is the first 46 # entry inside the main function. 47 """Tutorial script to show how to use the ITS infrastructure. 48 """ 49 50 # A convention in each script is to use the filename (without the extension) 51 # as the name of the test, when printing results to the screen or dumping 52 # files. 53 NAME = os.path.basename(__file__).split(".")[0] 54 55 # The standard way to open a session with a connected camera device. This 56 # creates a cam object which encapsulates the session and which is active 57 # within the scope of the "with" block; when the block exits, the camera 58 # session is closed. 59 with its.device.ItsSession() as cam: 60 61 # Get the static properties of the camera device. Returns a Python 62 # associative array object; print it to the console. 63 props = cam.get_camera_properties() 64 pprint.pprint(props) 65 66 # Grab a YUV frame with manual exposure of sensitivity = 200, exposure 67 # duration = 50ms. 68 req = its.objects.manual_capture_request(200, 50*1000*1000) 69 cap = cam.do_capture(req) 70 71 # Print the properties of the captured frame; width and height are 72 # integers, and the metadata is a Python associative array object. 73 print "Captured image width:", cap["width"] 74 print "Captured image height:", cap["height"] 75 pprint.pprint(cap["metadata"]) 76 77 # The captured image is YUV420. Convert to RGB, and save as a file. 78 rgbimg = its.image.convert_capture_to_rgb_image(cap) 79 its.image.write_image(rgbimg, "%s_rgb_1.jpg" % (NAME)) 80 81 # Can also get the Y,U,V planes separately; save these to greyscale 82 # files. 83 yimg,uimg,vimg = its.image.convert_capture_to_planes(cap) 84 its.image.write_image(yimg, "%s_y_plane_1.jpg" % (NAME)) 85 its.image.write_image(uimg, "%s_u_plane_1.jpg" % (NAME)) 86 its.image.write_image(vimg, "%s_v_plane_1.jpg" % (NAME)) 87 88 # Run 3A on the device. In this case, just use the entire image as the 89 # 3A region, and run each of AWB,AE,AF. Can also change the region and 90 # specify independently for each of AE,AWB,AF whether it should run. 91 # 92 # NOTE: This may fail, if the camera isn't pointed at a reasonable 93 # target scene. If it fails, the script will end. The logcat messages 94 # can be inspected to see the status of 3A running on the device. 95 # 96 # > adb logcat -s 'ItsService:v' 97 # 98 # If this keeps on failing, try also rebooting the device before 99 # running the test. 100 sens, exp, gains, xform, focus = cam.do_3a(get_results=True) 101 print "AE: sensitivity %d, exposure %dms" % (sens, exp/1000000.0) 102 print "AWB: gains", gains, "transform", xform 103 print "AF: distance", focus 104 105 # Grab a new manual frame, using the 3A values, and convert it to RGB 106 # and save it to a file too. Note that the "req" object is just a 107 # Python dictionary that is pre-populated by the its.objets module 108 # functions (in this case a default manual capture), and the key/value 109 # pairs in the object can be used to set any field of the capture 110 # request. Here, the AWB gains and transform (CCM) are being used. 111 # Note that the CCM transform is in a rational format in capture 112 # requests, meaning it is an object with integer numerators and 113 # denominators. The 3A routine returns simple floats instead, however, 114 # so a conversion from float to rational must be performed. 115 req = its.objects.manual_capture_request(sens, exp) 116 xform_rat = its.objects.float_to_rational(xform) 117 118 req["android.colorCorrection.transform"] = xform_rat 119 req["android.colorCorrection.gains"] = gains 120 cap = cam.do_capture(req) 121 rgbimg = its.image.convert_capture_to_rgb_image(cap) 122 its.image.write_image(rgbimg, "%s_rgb_2.jpg" % (NAME)) 123 124 # Print out the actual capture request object that was used. 125 pprint.pprint(req) 126 127 # Images are numpy arrays. The dimensions are (h,w,3) when indexing, 128 # in the case of RGB images. Greyscale images are (h,w,1). Pixels are 129 # generally float32 values in the [0,1] range, however some of the 130 # helper functions in its.image deal with the packed YUV420 and other 131 # formats of images that come from the device (and convert them to 132 # float32). 133 # Print the dimensions of the image, and the top-left pixel value, 134 # which is an array of 3 floats. 135 print "RGB image dimensions:", rgbimg.shape 136 print "RGB image top-left pixel:", rgbimg[0,0] 137 138 # Grab a center tile from the image; this returns a new image. Save 139 # this tile image. In this case, the tile is the middle 10% x 10% 140 # rectangle. 141 tile = its.image.get_image_patch(rgbimg, 0.45, 0.45, 0.1, 0.1) 142 its.image.write_image(tile, "%s_rgb_2_tile.jpg" % (NAME)) 143 144 # Compute the mean values of the center tile image. 145 rgb_means = its.image.compute_image_means(tile) 146 print "RGB means:", rgb_means 147 148 # Apply a lookup table to the image, and save the new version. The LUT 149 # is basically a tonemap, and can be used to implement a gamma curve. 150 # In this case, the LUT is used to double the value of each pixel. 151 lut = numpy.array([2*i for i in xrange(65536)]) 152 rgbimg_lut = its.image.apply_lut_to_image(rgbimg, lut) 153 its.image.write_image(rgbimg_lut, "%s_rgb_2_lut.jpg" % (NAME)) 154 155 # Apply a 3x3 matrix to the image, and save the new version. The matrix 156 # is a numpy array, in row major order, and the pixel values are right- 157 # multiplied to it (when considered as column vectors). The example 158 # matrix here just boosts the blue channel by 10%. 159 mat = numpy.array([[1, 0, 0 ], 160 [0, 1, 0 ], 161 [0, 0, 1.1]]) 162 rgbimg_mat = its.image.apply_matrix_to_image(rgbimg, mat) 163 its.image.write_image(rgbimg_mat, "%s_rgb_2_mat.jpg" % (NAME)) 164 165 # Compute a histogram of the luma image, in 256 buckets. 166 yimg,_,_ = its.image.convert_capture_to_planes(cap) 167 hist,_ = numpy.histogram(yimg*255, 256, (0,256)) 168 169 # Plot the histogram using matplotlib, and save as a PNG image. 170 pylab.plot(range(256), hist.tolist()) 171 pylab.xlabel("Luma DN") 172 pylab.ylabel("Pixel count") 173 pylab.title("Histogram of luma channel of captured image") 174 matplotlib.pyplot.savefig("%s_histogram.png" % (NAME)) 175 176 # Capture a frame to be returned as a JPEG. Load it as an RGB image, 177 # then save it back as a JPEG. 178 cap = cam.do_capture(req, cam.CAP_JPEG) 179 rgbimg = its.image.convert_capture_to_rgb_image(cap) 180 its.image.write_image(rgbimg, "%s_jpg.jpg" % (NAME)) 181 r,g,b = its.image.convert_capture_to_planes(cap) 182 its.image.write_image(r, "%s_r.jpg" % (NAME)) 183 184 # This is the standard boilerplate in each test that allows the script to both 185 # be executed directly and imported as a module. 186 if __name__ == '__main__': 187 main() 188 189