Hyperfocal distance math needs changing
I'm not sure I posted correctly here: https://bitbucket.org/hudson/magiclantern/issues/2719/proposedcorrectiontofocusc
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 = (fdfl)/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 = (fdfl)/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;
Comments (7)


reporter Alex
I've changed the code and I've stumbled over how to do a pull request. I've opened up the Pull Request, but I can't work out how to open a new pull and go to the focus.c to enter my changes.
Sorry to bother you, but can you educate me.
Cheers
Garry

Let's just wait until @Audionut fixes the images in his tutorial.

reporter Alex pls see my latest post: Here is the focus.c fix.
Sorry I can't make a pull request.
void focus_calc_dof() { // Total (defocus + diffraction) blur dia in microns uint64_t coc = dof_info_coc*10; // from ML setting, converted to tenths here, as the base unit for blurs, to increase 'division accuracy' uint64_t coc_hfd = 0; // variable used to calculate HFD
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. Note lens_info.aperture = 10*N, eg at F/16 lens_info.aperture = 160 // Diffraction blur at any fd = 2.44*freq*N*(1+mag). Where mag = fl/(fdfl) // ie at fl = 10 and fd = 200, mag = 10/(20010) = 0.05. But note for 100mm macro lens at min fd = 300, mag = 100/(300100) = 0.5 const uint64_t freq = 550; // mid vis diffraction freq in nm (use 850 if IR) const uint64_t diff_hfd = (244*freq*lens_info.aperture)/100000; // Estimation of diffraction blur in tenths of microns, without (1+mag) factor as mag assumed at infinity, ie zero const uint64_t diff = diff_hfd*fd/(fdfl); // Diffraction blur (in tenths of units) in microns at fd, using (1+mag), ie being technically correct :) 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 for fd and hfd, in tenths of micron const uint64_t sq = (coc*coc  diff*diff); const uint64_t sq_hfd = (coc*coc  diff_hfd*diff_hfd); coc_hfd = (int) sqrtf(sq_hfd); // Estimate of defocus blur at HFD in tenths of units. Doesn't vary when focus changes, as uses a mag (at infinity) of zero. coc = (int) sqrtf(sq); // Focus distance aware defocus blur in tenths of units } } const uint64_t fl2 = fl * fl; // Calculate defocus hyperfocal distance H. Note this is diffraction aware, but is indepedent of fd const uint64_t H = coc ? fl + ((100000 * fl2) / (lens_info.aperture * coc_hfd)) : 1000 * 1000; // use coc to test for diffraction limit reached lens_info.hyperfocal = H; // Calculate near and far dofs const uint64_t temp = lens_info.aperture*coc*(fdfl) // note aperture and coc in tenths of their units, hence the 100000 factor below lens_info.dof_near = (fd*fl2*100000)/(100000*fl2 + temp); // in mm if( fd >= H ) { lens_info.dof_far = 1000 * 1000; // infinity } else { lens_info.dof_far = (fd*fl2*100000)/(100000*fl2  temp); // 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+5)/10; // at point of focus rounded up/down to nearest integer
}

You definitely can: https://bitbucket.org/hudson/magiclantern/pullrequests/632
Would be nice if you can tell me some numbers (where the formula is illconditioned) so I can crosscheck the results in some online calculator.

reporter I thought I just made a pull request, but can't see it in the pull request list. So maybe I didn't. The problem is simply the mag or imag part. I've eliminated this, but all the equations remain the same, ie DoF equations are simple.

 changed status to resolved
 Log in to comment
Do you mind reframing this as a pull request? You can do it from the web interface, and makes it easier to see the difference.