Re: A "slanted edge" analysis program



Bart van der Wolf wrote:

"Lorenzo J. Lucchini" <ljlbox@xxxxxxxxxx> wrote in message news:5KYZe.49331$nT3.33343@xxxxxxxxxxxxxxxxxxxxxxxx
SNIP


[snip]

I've added a few comments, hopefully it will help to better understand the reasons behind the steps.

1) Read in an RGB image
2) We work with vertical edges, so rotate the image if needed

This is only done to simplify the calculations. All that's required is to get the image data in a uniform orientation, so all subsequent subroutines will know what to expect (which avoids rechecking assumptions).

Sure. I only specified this because I think I used terms like "lines", "rows" etc. later on.


3) Besides the "red", "blue" and "green" channels, create a "gray" channel that is the average of the other three

The image code values should be linarized at this stage, so film/sensor non-linearity and gamma adjustments can't influence the calculations.

Yes, I am currently ignoring gamma, as my test images are gamma=1.0 anyway.
If I'm not mistaken, though, this all boils down to a "Pixel=InputPixel^Gamma" instead of just "Pixel=InputPixel", so I'll be be very easy to add.


It is customary to use a different weighting than the (R+G+B)/3 average. The ISO suggests the calculation of a luminance channel, so a ratio of approx. 3R:6G:1B is closer to what we experience as luminance.

I suspected this. This is also easy to do, so I'll fix it right now.

4) Normalize the image, so that 0.5% of the pixels clip down, and 0.5% clip up

I think that, especially on non-linear image codes, this will influence the MTF results, because the contrast is expanded. On a perfectly symmetrical brightness distribution its effect will be small, but the possibility of clipping in later stages should be avoided.

I'm not sure I understand why it can affect the MTF, but I'll take your word for it.


I've included this normalization step mainly because of the way I decide how many pixels in each line will be considered part of the "edge", i.e. contribute to the ESF: what I did is consider every pixel above a certain threshold and below another (e.g. 10% and 90%, or more recently 5% and 95% since the former didn't work out well) part of the edge.

But (also judging from your other message) it seems I was completely off track about this. I suppose I can just do like Imatest does, and say that 10 pixels on the right and 6 on the left of the edge center will be "part of the edge".

This way, the normalization process becomes unnecessary.

Also a check for at least 20% edge modulation should be made, in order to avoid a too low input S/N ratio.

I'm taking note, but I think I'll leave such checks for later when the program is somewhat stable.


It is however perfectly normal to normalize the ESF output to a range between 0.0 and 1.0, and later to normalize the SFR/MTF to 1.0 (100%) at zero spatial frequency.

Currently, I'm normalizing the ESF, the LSF and the MTF to between 0.0 and 1.0.


5) For each line in the image, find the point with the max adjacent pixel difference (should be the edge)

Not necessarily, that is just the maximum gradient and that need not be the same as the edge.
The ISO suggests to combine this with with your step 9, and determine the centroid of the LSF (by calculating the discrete derivative of the ESF). The centroids can be used for regression.
>
The derivative suggested by the ISO is:
"for each line of pixels perpendicular to the edge, the edge is differentiated using the discrete derivative "-0,5 ; +0,5", meaning that the derivative value for pixel "X" is equal to -1/2 times the value of the pixel immediately to the left, plus 1/2 times the value of the pixel to the right".

Sorry if I'm thick, but mathematics isn't my best friend...
You're implying that, for each line of pixels, the edge center(oid?) will be the absolute maximum of the above derivative, aren't you?


But isn't the absolute maximum of the derivative precisely the maximum gradient?

(Though the formula I use is currently simpler than the one you cite: simply y'[i]=y[i+1]-y[i])

[snip]

6) By doing a least squares regression on those points, find a straight line that ought to best represent the edge
7) Associate a distance from that line to each pixel in the image.
The ISO method shifts each row of the ESF by the calculated amount from the regression, but uses quarter pixel bins. This produces a 4x oversampling per pixel position.

This doesn't sound like a bad idea at all. It'd probably simplify things a lot, expecially with my "local regression" problems...


The function PixelValue(Distance) approximates the edge spread function.
8) Use "some kind" of local regression to create a uniformly-spaced version of the ESF, from the data described above.
9) Derive the line spread function from the edge spread function: LSF(i)=ESF(i+1)-ESF(i)

See earlier remark, and provisions need to be made to detect multiple maxima (caused by noise/graininess).

What kind of provisions?

> [snip]
11) Take the discrete Fourier transform or the resulting data

And take the Modulus, and normalize.

Yes, I forgot to mention these steps, but they're done by the program.

Note that, at the moment, the input image must be an RGB, 8-bit ASCII ("plain") PPM file. These can be created using "*topnm" and "pnmtoplainpnm" from the NetPBM suite, or by using the GIMP.
Type --help for some uncomprehensive help.

;-) Room for improvement ...

I know :-) But I was concentrating more on the mathematical aspects now... after all, I *am* able to write code that loads an image file -- well, I can take some time, but I can -- while to be sure I can manage to compute an MTF or things like that, I have to try first...


[snip]
>
Please keep in mind that I knew nothing about regressions, spread functions or Fourier transforms two weeks ago -- and I suppose I don't know that much more now.
>
> Isn't that the fun of programming, it forces you to describe the
> principles in detail. Learning new stuff is inevitable.

Sure, one of the reasons why I didn't just uploads some edges and ask you to do my homework on them with Imatest! ;-)

Even though the SourceForge description currently says little more than "calculates the MTF from a slanted edge", ultimately I'd like this program to do automatic deconvolution (or whatever is best) of images based on the edge results.

Like, "to sharpen an image, first scan a cutter or razor blade using the '--edge' option, then run the program on the image with '--sharpen'". Would be nice.

I just read some Internet source and implemented what I thought they meant.

With the program (to be) available to the public, the chance of helping hands increases.

Hope so!

The source code you have probably read will give a good start. As always, the devil is in the details, but that can be overcome.

To be honest, I've read very little source, if any (well, except the FFTW tutorial).


My main resource has been
  http://www.isprs.org/istanbul2004/comm1/papers/2.pdf

where I took the evil alternative to the "4x bins" that I'm currently using, with all the regression nighmares it brings ;-)
But it was an interesting document, anyway.



by LjL ljlbox@xxxxxxxxxx .



Relevant Pages

  • Re: Interesting timing issue I noticed
    ... no image processing background needed. ... Suffice to say that I initially wrote a script that goes through every pixel ... After a while, to try to speed up the calculations, I realized that I didn't ... gives me on average an execution time of around 0.125s, ...
    (comp.lang.python)
  • Re: Multibyte add & subtract
    ... The basic idea is to filter one pixel on each side of a 8-pixel border. ... These macros works great for small values! ... the carry so that the correct values after the calculations in ... The MBS macro _appears_ to be calculating two's ...
    (comp.lang.c)
  • Re: Multibyte add & subtract
    ... each pixel is 1 byte ... the carry so that the correct values after the calculations in ... If you can guarantee that the difference in pixel value over points a - e is less than 64, you can simply use the msb as the sign bit. ... If you choose to use two 11 bit pixels in a 32-bit word, you might as well pack 2 16-bit values per 32-bit word, which gives easier packing and unpacking. ...
    (comp.lang.c)
  • Re: A "slanted edge" analysis program
    ... The ISO suggests the calculation of a luminance channel, ... pixel difference ... The centroids can be used for regression. ... Derive the line spread function from the edge spread function: ...
    (comp.periphs.scanners)