PIL provides a nice function to retrieve the EXIF data from an image file. It is a 'hidden' function and it seems to work fairly well. I don't know how well it works with manufacturer specific information however.
To access the EXIF data, simply open an image with PIL:
from PIL import Image
im=Image.open('./someImage')
to get the EXIF data, simply call this function:
exifData=im._getexif()
This will produce a dictionary, exifData, with various numbers as the keys that store some EXIF data value. To help understand what those numbers are, PIL has a list to relate the numbers to words:
from PIL.ExifTags import TAGS
Which if you print the dictionary TAGS, it looks something like this:
4096: 'RelatedImageFileFormat', 513: 'JpegIFOffset', 514: 'JpegIFByteCount', 40963: 'ExifImageHeight', 36868: 'DateTimeDigitized', 37381: 'MaxApertureValue', 37382: 'SubjectDistance', 4097: 'RelatedImageWidth', 37384: 'LightSource', 37385: 'Flash', 37386: 'FocalLength', 37387: 'FlashEnergy', 37388: 'SpatialFrequencyResponse'...
It could then be possible to use the EXIF information to rename your images with something more useful.
Saturday, November 10, 2012
Sunday, September 30, 2012
Image Stacking: Using Filters
Now that we have played with the most basic image stacking, we can start to think of interesting ways to accentuate certain aspects of an image. For example, if we want to capture stars we want to preserve the brightness of the star. If we simply perform the previous averaging, one bright pixel averaged with 100 other dark pixels will result in a dark pixel. PIL happens to have an interesting function that will compare to images and return a new image with the brightest pixels from both input images:
If we use this on a series of images, comparing the next image to the result image, we essentially create an image of the brightest pixels from the image series. This can be accomplished in python by using code along these lines:
Using an image series (ISS030-E-271717-ISS030-E-271798) from over here and the above code generates this image:
from PIL import ImageChops resultIm = ImageChops.lighter(im1,im2)
If we use this on a series of images, comparing the next image to the result image, we essentially create an image of the brightest pixels from the image series. This can be accomplished in python by using code along these lines:
from PIL import Image, ImageChops import glob imgList = glob.glob('./*.jpg') resultIm = Image.open(imgList[0]) for i in range(1,len(imgList)): tempIm = Image.open(imgList[i]) resultIm = ImageChops.lighter(resultIm, tempIm) resultIm.show()
Using an image series (ISS030-E-271717-ISS030-E-271798) from over here and the above code generates this image:
Images courtesy of the Image Science & Analysis Laboratory, NASA Johnson Space Center
Tuesday, September 25, 2012
Image Stacking: Averaging
Image stacking using python is fast, efficient, and allows for custom filtering during the stacking process. Why would you want to stack images? Well, it allows for "manual long exposures" as instead of letting the camera's shutter stay open for long time periods, you can take multiple photos in series and stack the images together. The other advantage is that you can apply different stacking techniques such as bringing out the bright spots in an image to produce star trails.
So, how do we do this in python? Essentially the easiest stacking is to simply add up all the pixel values for all the desired images, and divide by the number of images, creating an average image. Building on our knowledge of PIL we can write a script starting with importing the required libraries:
find all the images in a folder, in this case *.png files:
Next we create a loop to loop through all the pictures we found however, we need to know if it is the first image to intialize the summed image variable:
Now for the tricky part. Notice how we imported numpy. The problem with using the PIL image class is that the data type for the RGB pixels values are unit8, or a value between 0 and 255. If the resulting value exceeds 255, then it restarts from 0 (i.e. 140+210=94). This is known as an overflow and will change the pixel color. to overcome this issue we will convert the PIL image to a numpy array:
Then change the data type of the array.There are several options for data types. Lets try to pick on logically. Suppose we have 1000 photos. The maximum value for one photo is 255. Therefore we need a data type that will handle a number of 1000*255 = 255,000. So uint32 should do the trick (0 to 4294967295)
to float:
next, we have to either 1) create a new variable to hold the sum or 2) add the current image to the summed image:
now we calculate the averaged image by dividing the summed image by the number of images:
we have to convert back to the unit8 data type, then back into the PIL image class:
Finally using what we learned previously, we can show, save, etc...
Bringing it all back together:
Image Example:
I didn't have a 'real world' example so I made a quick scene in blender of several balls drooping. I rendered 127 images at 24 fps. The first one looks like this:
Images ISS030-E-271717 to ISS030-E-271798:
Images ISS031-E-57221 to ISS031-E-57490:
I think I could do a couple things to make better images. Ill have to give it a shot. There also seem to be a lot of noise. i don't know if the noise is from the actual images or my algorithm? I would assume averaging the photos would eliminate the noise.
So, how do we do this in python? Essentially the easiest stacking is to simply add up all the pixel values for all the desired images, and divide by the number of images, creating an average image. Building on our knowledge of PIL we can write a script starting with importing the required libraries:
from PIL import Image import glob import numpy as np
find all the images in a folder, in this case *.png files:
imgList = glob.glob('./*.png')
Next we create a loop to loop through all the pictures we found however, we need to know if it is the first image to intialize the summed image variable:
first = True for img in imgList:
Now for the tricky part. Notice how we imported numpy. The problem with using the PIL image class is that the data type for the RGB pixels values are unit8, or a value between 0 and 255. If the resulting value exceeds 255, then it restarts from 0 (i.e. 140+210=94). This is known as an overflow and will change the pixel color. to overcome this issue we will convert the PIL image to a numpy array:
temp = np.asarray(Image.open(img))
Then change the data type of the array.There are several options for data types. Lets try to pick on logically. Suppose we have 1000 photos. The maximum value for one photo is 255. Therefore we need a data type that will handle a number of 1000*255 = 255,000. So uint32 should do the trick (0 to 4294967295)
to float:
temp = temp.astype('uint32')
next, we have to either 1) create a new variable to hold the sum or 2) add the current image to the summed image:
if first: sumImage = temp first = False else: sumImage = sumImage + temp
now we calculate the averaged image by dividing the summed image by the number of images:
avgArray = sumImage/len(imgList)
we have to convert back to the unit8 data type, then back into the PIL image class:
avgImg = Image.fromarray(avgArray.astype('uint8'))
Finally using what we learned previously, we can show, save, etc...
avgImg.show()
Bringing it all back together:
from PIL import Image
import glob
import numpy as np
imgList = glob.glob('./*.png')
first = True
for img in imgList:
temp = np.asarray(Image.open(img))
temp = temp.astype('uint32')
if first:
sumImage = temp
first = False
else:
sumImage = sumImage + temp
avgArray = sumImage/len(imgList)
avgImg = Image.fromarray(avgArray.astype('uint8'))
avgImg.show()
Image Example:
I didn't have a 'real world' example so I made a quick scene in blender of several balls drooping. I rendered 127 images at 24 fps. The first one looks like this:
You can see the effect of sample rate on the averaging 1) all the frames, 2) every 10th frame, and 3) every 20th frame:
It is possible to modify the code and subtract frames:
and multiply frames:
I stumbled upon this awesome NASA website. The following images have been stacked with the above code. Images courtesy of the Image Science & Analysis Laboratory, NASA Johnson Space Center. Thanks for providing those images. They are great!
Images ISS031-E-66034 to ISS031-E-66136:
Images ISS030-E-68896 to ISS030-E-69180:
Images ISS030-E-271717 to ISS030-E-271798:
Images ISS031-E-57221 to ISS031-E-57490:
I think I could do a couple things to make better images. Ill have to give it a shot. There also seem to be a lot of noise. i don't know if the noise is from the actual images or my algorithm? I would assume averaging the photos would eliminate the noise.
Sunday, September 23, 2012
PIL Introduction, Batch Image Converting
PIL or the Python Imaging Library, is a library designed to add imaging processing capabilities to python. PIL supports a variety of image formats including: PNG, JPEG, TIFF, as well as many others.
Note: The examples here apply to Python 2.7 and PIL 1.1.7
To open an image using PIL, we use the PIL's Image module (in an interactive shell, or python script):
There are some useful attributes of the image class such as:
We can now use this instance to do a variety of tasks such as showing the image:
Rotating the image counter clockwise at an angle specified in degrees, creating a new image instance of the rotated image:
Re-sizing the image, preserving the aspect ratio:
Re-sizing the image, not preserving the aspect ratio:
Cropping the image by providing a cropping box in terms of (Left, Upper, Right, Lower) in terms of pixels, this also returns a new image instance:
Finally, saving the resulting image as jpeg (indicated by the file extension):
Bringing these concepts together along with some core python functions, we can write a simple script (i.e. batchImgConvert.py) to convert all the *.jpg files in a giving folder to *.png files:
Once you have this mastered, then the sky is the limit. You can use the commands described above to batch rotate, resize, and crop. There are many more functions available in PIL, which will be covered later.
To give you a more complex example that I used to answer a question on the photography stack exchange:
Note: The examples here apply to Python 2.7 and PIL 1.1.7
To open an image using PIL, we use the PIL's Image module (in an interactive shell, or python script):
>>> from PIL import Image >>> im=Image.open('./example.JPG')Where './example.JPG' is the image path. This creates an PIL instance of the specified image, im.
There are some useful attributes of the image class such as:
>>> im.size (3872, 2592) >>> im.format 'JPEG' >>> im.mode 'RGB'
We can now use this instance to do a variety of tasks such as showing the image:
>>> im.show()
Rotating the image counter clockwise at an angle specified in degrees, creating a new image instance of the rotated image:
>>> im2=im.rotate(45)
Re-sizing the image, preserving the aspect ratio:
>>> im.thumbnail([128,128])This will re-size the maximum dimension, preserving the aspect ratio. To control the interpolation scheme of the re-size, you can pass a filter argument such as NEAREST, BILINEAR, BICUBIC, or ANTIALIAS (the best quality):
>>> im.thumbnail([128,128],Image.ANTIALIAS)
Re-sizing the image, not preserving the aspect ratio:
>>> im.resize([128,128])You can also change the interpolation scheme:
>>> im.resize([128,128],Image.ANTIALIAS)
Cropping the image by providing a cropping box in terms of (Left, Upper, Right, Lower) in terms of pixels, this also returns a new image instance:
>>> im3=im.crop([10,40,400,350])
Finally, saving the resulting image as jpeg (indicated by the file extension):
>>> im.save('./exampleOut.jpg')You may also explicitly tell the function what format to save it in (int his case, as png image):
>>> im.save('./exampleOut', 'PNG')Note: This will not automatically append the file extension to the file name.
Bringing these concepts together along with some core python functions, we can write a simple script (i.e. batchImgConvert.py) to convert all the *.jpg files in a giving folder to *.png files:
#import require libraries from PIL import Image import glob import os
# Find all the jpegs in a given folder: folder='C:/exampleImages/' imList=glob.glob(folder+'*.jpg')
# Loop through all the image: for img in imList: # open the image im = Image.open(img) # extract the filename and extension from path fileName, fileExt = os.path.splitext(img) # save the image in the same folder, with the same name, except *.png im.save(folder+fileName+'.png')
Once you have this mastered, then the sky is the limit. You can use the commands described above to batch rotate, resize, and crop. There are many more functions available in PIL, which will be covered later.
To give you a more complex example that I used to answer a question on the photography stack exchange:
#Python 2.7, PIL 1.1.7 import Image import glob import os #Function to resize image, preserving aspect ratio def resizeAspect(im, size): w,h = im.size aspect=min(size[0]/float(w), size[1]/float(h)) return im.resize((int(w*aspect),int(h*aspect)),Image.ANTIALIAS) #Find all png images in a directory imgList=glob.glob('C:/icons/*.png') #Loop through all found images for img in imgList: #open the image im = Image.open(img) print "resizing:",os.path.basename(img) #Get image width and height w,h = im.size #Check if either dimension is smaller then 600 if min(w,h)<600: #Re-size Image im=resizeAspect(im,(600,600)) #update image size w,h = im.size #Calculate Center center = [int(w/2.0),int(h/2.0)] #Defines a box where you want it to be cropped box = (center[0]-300, center[1]-300, center[0]+300, center[1]+300) #Crop the image croppedIm = im.crop(box) fileName, fileExtension=os.path.splitext(img) #Save the cropped image croppedIm.save(fileName+'_crop.png', "PNG")
Tuesday, September 18, 2012
Intro to Python
Python is an awesome cross platform opensource language that allows for quick development of anything from simple scripts to fully functional programs. There are numerous libraries that can perform just about any task you would ever need to do, from accessing your gmail account to high performance computing on the worlds largest super computers.
You can download the official python source and installers here. At the present, I would install the latest 2.x series which is 2.7.3. There is a 3.x series, with the latest development being 3.2.3, however not every library officially supports the new 3.x series, which has made some significant changes. As this is a blog focused on the use of python for photographers, the library PIL (Python Imaging Library) will be constantly used. Unfortunately, PIL does not officially support the python 3.x series.
Several import libraries to get working on your machine:
Play with the above code examples, exploring what the commands are doing. If you can master these commands, then we can start writing useful code!
You can download the official python source and installers here. At the present, I would install the latest 2.x series which is 2.7.3. There is a 3.x series, with the latest development being 3.2.3, however not every library officially supports the new 3.x series, which has made some significant changes. As this is a blog focused on the use of python for photographers, the library PIL (Python Imaging Library) will be constantly used. Unfortunately, PIL does not officially support the python 3.x series.
Several import libraries to get working on your machine:
Note: If you are using a windows machine I would highly suggest using Christoph Gohlke's windows installers for the libraries that you are interested in.
Assuming that you have python installed, try opening the IDLE (python shell). You should see something like:
This is 2.7.2 on windows 7.
If so, your good to start writing python code. Note: you essentially will be creating text files with a *.py extension so any text editor will work for writing python code. There are also other IDEs you can use. A list is maintained here.
You can also access python through the command line by typing python (if your path variables are setup correctly):
So, if you have python up and running try out the following code:
>>> print 'Hello, World' Hello, World >>> x=200 >>> print x 200 >>> x="foo bar" >>> print x foo bar >>> x=10 >>> y=100 >>> z=x*y >>> print z 1000 >>> x='Print Me' >>> for i in x: print i P r i n t M e >>> x=range(10) >>> print x [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> for i in range(5): print i 0 1 2 3 4 >>> a=list() >>> for i in 'Dude': a.append(i) >>> print a ['D', 'u', 'd', 'e']
Play with the above code examples, exploring what the commands are doing. If you can master these commands, then we can start writing useful code!
Monday, September 17, 2012
Test Post
Test post
import PIL print 'Does this work?' print "How about this?" for i in range(10): print iI followed this example of how to get blogger to perform code highlighting.
Subscribe to:
Posts (Atom)