tag:blogger.com,1999:blog-70703500966438654072024-03-13T21:13:37.075-07:00Python for Photographersonlyjushttp://www.blogger.com/profile/14236929826206309645noreply@blogger.comBlogger6125tag:blogger.com,1999:blog-7070350096643865407.post-5813056413155989442012-11-10T09:57:00.003-08:002012-11-10T09:58:09.100-08:00Getting EXIF DataPIL 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.<br />
<br />
To access the EXIF data, simply open an image with PIL:<br />
from PIL import Image<br />
<br />
im=Image.open('./someImage')<br />
<br />
to get the EXIF data, simply call this function:<br />
<br />
exifData=im._getexif()<br />
<br />
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:<br />
<br />
from PIL.ExifTags import TAGS<br />
<br />
Which if you print the dictionary TAGS, it looks something like this:<br />
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'...<br />
<br />
It could then be possible to use the EXIF information to rename your images with something more useful.onlyjushttp://www.blogger.com/profile/14236929826206309645noreply@blogger.com0tag:blogger.com,1999:blog-7070350096643865407.post-46529336765351919342012-09-30T15:53:00.001-07:002012-09-30T15:53:06.135-07:00Image Stacking: Using FiltersNow 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:<br />
<br />
<pre class="prettyprint">from PIL import ImageChops
resultIm = ImageChops.lighter(im1,im2)
</pre>
<br />
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:<br />
<br />
<pre class="prettyprint">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()
</pre>
<br />
Using an image series (ISS030-E-271717-ISS030-E-271798) from <a href="http://eol.jsc.nasa.gov/Videos/CrewEarthObservationsVideos/Videos_NorthAmerica.htm">over here</a> and the above code generates this image:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-w6ppGmf0cB4/UGjIRsPqblI/AAAAAAAAAsU/loKNEuKX5eE/s1600/allblended_d.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="213" src="http://2.bp.blogspot.com/-w6ppGmf0cB4/UGjIRsPqblI/AAAAAAAAAsU/loKNEuKX5eE/s320/allblended_d.jpg" width="320" /></a></div>
<br />
<div style="text-align: center;">
Images courtesy of the Image Science & Analysis Laboratory, NASA Johnson Space Center</div>
onlyjushttp://www.blogger.com/profile/14236929826206309645noreply@blogger.com0tag:blogger.com,1999:blog-7070350096643865407.post-41673710478493764022012-09-25T18:36:00.000-07:002012-09-26T19:18:09.377-07:00Image Stacking: AveragingImage 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 <a href="https://www.google.com/search?q=star+trails">star trails</a>.<br />
<br />
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 <a href="http://onlyjus-photopy.blogspot.com/2012/09/pil-introduction-batch-image-converting.html">knowledge of PIL</a> we can write a script starting with importing the required libraries:<br />
<br />
<pre class="prettyprint">from PIL import Image
import glob
import numpy as np
</pre>
<br />
find all the images in a folder, in this case *.png files:<br />
<pre class="prettyprint">imgList = glob.glob('./*.png')
</pre>
<br />
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:<br />
<pre class="prettyprint">first = True
for img in imgList:
</pre>
<br />
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:<br />
<pre class="prettyprint"> temp = np.asarray(Image.open(img))
</pre>
<br />
Then change the data type of the array.There are several options for <a href="http://docs.scipy.org/doc/numpy/user/basics.types.html">data types</a>. 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. <span style="font-family: inherit;">So uint32 should do the trick (0 to <span style="background-color: white;">4294967295)</span></span><br />
<br />
to float:<br />
<pre class="prettyprint"> temp = temp.astype('<span style="font-family: 'Times New Roman'; white-space: normal;">uint32</span>')
</pre>
<br />
next, we have to either 1) create a new variable to hold the sum or 2) add the current image to the summed image:<br />
<pre class="prettyprint"> if first:
sumImage = temp
first = False
else:
sumImage = sumImage + temp
</pre>
<br />
now we calculate the averaged image by dividing the summed image by the number of images:<br />
<pre class="prettyprint">avgArray = sumImage/len(imgList)
</pre>
<br />
we have to convert back to the unit8 data type, then back into the PIL image class:
<br />
<pre class="prettyprint">avgImg = Image.fromarray(avgArray.astype('uint8'))
</pre>
<br />
Finally using what we learned previously, we can show, save, etc...<br />
<pre class="prettyprint">avgImg.show()
</pre>
<br />
Bringing it all back together:<br />
<pre class="prettyprint">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('<span style="font-family: 'Times New Roman'; white-space: normal;">uint32</span>')
if first:
sumImage = temp
first = False
else:
sumImage = sumImage + temp
avgArray = sumImage/len(imgList)
avgImg = Image.fromarray(avgArray.astype('uint8'))
avgImg.show()</pre>
<br />
<b>Image Example:</b><br />
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:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-PZfatwiPhDQ/UGJYQo0ZE9I/AAAAAAAAAq8/eF8dTnyyJqg/s1600/balls_0001.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="http://3.bp.blogspot.com/-PZfatwiPhDQ/UGJYQo0ZE9I/AAAAAAAAAq8/eF8dTnyyJqg/s320/balls_0001.png" width="296" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
You can see the effect of sample rate on the averaging 1) all the frames, 2) every 10th frame, and 3) every 20th frame:</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://4.bp.blogspot.com/-ji10-PxrHG8/UGJYSCXV7MI/AAAAAAAAArE/awhrOsassZc/s1600/avg_compare.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="115" src="http://4.bp.blogspot.com/-ji10-PxrHG8/UGJYSCXV7MI/AAAAAAAAArE/awhrOsassZc/s320/avg_compare.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
It is possible to modify the code and subtract frames:</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-6ddHn-P01s4/UGJazY4PkoI/AAAAAAAAArU/SPOCsPdbcMs/s1600/avg_sub.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="http://3.bp.blogspot.com/-6ddHn-P01s4/UGJazY4PkoI/AAAAAAAAArU/SPOCsPdbcMs/s320/avg_sub.png" width="296" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
and multiply frames:</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-LuWFgKJlFjQ/UGJax5-NSQI/AAAAAAAAArM/Asl7Tb6XLR0/s1600/avg_m.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="http://1.bp.blogspot.com/-LuWFgKJlFjQ/UGJax5-NSQI/AAAAAAAAArM/Asl7Tb6XLR0/s320/avg_m.png" width="296" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<span style="font-family: inherit;"><br /></span></div>
<div class="separator" style="clear: both; text-align: left;">
<span style="font-family: inherit;"><br /></span></div>
<div class="separator" style="clear: both; text-align: left;">
<span style="font-family: inherit;">I stumbled upon this awesome NASA <a href="http://eol.jsc.nasa.gov/Videos/CrewEarthObservationsVideos/Videos_NorthAmerica.htm">website</a>. The following images have been stacked with the above code. <u style="background-color: white; font-weight: bold;">Images courtesy of the Image Science & Analysis Laboratory, NASA Johnson Space Center.</u><span style="background-color: white;"> Thanks for providing those images. They are great!</span></span></div>
<div class="separator" style="clear: both; text-align: left;">
<span style="font-family: inherit;"><span style="background-color: white;"><br /></span></span></div>
<div class="separator" style="clear: both; text-align: left;">
<span style="font-family: inherit;"><span style="background-color: white;">Images </span></span>ISS031-E-66034 to ISS031-E-66136:</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-I8HMTD3ORSE/UGOoCwAqj-I/AAAAAAAAAro/O9awr9qxQdA/s1600/avg_b.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="213" src="http://2.bp.blogspot.com/-I8HMTD3ORSE/UGOoCwAqj-I/AAAAAAAAAro/O9awr9qxQdA/s320/avg_b.jpg" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
Images ISS030-E-68896 to ISS030-E-69180:</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-7bP3M5Lzqwg/UGOoC3O02jI/AAAAAAAAArs/hcL1_yLBLZg/s1600/avg_c.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="213" src="http://1.bp.blogspot.com/-7bP3M5Lzqwg/UGOoC3O02jI/AAAAAAAAArs/hcL1_yLBLZg/s320/avg_c.jpg" width="320" /></a></div>
<br />
Images ISS030-E-271717 to ISS030-E-271798:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://1.bp.blogspot.com/-BC82NGe5A10/UGOoC8B5bAI/AAAAAAAAArk/KhDCk7BoKwQ/s1600/avg_d.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="213" src="http://1.bp.blogspot.com/-BC82NGe5A10/UGOoC8B5bAI/AAAAAAAAArk/KhDCk7BoKwQ/s320/avg_d.jpg" width="320" /></a></div>
<br />
Images ISS031-E-57221 to ISS031-E-57490:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-PztJ2LP7uXI/UGOrkYt7OcI/AAAAAAAAAsE/k6hYG7FFBxQ/s1600/avg_e.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="213" src="http://2.bp.blogspot.com/-PztJ2LP7uXI/UGOrkYt7OcI/AAAAAAAAAsE/k6hYG7FFBxQ/s320/avg_e.jpg" width="320" /></a></div>
<br />
<br />
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.onlyjushttp://www.blogger.com/profile/14236929826206309645noreply@blogger.com5tag:blogger.com,1999:blog-7070350096643865407.post-24432298288964962872012-09-23T13:32:00.000-07:002012-09-23T13:32:18.146-07:00PIL Introduction, Batch Image ConvertingPIL or the<a href="http://www.pythonware.com/products/pil/"> Python Imaging Library</a>, 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 <a href="http://infohost.nmt.edu/tcc/help/pubs/pil/formats.html">others</a>.<br />
<br />
<i>Note: The examples here apply to Python 2.7 and PIL 1.1.7</i><br />
<i><br /></i>
To open an image using PIL, we use the PIL's Image module (in an interactive shell, or python script):<br />
<pre class="prettyprint">>>> from PIL import Image
>>> im=Image.open('./example.JPG')
</pre>
Where './example.JPG' is the image path. This creates an PIL instance of the specified image, im.<br />
<br />
There are some useful attributes of the image class such as:
<pre class="prettyprint">>>> im.size
(3872, 2592)
>>> im.format
'JPEG'
>>> im.mode
'RGB'
</pre>
<br />
We can now use this instance to do a variety of tasks such as showing the image:
<br />
<pre class="prettyprint">>>> im.show()
</pre>
<br />
Rotating the image counter clockwise at an angle specified in degrees, creating a new image instance of the rotated image:<br />
<pre class="prettyprint">>>> im2=im.rotate(45)
</pre>
<br />
Re-sizing the image, preserving the aspect ratio:<br />
<pre class="prettyprint">>>> im.thumbnail([128,128])
</pre>
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 <span style="background-color: white; font-family: Georgia, serif;">NEAREST</span><span style="background-color: white; font-family: Georgia, serif;">, </span><span style="background-color: white; font-family: Georgia, serif;">BILINEAR</span><span style="background-color: white; font-family: Georgia, serif;">, </span><span style="background-color: white; font-family: Georgia, serif;">BICUBIC</span><span style="background-color: white; font-family: Georgia, serif;">, or </span><span style="background-color: white; font-family: Georgia, serif;">ANTIALIAS (the best quality):</span><br />
<pre class="prettyprint">>>> im.thumbnail([128,128],Image.ANTIALIAS)
</pre>
<br />
Re-sizing the image, not preserving the aspect ratio:
<br />
<pre class="prettyprint">>>> im.resize([128,128])</pre>
You can also change the interpolation scheme:
<br />
<pre class="prettyprint">>>> im.resize([128,128],Image.ANTIALIAS)</pre>
<br />
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:
<br />
<pre class="prettyprint">>>> im3=im.crop([10,40,400,350])
</pre>
<br />
Finally, saving the resulting image as jpeg (indicated by the file extension):<br />
<pre class="prettyprint">
>>> im.save('./exampleOut.jpg')
</pre>
You may also explicitly tell the function what format to save it in (int his case, as png image):<br />
<pre class="prettyprint">
>>> im.save('./exampleOut', 'PNG')
</pre>
<i>Note: This will not automatically append the file extension to the file name.</i><br />
<br />
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:<br />
<pre class="prettyprint">
#import require libraries
from PIL import Image
import glob
import os
<br />
# Find all the jpegs in a given folder:
folder='C:/exampleImages/'
imList=glob.glob(folder+'*.jpg')
<br />
# 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')
</pre>
<br />
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.<br />
<br />
To give you a more complex example that I used to answer a question on the<a href="http://photo.stackexchange.com/questions/27137/what-program-can-automatically-crop-a-folder-of-images-to-a-certain-resolution/27147#27147"> photography stack exchange</a>:<br />
<br />
<pre class="prettyprint">#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")
</pre>
<br />
<br />
<br />onlyjushttp://www.blogger.com/profile/14236929826206309645noreply@blogger.com0tag:blogger.com,1999:blog-7070350096643865407.post-41385682110172920972012-09-18T16:48:00.003-07:002012-09-18T16:57:30.317-07:00Intro to Python<a href="http://www.python.org/">Python</a> 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.<br />
<br />
You can download the official python source and installers <a href="http://www.python.org/download/">here</a>. 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.<br />
<br />
Several import libraries to get working on your machine:<br />
<ol>
<li><a href="http://www.pythonware.com/products/pil/">PIL</a></li>
<li><a href="http://numpy.scipy.org/">Numpy</a></li>
</ol>
<div>
<i>Note: If you are using a windows machine I would highly suggest using <span style="background-color: white;"> </span><a href="http://www.lfd.uci.edu/~gohlke/pythonlibs/">Christoph Gohlke's</a> windows installers for the libraries that you are interested in.</i><br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
Assuming that you have python installed, try opening the IDLE (python shell). You should see something like:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="http://3.bp.blogspot.com/-epG9aAeWsiQ/UFkA8qUkHyI/AAAAAAAAApo/WIK7dqbvM5E/s1600/python+IDLE.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" height="93" src="http://3.bp.blogspot.com/-epG9aAeWsiQ/UFkA8qUkHyI/AAAAAAAAApo/WIK7dqbvM5E/s320/python+IDLE.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<i>This is 2.7.2 on windows 7.</i></div>
<div class="separator" style="clear: both; text-align: center;">
<i><br /></i></div>
<div class="separator" style="clear: both; text-align: left;">
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 <a href="http://wiki.python.org/moin/IntegratedDevelopmentEnvironments">here</a>.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
You can also access python through the command line by typing python (if your path variables are setup correctly):</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="http://2.bp.blogspot.com/-xdv8jxIeOKk/UFkD8PLqM1I/AAAAAAAAAp4/u6byPU9UI1w/s1600/pythonCMD.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="78" src="http://2.bp.blogspot.com/-xdv8jxIeOKk/UFkD8PLqM1I/AAAAAAAAAp4/u6byPU9UI1w/s320/pythonCMD.png" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
So, if you have python up and running try out the following code:</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<pre class="prettyprint">>>> 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']
</pre>
</div>
<br />
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!onlyjushttp://www.blogger.com/profile/14236929826206309645noreply@blogger.com0tag:blogger.com,1999:blog-7070350096643865407.post-85024640981025261622012-09-17T18:48:00.000-07:002012-09-17T18:59:16.745-07:00Test PostTest post
<pre class="prettyprint">
import PIL
print 'Does this work?'
print "How about this?"
for i in range(10):
print i
</pre>
<a href="http://lukabloga.blogspot.com/2008/10/to-test-new-highlighting.html">I followed this example of how to get blogger to perform code highlighting.</a>onlyjushttp://www.blogger.com/profile/14236929826206309645noreply@blogger.com0