ImonBayazid
ImonBayazid

Reputation: 1096

Calculating How much curve in a straight line into a image using processing in C#

I have a images like below enter image description here enter image description here

Here there is a line. This line is not straight everywhere. In the middle part of the line there is a curve. My work is to calculate that how much the line is straight or how much the line is curved ??? How can i do that using C# . I searched everywhere but cant get any idea how to do that. Have anyone any idea how to do that?? My aim is not only to detect a line but also to calculate how much curve the line is??

Upvotes: 3

Views: 1151

Answers (2)

Mark Setchell
Mark Setchell

Reputation: 207550

My approach would probably be more basic and I would use ready-made tools where possible. So I would go the following way:

Step 1. Use ImageMagick convert to threshold and grayscale the image and write it out as PGM (Portable Grey Map) so I didn't have to understand DIBs and JPEGs.

convert EuJpb.jpg -threshold 10% -compress none 1.pgm

Contents of resulting file "1.pgm"

P2
1200 400
255
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
...
... 255 255 255 ... 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
... 0 0 255 255 ... 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
...

I have had to render it as a JPEG for display here, but this is what you get:

enter image description here Step 2

Write some pretty simple C (or more likely awk or Perl) to generate a list of points from the easy-to-read PGM.

Something like this:

#!/bin/bash
# First put each sample on its own line to make processing easier
cat 1.pgm | tr ' ' '\n' | sed '/^$/d' | awk '
   NR==2{w=$1;x=0;y=0}         # Line 2 is the image width
   NR==3{h=$1}                 # Line 3 is the image height
   NR>=5{                      # Line 5 onwards are the pixel values
      if($1>0){                # If pixel non-zero, output point
         printf "%d,%d\n",x,y
      }
      # Calculate new x and y for next point
      if(x++==w){
         x=0;y++
      }
   }' > points.txt

Step 3

Put the points (in points.txt) into gnuplot and fit a line of the format y=ax + b and look at the standard deviations of the residuals to get a measure of straightness.

Save this as plotcmds

set title 'Plotted with Gnuplot'
set ylabel 'y-axis (inverted)'
set xlabel 'x-axis'
set yrange [0:400]
set xrange [0:1200]
f(x)=a*x+b
fit f(x) 'points.txt' using 1:2 via a,b
plot 'points.txt',f(x) with lines linestyle 3
set terminal postscript color landscape dashed enhanced 'Times-Roman'
set output 'file.eps'
set size 1,0.5
replot

Then run using:

gnuplot plotcmds

The statistics are output here:

resultant parameter values

a               = -0.0331951
b               = 218.852

After 5 iterations the fit converged.
final sum of squares of residuals : 2.39695e+06
rel. change during last iteration : -1.14297e-11

degrees of freedom    (FIT_NDF)                        : 3931
rms of residuals      (FIT_STDFIT) = sqrt(WSSR/ndf)    : 24.6932
variance of residuals (reduced chisquare) = WSSR/ndf   : 609.755

Final set of parameters            Asymptotic Standard Error
=======================            ==========================

a               = -0.0331951       +/- 0.001672     (5.035%)
b               = 218.852          +/- 0.8006       (0.3658%)


correlation matrix of the fit parameters:

               a      b      
a               1.000 
b              -0.871  1.000

As you can see, the best line is y=-0.033x + 218 (my origin is top-left by the way, so essentially upside down). Now you can compare the residuals to get an idea of the measure of deviation from a straight line.

Here is the plot, with the calculated points in red and the best-fit straight line in blue(ish).

enter image description here

Upvotes: 2

Mihai Hantea
Mihai Hantea

Reputation: 1743

This is just a sample using the EmguCV wrapper over OpenCV image processing library detecting the lines. Of course this is not 100% accurate, you will have to tweak a little more. When you get the lines you may calculate the curve.

Or another way is to implement your own algorithm to detect the lines.

Using this algorithm I got 16 lines from the provided image. With some tweak you can get more accurate number.

var bmp = new Bitmap(pathToImage);

                //Load the image from file and resize it for display
        using (Image<Bgr, Byte> img = new Image<Bgr, byte>(bmp))
        {
            //Convert the image to grayscale and filter out the noise
            using (Image<Gray, Byte> gray = img.Convert<Gray, Byte>().PyrDown().PyrUp())
            {
                Gray cannyThreshold = new Gray(180);

                #region Canny and edge detection

                Gray cannyThresholdLinking = new Gray(120);
                Image<Gray, Byte> cannyEdges = gray.Canny(cannyThreshold, cannyThresholdLinking);
                LineSegment2D[] lines = cannyEdges.HoughLinesBinary(
                    1, //Distance resolution in pixel-related units
                    Math.PI/60.0, //Angle resolution measured in radians.
                    20, //threshold
                    30, //min Line width
                    10 //gap between lines
                    )[0]; //Get the lines from the first channel

                #endregion
            }
        }

Upvotes: 2

Related Questions