I've been wondering how many pictures I've taken with my Canon EOS 350D lately. After a lot of research online it seems there are two trains of thought on this subject on the Interwebs. Higher end models store this value internally but accessing it is proprietary - I know that at least the 40D supports using the Canon SDK to find the shutter actuation count, but you have to sign for a license with all kinds of terms and the library is proprietary so this is a non-starter for me.

My Canon EOS 350D
(~)| Camera | Canon Eos Digital Rebel Xt |
| Date | 20 October 2008 at 12:11 |
| Exposure Mode | Aperture Priority |
| Exposure Time | 1/60 seconds |
| Aperture | f/4 |
| ISO Speed | 1600 |
| Focal Length | 105 mm |
| Metering | Pattern |
| Flash | Off |
Another approach I found uses a header stored in all RAW files produced by the camera. Here is an article on finding the shutter actuation count on a 20D, but several flaws have been found. This number can be forced to reset with a factory reset (apparently). This number is only 16-bit (max value of 65,536). After my own testing this is not the shutter actuation count, but the number of files that have been saved to a memory card (taking out the card and taking photos doesn't increase the number). The location of this value changes from camera to camera due to strings in the TIFF tags.
The limitations above suck, but I've been the only owner of my camera, I know I haven't taken over 65,000 photos, and I've rarely shot without a card. The last issue can be solved programmatically, so that is what I did.
Assume that there exists a single byte value in every RAW image shot with the camera that increases by one for every picture taken. For any given two pictures the probability of finding this value is low - in fact I bet there are hundreds of values that increase by one, but add another photo or two and the probability rapidly approaches one. Taking this assumption I hacked together a bit of python to search for this value by doing the equivalent of a byte-by-byte diff of any number of RAW files, throwing out any diffs that do not increase by one each time. Using just four photos from my 350D I was able to find the correct value:
./framecount.py IMG_417*
Using 4 images, scanning first 512 KiB
Potential candidate found at 0x944: 79 => 80 => 81 => 82
Found 1 candidates
Unsigned 16-bit integer at 0x943 is 21077 for /Users/dan/IMG_4178.CR2
So I've taken around 21,077 photos since I bought the camera. Not bad :-) The source for the script is provided below for anyone that is interested in trying this on their own camera:
#!/usr/bin/env python
import struct
import sys
BUFFER_SIZE = 1024
READ_COUNT = 512
imgs = []
candidates = []
# Open all passed files
for value in sys.argv[1:]:
imgs.append(open(value))
print "Using %d images, scanning first %d KiB" % \
(len(imgs), BUFFER_SIZE * READ_COUNT / 1024)
for x in range(READ_COUNT):
# Read in chunks of bytes to test
values = []
for image in imgs:
values.append(list(struct.unpack(str(BUFFER_SIZE) + "B",
image.read(BUFFER_SIZE))))
base_pos = x * BUFFER_SIZE
for y in range(BUFFER_SIZE):
# Increment values that come after the max 8-bit uint
overflow = False
for pos in range(len(values)):
if overflow:
values[pos][y] += 255
if values[pos][y] == 255:
overflow = True
# Make sure values are increasing by one each time
failed = False
last = values[0][y]
for pos in range(len(values) - 1):
cur = values[pos + 1][y]
if last != cur - 1:
failed = True
break
last = cur
if not failed:
# Print info about this candidate
value_str = "%s => " * len(values) % \
tuple([value[y] for value in values])
print "Potential candidate found at %s: %s" % \
(str(hex(base_pos + y)), value_str.strip("=> "))
candidates.append(base_pos + y)
print "Found %d candidates" % len(candidates)
if len(candidates) == 1:
offset = candidates[0] - 1
imgs[-1].seek(offset)
value = struct.unpack("<H", imgs[-1].read(2))[0]
print "Unsigned 16-bit integer at %s is %d for %s" % (str(hex(offset)),
value, sys.argv[-1])
elif len(candidates) > 1:
print "Try passing more photo data to scan to narrow down the number "
"of candidates!"
else:
print "Hmmm, try passing several raw images that were taken one after "
"the other so that the image count increases by one each time!"





