Last active
December 20, 2015 13:59
-
-
Save indranilsinharoy/6142992 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- coding: utf-8 -*- | |
""" | |
File: simpleLensScaling.py | |
Purpose : Calculate two-point resolution using Rayleigh criterion and | |
study the effect of lens scaling on Rayleigh resolution. | |
Assumption: First order optical analysis, specifically they are: | |
1. The system is diffraction limited (aberrations are not considered) | |
2. The aperture is circular | |
3. A simple single lens system is considered, thus | |
a. the entrance pupil diameter = exit pupil diameter = aperture diameter | |
b. apply simple lens equation to find distance and magnification relationships | |
Created on Thu Aug 01 14:18:27 2013 | |
Author: Indranil Sinharoy | |
License : MIT License | |
""" | |
from __future__ import division, print_function | |
from math import atan, pi | |
class camera(object): | |
"""a camera class""" | |
def __init__(self, lens=None, sensor=None): | |
self.lens = lens | |
self.sensor = sensor | |
self.fov_width = -1.0 | |
self.fov_height = -1.0 | |
def setObjDist(self, distance): | |
"""set the distance of the camera from the object plane in mm""" | |
self.lens.setObjDist(distance) | |
def calculateFOV(self): | |
"""returns the field-of-view of the camera""" | |
if self.lens and self.sensor: | |
img_w = self.sensor.width | |
img_h = self.sensor.height | |
img_z = self.lens.getImgDist() | |
self.fov_width = 2.0*atan((img_w/2.0)/img_z)*180.0/pi | |
self.fov_height = 2.0*atan((img_h/2.0)/img_z)*180.0/pi | |
return (self.fov_width, self.fov_height) | |
else: | |
print("Can't calculate FOV. Attach a lens and sensor to the camera") | |
return | |
class lens(object): | |
"""lens class, described by focal length, `f` mm, and aperture diameter, `D` mm. | |
The aperture is assumed to be circular. | |
""" | |
def __init__(self, f, D): | |
self.f = f # focal length in mm | |
self.D = D # aperture diameter in mm | |
self.Fnum = f/D # F/# | |
self.z_o = None # object distance in mm | |
self.latMag = None # lateral magnification | |
self.effFnum = None # effective F/# | |
def setObjDist(self,z_o): | |
"""sets the object distance z_o (mm)""" | |
self.z_o = z_o # set an object distance | |
self.z_i = self.getImgDist(z_o) # image distance for the set object distance | |
self.latMag = self.z_i/self.z_o # calculate lateral magnification | |
self.effFnum = self.z_i/self.D # calculate effective F/# | |
def getImgDist(self, zo=None): | |
"""returns the image distance for a particular object distance `zo` (which | |
might be different from `z_o`, the set object distance). If `zo=None`, then | |
the returned image distance is for the set object distance. If the object | |
distance has not been set, then the object distance is assumed to be infinity | |
and the image distance is equal to the focal length. | |
""" | |
if zo: | |
zi= self.f*zo/(zo-self.f) | |
elif not zo and self.z_o: | |
zi= self.f*self.z_o/(self.z_o-self.f) | |
elif not zo and not self.z_o: | |
zi = self.f | |
return zi | |
def getMinResolvSepImgPlane(self,lamda=550e-6): | |
"""returns the minimum resolvable separation of the geometrical image points | |
The default wavelength is 550 nm or 550e-6 mm | |
""" | |
deltaSi = 1.22*lamda*self.effFnum | |
return deltaSi | |
def getMinResolvSepObjPlane(self,lamda=550e-6): | |
"""returns the minimum resolvable separation of the geometrical image points | |
The default wavelength is 550 nm or 550e-6 mm | |
""" | |
deltaSo = self.getMinResolvSepImgPlane(lamda)/self.latMag | |
return deltaSo | |
def getLatRayleighResImgPlane(self,lamda=550e-6): | |
"""returns the lateral resolution in the image plane""" | |
deltaRi = 1.0/self.getMinResolvSepImgPlane(lamda) | |
return deltaRi | |
def getLatRayleighResObjPlane(self,lamda=550e-6): | |
"""returns the lateral resolution in the object plane""" | |
deltaRo = 1.0/self.getMinResolvSepObjPlane(lamda) | |
return deltaRo | |
def scaleLens(self,factor=0.5): | |
"""returns a scaled lens object""" | |
return lens(self.f*factor, self.D*factor) | |
class sensor(object): | |
"""a very simple sensor class""" | |
def __init__(self, width=36.0, height=24.0): | |
self.width = width | |
self.height = height | |
def scaleSensor(self, factor=0.5): | |
"""scale the dimensions of the sensor by the given factor and return | |
a new sensor object""" | |
return sensor(self.width*factor, self.height*factor) | |
if __name__ == "__main__": | |
print("Study the effect of Lens Scaling on Diffraction limited resolution:") | |
# Test the camera class | |
object_distance = 2000.0 # Object distance = 2 meters | |
lensA = lens(50.0, 25.0) # lensA, focal length=50mm, aperture diameter = 25 mm | |
sensorA = sensor(36.0, 24.0) | |
cameraA = camera(lensA, sensorA) | |
cameraA.setObjDist(object_distance) | |
print("Lens A: f = %1.4g, D = %1.4g, F/# = %1.4g, eff F/# = %1.4g" % | |
(lensA.f, lensA.D, lensA.Fnum, lensA.effFnum)) | |
print("Lens A: minimum resolvable separation on image plane = %1.5g microns" % | |
(lensA.getMinResolvSepImgPlane()*1000.0)) | |
print("Lens A: minimum resolvable separation on the object plane = %1.5g microns" % | |
(lensA.getMinResolvSepObjPlane()*1000.0)) | |
print("Camera A: field of view (degrees): horizontal = %1.4g, vertical = %1.4g" % | |
(cameraA.calculateFOV()[0], cameraA.calculateFOV()[1])) | |
print("\nCreate a scaled camera B") | |
# scale lens by a factor of 1/10 and place the scaled lens at the same distance | |
lensB = lensA.scaleLens(1.0/10) | |
lensB.setObjDist(object_distance) | |
sensorB = sensorA.scaleSensor(1.0/10) | |
cameraB = camera(lensB, sensorB) | |
print("Lens B: f = %1.4g, D = %1.4g, F/# = %1.4g, eff F/# = %1.4g" % | |
(lensB.f, lensB.D, lensB.Fnum, lensB.effFnum)) | |
print("Lens B: minimum resolvable separation on image plane = %1.5g microns" % | |
(lensB.getMinResolvSepImgPlane()*1000.0)) | |
print("Lens B: minimum resolvable separation on the object plane = %1.5g microns" % | |
(lensB.getMinResolvSepObjPlane()*1000.0)) | |
print("Camera B: field of view (degrees): horizontal = %1.4g, vertical = %1.4g" % | |
(cameraB.calculateFOV()[0], cameraB.calculateFOV()[1])) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment