gghuffer
gghuffer

Reputation: 1143

Plot values of a line from a grayscale image

I am trying to take a grayscale bitmap and extract a single line from it and then graph the gray values. I got something to work, but I'm not really happy with it. It just seems slow and tedious. I am sure someone has a better idea

WriteableBitmap someImg; //camera image
int imgWidth = someImg.PixelWidth;
int imgHeight = someImg.PixelHeight;

Int32Rect rectLine = new Int32Rect(0, imgHeight / 2, imgWidth, 1); //horizontal line half way down the image as a rectangle with height 1
//calculate stride and buffer size
int imgStride = (imgWidth * someImg.Format.BitsPerPixel + 7) / 8; // not sure I understand this part
byte[] buffer = new byte[imgStride * rectLine.Height];
//copy pixels to buffer
someImg.CopyPixels(rectLine, buffer, imgStride, 0);
const int xGraphHeight = 256;
WriteableBitmap xgraph = new WriteableBitmap(imgWidth, xGraphHeight, someImg.DpiX, someImg.DpiY, PixelFormats.Gray8, null);
//loop through pixels
for (int i = 0; i < imgWidth; i++)
     {
        Int32Rect dot = new Int32Rect(i, buffer[i], 1, 1);  //1x1 rectangle
        byte[] WhiteDotByte = { 255 };                      //white
        xgraph.WritePixels(dot, WhiteDotByte, imgStride, 0);//write pixel 
     }

the image and the graph below it

You can see the image and the plot below the green line. I guess I am having some WPF issues that make it look funny but that's a problem for another post.

Upvotes: 0

Views: 185

Answers (1)

JonasH
JonasH

Reputation: 36446

I assume the goal is to create a plot of the pixel value intensities of the selected line.

The first approach to consider it to use an actual plotting library. I have used oxyplot, it works fine, but is lacking in some aspects. Unless you have specific performance requirements this will likely be the most flexible approach to take.

If you actually want to render to an image you might be better of using unsafe code to access the pixel values directly. For example:

xgraph.Lock(); 
for (int y = 0; y < imgHeight; y++){
 var rowPtr = (byte*)(xgraph.BackBuffer + y * xgraph.BackBufferStride);
 for(int x = 0; x < imgWidth; x++){
    rowPtr[x] = (byte)(y < buffer[i] ? 0 : 255);
  }
}
self.Unlock(); // this should be placed in a finally statement

This should be faster than writing 1x1 rectangles. It should also write columns instead of single pixels, and that should help making the graph more visible. You might also consider allowing arbitrary image height and scale the comparison value.

If you want to plot the pixel values along an arbitrary line, and not just a horizontal one. You can take equidistant samples along the line, and use bilinear interpolation to sample the image.

Upvotes: 1

Related Questions