Ruben Brunk | 370e243 | 2014-10-14 18:33:23 -0700 | [diff] [blame] | 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 | 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 | # multipled 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 buckeits. |
| 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 | |