Propeller Image Aliasing
Posted by ScalarMotion on March 15, 2009
Many people, who have tried taking a picture of a spinning airplane propeller with their cellphone cameras, have been surprised by the outcome. After all, they didn’t expect to see many ghostly propeller blades floating in the air without being totally detached to the airplane. Here is an example: a photograph of a rotating propeller taken by an iPhone.
If you click on the photograph, it’ll take you the forum where it was originally posted. Sure enough, you’ll also see the ususal cries of “photoshop”.
What really happens
The cameras on many cellphones are slow scanning digital cameras. When capturing an image, they do not expose all the pixels at the same time. Rather they expose and capture one row of the sensor before moving onto the next. What this means is that different rows (or columns, depending on the orientation of the sensor) of the image are captured at different times. And during this interval the blades move appreciably. The entire thing is a bit difficult to visualize. So I have created a MATLAB simulation to demonstrate this effect in a slow-motion video. In the video below: a sensor is capturing the photograph of a spinning propeller by exposing one row at a time.
Simulation parameters: Propeller speed = 1800 RPM. Camera shutter speed = 1/15 s.
Notice the similarities between the simulation result and the propeller picture above?!




Ross youngblood said
Interesting, if one knew the scan rate of the iPhone it might be a reliable propeller tachometer
ScalarMotion said
Absolutely right, Ross! I guess an iPhone app is around the corner.
Alex said
Really useful post. Could you upload or send the matlab code? I’d like to play with it a bit. Thanks.
ScalarMotion said
Thanks, Alex.
WordPress does not allow uploading a text file. But if you don’t mind getting the code from a PDF, here it is.
Image Aliasing of Plane Propellers in Photos and Video said
[...] the internet and found that I was not the only one to notice this oddity. I also stumbled upon this great post explaining clearly and graphically why the iPhone photo looks the way it does. In short, most [...]
Hi said
Nice post. Looks like the iPhone scans left to right or right to left based on your simulation?
ScalarMotion said
I am not sure. I guess if I knew the orientation of the camera when the pictures were taken, I could deduce the direction of scanning. But I do not own an iPhone, so cannot experiment. Yes, yes, there are still people out there who do not own an iPhone,
Thanks for the comment.
Phlip said
One interesting effect is that on the side where the propeller images are close together (the top on the original picture, the right in the video), they’re moving against the scan, and the orientation is preserved, but on the side where they’re far apart, they’re moving with the scan, and the images are mirror images of the real propellers. For instance, in the original photo, near the hub, on each blade, there’s a black stripe… on the top half of the image, this black stripe is on the clockwise-facing side, but on the bottom half it’s the anticlockwise-facing side (which means it’s on the right-hand side in both cases… which is most visible on the second warped blade from the left). So this means the black stripe is really on the clockwise side.
Now, a comment on the original blog (for some reason, I can’t link to it without triggering a spam filter or something… but it’s comment #10) says that strip is on the leading edge of the propeller, so the prop would be spinning clockwise in that photo. So the top was moving left-to-right, against the scan, but the bottom was moving right-to-left, with the scan.
So the scan was right-to-left in that photo.
But like the guy says, we don’t know the orientation of the iPhone when the photo was taken… I don’t know much about the iPhone (I don’t own one either) but I do know you can hold it horizontally or vertically, and it’ll do fancy things… but that probably doesn’t include rotating the physical camera itself. So if it was horizontal when that photo was taken, then holding it vertically would have scan bottom-to-top… but if it was vertical when that photo was taken, then holding it horizontally would have it scan top-to-bottom.
iPhoneでプロペラの回転を撮影したらとんでもないことになってた « MEGANEW said
[...] Propeller Image Aliasing « Scalar Motion ベーコン風味の爪楊枝とデンタルフロス » [...]
c00 said
You are awesome! Movie explained it brilliantly.
ScalarMotion said
Thanks! You are kind.
marc said
Can you make the MATLAB code available?
ScalarMotion said
%%%%%%%%%%%%% MATLAB CODE STARTS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Simulation of image aliasing due to pixel-wise scanning of a propeller.
%% Assumptions:
%% Propeller:
%% 1. Constant angular velocity
%% 2. Uniform visual cross-section of the blades (rectangular
%% blades)
%% Camera:
%% 1. pixel-wise scanning left-to-right, from top to bottom.
%% 2. no TV camera like interleaving
%% Propeller description
omega = 30; % Angular speed in rotations per second
length = 200; % Length of the blades in cm
width = 10; % Cross-section width in cm. (effective projection visible from the camera. assumed constant.)
numBlades = 3; % number of blades
discWidth = 0;
%% Camera description
frameSize = 600*[1 3/4]; % Width & height of the picture frame (in cm) at the plane of the propeller (assuming the propeller is at the center of the image)
sensorSize = 400*[1 3/4]; % Sensor resolution in pixels
frameDuration = 1/15; % Time (in seconds) taken to scan all pixels in the sensor
%% Initializations
initAngle = 0; % Initial orientation of the propeller. Can be assumed to be anything without loss of generality.
numPixels = prod(sensorSize); % total number of pixels
tArrScan = [1:numPixels]‘*frameDuration/numPixels; % Time instants at which different pixels are sampled. Starting top-left.
% posPixels: position of the pixels. matrix of dimension numPixels x 2. 1 row for each pixel. 2 elements
% per pixel for X & Y coordinates.
posPixels = -0.5+[reshape(repmat([sensorSize(2):-1:1], sensorSize(1), 1), numPixels, 1)-sensorSize(2)/2 mod([0:numPixels-1]‘, sensorSize(1))+1-sensorSize(1)/2];
posPixels = posPixels*frameSize(1)/sensorSize(1); % scaling to translate the pixels on plane of the propeller.
distPixels = abs(posPixels * [1 i]‘); % distance of the pixels from the center of the frame.
angPixels = angle(posPixels * [i 1]‘); % distance of the pixels from the center of the frame.
%% Camera operation
img = zeros(numPixels,1); % initialization
for kk=0:numBlades-1 % do for each balde
angleBlade = (2*pi/numBlades*kk)+initAngle+2*pi*mod(tArrScan*omega, 1); % position of the blade when the pixels are being scanned.
distPixel2Blade = sum(posPixels .* [-cos(angleBlade) sin(angleBlade)], 2); % distance of the pixels (when they are scanned) from the axis of the blade
distPixel2PerpOrigin = sum(posPixels .* [sin(angleBlade) cos(angleBlade)], 2); % distance of the pixels from the axis perpendicular to the blade at origin
distPixel2PerpOutEnd = distPixel2PerpOrigin – length; % distance of the pixels from the axis perpendicular to the blade at the ouward end of the blade
pixelIsBesideTheBlade = (distPixel2PerpOrigin .* distPixel2PerpOutEnd) <= 0; % Pixel is within the two ends of the blade
img = img+ min(abs(distPixel2Blade)<width, pixelIsBesideTheBlade); % add 1 to the pixels that are: (1) within distance width/2 from the line of axis of the blade, and (2) within the two ends of the blade.
end
% figure; imagesc(min([reshape(img, sensorSize(1), sensorSize(2))]',1)); colormap(gray); axis equal; % convert the pixels to 2-D image
%% Create a video to show the results progressively
tmpimg = zeros(numPixels,1); % initialization
figure; imagesc([reshape(tmpimg, sensorSize(1), sensorSize(2))]'); colormap(gray); axis equal;
clf;
set(gcf,'DoubleBuffer','on') % To reduce the flicker
for ii=1:round(numPixels/100):numPixels % only sample 100 frames
tmpimg = zeros(numPixels,1);
tmpimg(1:ii) = min(1,img(1:ii));
scnrow = ceil(ii/sensorSize(1));
scncol = mod(ii-1,sensorSize(1))+1;
scnimg = zeros(numPixels,1);
scnimg((scnrow-1)*sensorSize(1)+[1:sensorSize(1)]) = 1; % mark the row
% scnimg(scncol:sensorSize(1):end) = 1; % mark the column
tmpimg(ii) = 1;
bldimg = zeros(numPixels,1);
for kk=0:numBlades-1 % do for each balde
angleBladeTmp = (2*pi/numBlades*kk)+initAngle+2*pi*mod(tArrScan(ii)*omega, 1); % position of the blade when the pixels are being scanned.
distPixel2BladeTmp = posPixels * [-cos(angleBladeTmp) sin(angleBladeTmp)]'; % distance of the pixels (when they are scanned) from the axis of the blade
distPixel2PerpOriginTmp = posPixels * [sin(angleBladeTmp) cos(angleBladeTmp)]'; % distance of the pixels from the axis perpendicular to the blade at origin
distPixel2PerpOutEndTmp = distPixel2PerpOriginTmp – length; % distance of the pixels from the axis perpendicular to the blade at the ouward end of the blade
pixelIsBesideTheBladeTmp = (distPixel2PerpOriginTmp .* distPixel2PerpOutEndTmp) <= 0; % Pixel is within the two ends of the blade
bldimg = bldimg+ min(abs(distPixel2BladeTmp)<width, pixelIsBesideTheBladeTmp); % add 1 to the pixels that are: (1) within distance width/2 from the line of axis of the blade, and (2) within the two ends of the blade.
end
pause(1/1000);
imagesc(min([reshape(tmpimg+scnimg+bldimg, sensorSize(1), sensorSize(2))]',1)); colormap(gray); axis equal;
% imagesc([reshape(max(max(2*tmpimg,scnimg),bldimg), sensorSize(1), sensorSize(2))]'); colormap(gray); axis equal;
end
imagesc(min([reshape(img, sensorSize(1), sensorSize(2))]',1)); colormap(gray); axis equal;
%%%%%%%%%%%%% MATLAB CODE ENDS %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Ben Jackson said
That’s great! Now I’m tempted to take your Matlab script, find a promising set of RPMs and try to generate specific effects with a real plane.