Skip to content

Instantly share code, notes, and snippets.

@pigeonhill
Last active September 25, 2017 09:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save pigeonhill/ee60d0c23b27273c0445bf1846c258a5 to your computer and use it in GitHub Desktop.
Save pigeonhill/ee60d0c23b27273c0445bf1846c258a5 to your computer and use it in GitHub Desktop.
/**
* Compute the depth of field, accounting for diffraction.
*
* See:
* The INs and OUTs of FOCUS: An Alternative Way to Estimate Depth-of-Field and Sharpness in the Photographic Image
* by
* Harold M. Merklinger - Page 15
*
* Note the equations used in the above are referenced to the lens princpal of the lens, ie about a focal length difference
* which is important for macro work
*
* Assumes a 'generic' FF or Crop sensor, ie pixel density
*
* Makes the reasonable assumption that pupillary ratio can be ignored, ie use symmetric lens equations,
* as this only introduces a very small correction for non-macro imaging (hence what follows does
* not apply for close in macro where dof is around a (few) mm), ie approx 2NC(1+M/p)/M^2,
* where N = aperture, c = blur dia (ie coc), M = magnification and p = pupillary ratio.
*
* Hint: best to use cm in ML, rather than ft, ie more refined feedback
*
*/
void focus_calc_dof()
{
// Total (defocus + diffraction) blur dia in microns
uint64_t coc = dof_info_coc * 10; //User CoC in tenths of a micron
const uint64_t fl = lens_info.focal_len; // already in mm
const uint64_t fd = lens_info.focus_dist * 10 - fl; // convert focus relative to approx principal plane, ie not sensor
// If we have no aperture value then we can't compute any of this
// Also not all lenses report the focus length or distance
if (fl == 0 || lens_info.aperture == 0 || fd == 0)
{
lens_info.dof_near = 0;
lens_info.dof_far = 0;
lens_info.hyperfocal = 0;
return;
}
// Estimate diffraction
const uint64_t freq = 550; // mid vis diffraction freq in nm (use 850 if IR)
const uint64_t diff = (244*freq*lens_info.aperture/1000000; // Diffraction blur at infinity in tenths of a micron
int dof_flags = 0;
if (dof_info_formula == DOF_FORMULA_DIFFRACTION_AWARE)
{
// Test if large aperture diffraction limit reached
if (diff >= coc)
{
// note: in this case, DOF near and far will collapse to focus distance
dof_flags |= DOF_DIFFRACTION_LIMIT_REACHED;
coc = 0;
}
else
{
// calculate defocus only blur in microns
const uint64_t sq = (coc*coc - diff*diff);
coc = (int) sqrtf(sq); // Defocus only blur in tenths of a micron
}
}
const uint64_t fl2 = fl * fl;
// Calculate hyperfocal distance H
const uint64_t H = coc ? fl + ((100000 * fl2) / (lens_info.aperture * coc)) : 1000 * 1000; // H referenced to the lens principal plane
lens_info.hyperfocal = H + fl; // in mm referenced to the sensor
// Calculate near and far dofs
lens_info.dof_near = fl + (fd*H-fl2)/(H+fd-2*fl); // in mm relative to the sensor plane
if( fd >= H )
{
lens_info.dof_far = 1000 * 1000; // infinity
}
else
{
lens_info.dof_far = fl + (fd*H - 2*fl*fd + fl2)/(H-fd); // in mm relative to the sensor plane
}
// update DOF flags
lens_info.dof_flags = dof_flags;
// make sure we have nonzero DOF values, so they are always displayed
lens_info.dof_near = MAX(lens_info.dof_near, 1);
lens_info.dof_far = MAX(lens_info.dof_far, 1);
lens_info.dof_diffraction_blur = (int) diff/10; //Return to microns
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment