Last active
September 25, 2017 09:33
-
-
Save pigeonhill/ee60d0c23b27273c0445bf1846c258a5 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
/** | |
* 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