| # Copyright 2013 The Android Open Source Project |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| |
| import its.image |
| import its.device |
| import its.objects |
| import pylab |
| import os.path |
| import matplotlib |
| import matplotlib.pyplot |
| import numpy |
| |
| def main(): |
| """Black level consistence test. |
| |
| Test: capture dark frames and check if black level correction is done |
| correctly. |
| 1. Black level should be roughly consistent for repeating shots. |
| 2. Noise distribution should be roughly centered at black level. |
| |
| Shoot with the camera covered (i.e.) dark/black. The test varies the |
| sensitivity parameter. |
| """ |
| NAME = os.path.basename(__file__).split(".")[0] |
| |
| NUM_REPEAT = 3 |
| NUM_STEPS = 3 |
| |
| # Only check the center part where LSC has little effects. |
| R = 200 |
| |
| # The most frequent pixel value in each image; assume this is the black |
| # level, since the images are all dark (shot with the lens covered). |
| ymodes = [] |
| umodes = [] |
| vmodes = [] |
| |
| with its.device.ItsSession() as cam: |
| props = cam.get_camera_properties() |
| sens_range = props['android.sensor.info.sensitivityRange'] |
| sens_step = (sens_range[1] - sens_range[0]) / float(NUM_STEPS-1) |
| sensitivities = [sens_range[0] + i*sens_step for i in range(NUM_STEPS)] |
| print "Sensitivities:", sensitivities |
| |
| for si, s in enumerate(sensitivities): |
| for rep in xrange(NUM_REPEAT): |
| req = its.objects.manual_capture_request(100, 1*1000*1000) |
| req["android.blackLevel.lock"] = True |
| req["android.sensor.sensitivity"] = s |
| cap = cam.do_capture(req) |
| yimg,uimg,vimg = its.image.convert_capture_to_planes(cap) |
| w = cap["width"] |
| h = cap["height"] |
| |
| # Magnify the noise in saved images to help visualize. |
| its.image.write_image(yimg * 2, |
| "%s_s=%05d_y.jpg" % (NAME, s), True) |
| its.image.write_image(numpy.absolute(uimg - 0.5) * 2, |
| "%s_s=%05d_u.jpg" % (NAME, s), True) |
| |
| yimg = yimg[w/2-R:w/2+R, h/2-R:h/2+R] |
| uimg = uimg[w/4-R/2:w/4+R/2, w/4-R/2:w/4+R/2] |
| vimg = vimg[w/4-R/2:w/4+R/2, w/4-R/2:w/4+R/2] |
| yhist,_ = numpy.histogram(yimg*255, 256, (0,256)) |
| ymodes.append(numpy.argmax(yhist)) |
| uhist,_ = numpy.histogram(uimg*255, 256, (0,256)) |
| umodes.append(numpy.argmax(uhist)) |
| vhist,_ = numpy.histogram(vimg*255, 256, (0,256)) |
| vmodes.append(numpy.argmax(vhist)) |
| |
| # Take 32 bins from Y, U, and V. |
| # Histograms of U and V are cropped at the center of 128. |
| pylab.plot(range(32), yhist.tolist()[0:32], 'rgb'[si]) |
| pylab.plot(range(32), uhist.tolist()[112:144], 'rgb'[si]+'--') |
| pylab.plot(range(32), vhist.tolist()[112:144], 'rgb'[si]+'--') |
| |
| pylab.xlabel("DN: Y[0:32], U[112:144], V[112:144]") |
| pylab.ylabel("Pixel count") |
| pylab.title("Histograms for different sensitivities") |
| matplotlib.pyplot.savefig("%s_plot_histograms.png" % (NAME)) |
| |
| print "Y black levels:", ymodes |
| print "U black levels:", umodes |
| print "V black levels:", vmodes |
| |
| if __name__ == '__main__': |
| main() |
| |