Interferometer®
Description

This is a programming project devoted to develop an application that processes images from a very cool interferometer :). The end aim of the project is to leave single-pixel width skeleton of lines that are presented on interferograms (pictures that the interferogram produces). And those lines (or stripes) are really thick, noisy and sometimes even damaged (interrupted and so on).

Used resources:

Related keywords: System.Drawing, Image, Bitmap, RGB, Non-linear adaptive algo, Non-operator image processing.

Download: June 06 2008 version (needs the MS Visual Studio installed)

User's manual: Russian version.

To-do list
June 9 2008
 

Commitments:

Program is finally ready to use in real environment. Take the shot, put it in the program. Get the optical length along the whole area of interest upon the sample. Here is the user's manual (russian).

Mar 08 2008
Pixel summary weight is not to be normalized

I've just implemented a new version of calculateWeights() and smoothWeights() procedures. The point in reprogramming those procedures is that earlier each pixel's summary weight was normalized to one (if you put all weights from all the directions at any pixel — you would get one). But this doesn't seem adequate. Different places (and pixels) have a completely distinct direction weights and thus — distinct summary weight. The more weight is, the more expressive gradient is. And when we normalize all pixels to one, we dimish that difference. And make the whole picture blurry. But we desire to distinguish places with different directions! So we don't have to normalize pixels.

Direction averaging length estimation. Smoothing matrix radius

Now. I've tried different schemes for directionLength() estimation. Each formula suggests that the more current direction weight is, the longer estimation length should be. But they do it in a bit different way:

Exponential scheme seems insanely fast-growing. Logarithmical is opposite to the exponential. So, the linear is pretty adequate. And I choose second linear scheme that uses minimal fringe step and mean weight (not a max one). This scheme says we get minimal fringe step length for averaging if our current weight is equal to the mean one. The more cur weight is, the longer an averaging length is. And since on some test pictures max weight is 5 times bigger than the mean one, we get 5 * MIN_LEN length of averaging. But the most frequent length is pretty much a little bit below MIN_LEN.

If I increase MIN_LEN constant in the program (in the code), it starts blurring the picture and fringes overlay each other. A way out is to increase the smoothing matrix radius. The wider smoothing matrix is, the more precise directions are. But I pay for matrix radius increasing by exponential processing time lift. So, for now the values are: MIN_LEN = 8, SMOOTH_RADIUS = 5 (matrix side is 2*SMOOTH_RADIUS + 1 = 10 + 1 = 11, matrix pixels number is 11x11 = 121, each pixel's direction weight is averaged through 121 other ones).

Direction distance weight scheme

Another issue about weight estimation is which scheme for distance to use. When we calculate a mean value for some direction with a given length, we build a histogram containing weights of represented gray levels of given pixels. And a pixel with the same gray level (colour intensity) has a different weight being placed further or closer to a center of an averaging line.

So the question is which scheme to use in the weight (dependant on distance) estimation. Linear function is the most simple. However it can be normalized or not. It can be zero at the outermost pixels or not. We can use exponential formula as well. But it does not seem to suit in our pictures which require pretty strong averaging and even line break restoring! Exponential scheme descend way fast to the end of the line. Further pixels give a very small contribution to the mean value. Practically only 4-5 pixels matter. So, the linear scheme seems nice.

Mar 03 2008
Skeleton algo questions

I've just added 4 more directions (22.5, 67.5, 112.5 and 157.5 degrees). Improvements in a result picture are seen through slightly tilted pieces of stripes.

Agenda

There are some really challenging and interesting questions about the skeleton algorithm (look at the 5x5 pixel pictures):
Vertical gap
         
         
         
         
         
Horizontal gap
         
         
         
         
         
Multiple choice
         
         
         
         
         
Fake points
         
         
         
         
         
see, these are examples of decisions we have to make in order to join gaps: one dimensional (horizontal and vertical) and two dimensional. Decisions are:

Fake displacement

There is a very clear and visible bug that makes the whole picture shift one (or more) pixel to the right side. So after a fifth time I've applied the algo to a picture — it is shifted from the original position five (or even more) pixels to the right side. It makes the picture worse than it could be without displacement because there are borders staying without any impact and when we average displaced inner square using the same border pixels we acquire some mistake. Even if we consider only the inner averaging within the square being displaced we all the same acquire a mistake when a picture is spreaded over the given square. We gotta sharpen maxima stripes and spead black holes. But when we spread white areas over the square we get our skeleton overlayed.

Feb 26 2008
Averaging weight coefficient matrix

So, this is one of the most crucial moments — which mask to use in averaging those weight coefficients? This procedure should fix a local problems like square areas 10x10 pixels of dark spots in the middle of the maximum line. So it should be really big like 20x20 pixels and use info from far elements pretty much in the same weight as the nearest ones. So, it is rather simple average than gauss. Median filter also does not seem appropriate because damage does not look like a single pixel noise. The damage is of a large area type.

Feb 25 2008
Linear contrast. Equalization.

The two most needed algos: contrast and equalization works (in a nutshell) in the following ways.

Linear contrast

Let's assume we have an original (quantified) image with its minimal value xmin and maximum value xmax. And we wanna add some contrast in that picture so as the minimal value becomes ymin and the maximal one — ymax. Then the simple formula is applied to an each pixel value:

y(x) = (x - xmin) * (ymax - ymin) / (xmax - xmin) + ymin

So, we need to figure out what is the minimal and the maximal original values are and then to understand which values we wanna have instead.

Equalization

We build the histogram of quantified values H(xk), where k is from [0..K-1]. Then the result value y(xk) = Max * Sum(H(xk), xi<xk), where Max is the the maximal resulting value.

So, first we build the histo and then calculate each pixel value. Also a double passage algo as the first one is.

Feb 21 2008
Some improvements

Since last time I wrote here I've got some new functions and filters done:

Now after applying the average procedure and then low-pass filter, Corel Trace gives me almost the result which I recently obtained by applying ImageJ Smooth algo. So, one more algo in my program and no need of another programms. Final thing to do is to write the coefficient averaging.

I'm afraid that it is going to be a really long procedure. But I should try first then face the fact. Cause I've got nothing to do now. Why should I waste my time.

Then I should think about the single-pixel restoring algo.

Feb 15 2008
Corel Trace Centerline

The most appropriate algo of all the seen ones is Corel Trace Centerline algo. However, it requires picture to be processed to be black and white. I.e. firstly it asks about a threshold of pixel intensity to perceive it like a black one (R 0, G 0, B 0) or white one (R 255, G 255, B 255). And only after that conversion it applies its algo to build single-pixel skeleton.

So the algo knows for sure that there only two possible pixel intensities: white and black. The algo can be very simple -- it can leave a middle point of any given white stripe.

ImageJ Smooth then Corel Trace BW and finally Corel Trace Centerline produce a very nice picture though there are some intersections left. And also the centerline algo leaves centers of the dark stripes. But it's easy to fix by Corel Trace Invert procedure.

It is definitely different algo in concept. If I start implement it I should stop implement first one. It is probably good. Cause I can see advantages and disadvantages of both algos. But maybe I should not implement it cause ImageJ+CorelTrace already does it. And I am not quite sure it is the algo I need. Lines are interrupted, there are intersections. If I was sure I would definitely make that algo by my self in order to apply it on real pictures.

Feb 14 2008
 

I need some features to be added into the GUI of the program:

First processed (averaged) pictures show that nothing is really being averaged using my coefficients and not implemented weight functions. What is does is only adding white dots between white stripes where the minimum stripes go. Which is completely opposite to what should be done.

Brand image processors

Again tried ImageJ. It works pretty nice though skeleton still isn't appropriate. But the Smooth is very nice. Especially if combined with Enhance contrast procedure. May be I should implement the enhancing two.

And also I tried the PhotoShop in order if it has something for me. Well, the most appropriate filters seem to be: Brush-AccentedEdges, Brush-DarkStrokes, Brush-InkOutlines. Though the Photoshop doesn't leave single-pixelized skeleton two.

Feb 13 2008
 

I tried two software products on the interferogram processing: Corel Trace and ImageJ. The second one written on Java does not have any appropriate feature though has reall useful ones in image processing at all.

First one built by Corel makes my pictures very nice but not completely. It makes the skeleton picture but does not eliminate the serifs on the skeleton. There are a lot of serif left after the algo is applied even many times. Not once. Also the Trace leaves some noise between the skeleton lines.

So, by the end of the week I'm to finish the first approach of averaging in the processing algo.

Feb 12 2008
 

Ok. Now I wanna realize how does really the garbage collector works in matter of when it is allowed to free an allocated memory that we have a link to. This question is arisen because of many intermediate procedures in image processing which allocate new and new copies of an image. And it is really nice to know whether this memory is deleted right after finishing of just another procedure or it waits until the program stops.

The answer seems to be that if we are out of the scope (where the link was allocated) the link is disposed next time the GC works.

Ok. Now I wrote shifter and setter delegates and made arrays with 'em so in future I'm going to advance pixels in directions using those shifters and setters.

Feb 03 2008
The end aim

Latest aim to be achieved is to make single-pixel skeleton from a given interferogram.

Dec 17 2007
Painting data representation

Ok. I've decided the picture itself (I work at) is displayed by PictureBox control which has two the most important properties for that:

I chose Zoom mode cause it allows to display the image proportionally. Seems the most appropriate cause I have to work with stripes and proportions matter.

Now I have some questions:

Resizing painting window

Let's suppose we have painted an object that does not own any information about that. It was painted in the window having w and h sizes. Now they are wEnd and hEnd. Since I want objects to be painted proportionally, I have to repaint 'em with sizes multiplied by sMaxEnd/sMax, where sMax — is the biggest size of two (w and h). So, each time I have to calculate that factor by which object's boundaries should change.

Fucken PictureBox covers the painting I made on PictureBox.CreateGraphics() by some unknown event. I've already tried:

It does not help. After resizing my painting is covered by the image even if I repainted it by myself once again. What the fuck is going on downthere?

Ok. I can do the following. Make a Bitmap from the image. Paint on that Bitmap by using it's Graphics and then I set the PictureBox.Image to modified Bitmap.

Dec 16 2007
Adding picture files

Ok, I gotta add pictures in a way that I can woek with many pictures simultaneosly. That's why I need control for collecting those interferometer pictures. I've already chosen ComboListBox cause it allows to choose single picture at a time and simultaneously have some another loaded.


 _____________________________
| picture name number k.bmp |v|
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

I put an item into MenuStrip called «Add picture» which add picture and another one — «Close picture» which deletes current picture from the list.

Dec 10 2007
PictureBox control smoking

Main properties are:

Here is an example from out lovely MSDN:
private Bitmap MyImage ;
public void ShowMyImage(String fileToDisplay, int xSize, int ySize)
{
   // Sets up an image object to be displayed.
   if (MyImage != null)
   {
      MyImage.Dispose();
   }

   // Stretches the image to fit the pictureBox.
   pictureBox1.SizeMode = PictureBoxSizeMode.StretchImage ;
   MyImage = new Bitmap(fileToDisplay);
   pictureBox1.ClientSize = new Size(xSize, ySize);
   pictureBox1.Image = (Image) MyImage ;
}

Ivan Yurlagin,