Hyperfocal distance math needs changing
Created originally on Bitbucket by garry23 (Garry George)
I'm not sure I posted correctly here: https://bitbucket.org/hudson/magic-lantern/issues/2719/proposed-correction-to-focusc
Bluntly, although I suggested the original math, the HFD calculated by ML is wrong.
In an attempt to make it diffraction aware, I used the 'full' diffraction blur, which is focus distance aware, via the inverse of the magnification (to keep things integer in C), ie imag = (fd-fl)/fl.
Being focus distance aware is reasonable and 'correct', ie the fd changes, when calculating DoFs, ie at a specified distance.
For calculating the hyperfocal distance, it is meaningless to have this vary as we focus: which is what happens at the moment.
Here is my suggested fix to focus.c
void focus_calc_dof() { // Total (defocus + diffraction) blur dia in microns uint64_t coc = dof_info_coc;
const uint64_t fd = lens_info.focus_dist * 10; // into mm
const uint64_t fl = lens_info.focal_len; // already in mm
// 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;
}
// Set up some dof info
const uint64_t freq = 550; // mid vis diffraction freq in nm (use 850 if IR)
const uint64_t imag = (fd-fl)/fl; // inverse of magnification (to keep as integer)
const uint64_t diff = (244*freq*lens_info.aperture*(1+imag)/imag)/1000000; // focus distance aware Diffraction blur in microns
const uint64_t diff2 = (244*freq*lens_info.aperture)/1000000; // Diffraction blur in microns
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 blurs in microns
const uint64_t sq = (coc*coc - diff*diff);
const uint64_t sq2 = (coc*coc - diff2*diff2);
coc = (int) sqrtf(sq); // Focus distance aware defocus only blur
coc2 = (int) sqrtf(sq2); // Defocus only blur
}
}
const uint64_t fl2 = fl * fl;
// Calculate hyperfocal distance H, ie irrespective of lens focus distance, ie this should be a true constant
const uint64_t H = coc2 ? fl + ((10000 * fl2) / (lens_info.aperture * coc2)) : 1000 * 1000;
lens_info.hyperfocal = H;
// Calculate near and far dofs
lens_info.dof_near = (fd*fl*10000)/(10000*fl + imag*lens_info.aperture*coc); // in mm
if( fd >= H )
{
lens_info.dof_far = 1000 * 1000; // infinity
}
else
{
lens_info.dof_far = (fd*fl*10000)/(10000*fl - imag*lens_info.aperture*coc); // in mm
}
// 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;
}
Finally, being ignorant of the details in the ML backend, why is the following correct coc = dof_info_coc; and not coc = dof_info.coc;