Click here to Skip to main content
Rate this: bad
good
Please Sign up or sign in to vote.
See more: C#
Hi:
I have developed code to scan different sections of an image on background panel, after Otsu Thresholding has been applied to the image, and add up pixel values. After this it should evaluate whether the values are above or below a set threshold value. If any of those sections are above the threshold value a rectangle should be drawn around the sections.
 
The code below shows the array population and scan and a poor attempt at drawing on the image.
            Bitmap myImage;
            myImage = (Bitmap)Image.FromFile(openFileDialog1.FileName);
            panel1.BackgroundImage = myImage;
 
            // Array for keeping the sums of each row of pixels
            float[] resultArray = new float[myImage.Height];
 
            // Populate the array with data from each row of pixels, using the brightness value
            for (int i = 0; i > 26 && i < 39; i++)
            {
                
                float value1 = 0;
                for (int j = 0; j > 22 && j < 35; j++)
                {
                    value1 += myImage.GetPixel(j, i).GetBrightness();
                }
                resultArray[i] = value1;
 
                if (value1 > 0)
                {
 
                    Pen pen = new Pen(Color.Red, 2);
                    Graphics g = panel1.CreateGraphics();
                    g.DrawRectangle(pen, 10, 10, 50, 50);
                }
 
This is just one array for the first section. I guess the best thing to do would be to create a function for the drawing part and just pass it the values of the arrays from a switch, case1, case2, etc. But my main concern is getting help to draw around the section detailed above. I have set the if condition to value > 0 for now just to be sure and test it works.
Thank you.
Posted 25-Feb-13 6:18am
Comments
Sergey Alexandrovich Kryukov at 25-Feb-13 12:24pm
   
You are doing it wrong. It will get you nowhere, because if unacceptable performance. SetPixel/SetPixel is too slow.
—SA
Sergey Alexandrovich Kryukov at 25-Feb-13 12:25pm
   
And don't create Graphics...
—SA
defunktlemon at 25-Feb-13 12:30pm
   
you want me to use LockPixels?
Sergey Alexandrovich Kryukov at 25-Feb-13 13:47pm
   
No, you want to use LockPixels. Of course. :-)
I answered, please see Solution 1.
—SA

1 solution

Rate this: bad
good
Please Sign up or sign in to vote.

Solution 1

Yes, if you really need to access individual pixels, the only reasonable way to go is using System.Drawing.Bitmap.LockBits:
http://msdn.microsoft.com/en-us/library/system.drawing.bitmap.lockbits.aspx[^].
 
Now, if you are creating the instance of Graphics somewhere using its constructor and draw, the graphics will not persist on screen. You need to override System.Windows.Graphics.Control.OnPaint or handle the event System.Windows.Graphics.Control.Paint and do all your rendering in the handler, using the instance of Graphics passed to the handler in the event arguments. Please see my past answers:
What kind of playful method is Paint? (DataGridViewImageCell.Paint(...))[^] (the background is explained here),
Drawing Lines between mdi child forms[^],
capture the drawing on a panel[^],
How to speed up my vb.net application?[^].
 
—SA
  Permalink  
v2
Comments
defunktlemon at 25-Feb-13 16:34pm
   
ok. I have gotten the lockbits, or lickbits as you like to call it :), into the program.
 
But no image loads into the panel? Can I use a panel or should it be picturebox? If I am not mistaken you are not a fan of picturebox as much as get / set pixels :)
Sergey Alexandrovich Kryukov at 25-Feb-13 16:42pm
   
Fist, not need to use PictureBox, ever. This is not about being a fun or not. This control is totally redundant in principle, you can do everything without it. It just depends on what you are doing. Is something simple, it just a read-to-use control, can simplify things; in other cases help you at all, if you modify an image in any ways, only adds a hassle...
What is image loads? No. Due to the need for LockBits, you just an image as an intermediate container of data. When the image is done, you can draw it using Graphics.DrawImage, in OnPaint or Paint handler, or put this image in a PictureBox...
Will you accept the answer formally now (green button)?
—SA
defunktlemon at 25-Feb-13 16:41pm
   
I have a question about this method Sergey. As stated in the original problem above, I would like for this to scan the image in a few different sections and draw around those sections which have a certain pixel value higher than a threshold set. It is possible to do that with this method, right?
Sergey Alexandrovich Kryukov at 25-Feb-13 16:43pm
   
I understand. This algorithm really requires access to individual bits, that's why I recommended to use LockBits (thanks for a fix of my typo; I updated the text).
—SA
defunktlemon at 25-Feb-13 16:50pm
   
I think this may be way too advanced for me - i'm just a newbie. Don't you think it is better for a newbie to not worry about performance so much and just use the Get / Set pixels as they are easier?
Sergey Alexandrovich Kryukov at 25-Feb-13 17:03pm
   
No, I don't think so. Here, there are no more and less advanced ways: you either solve this problem or not, your choice.
If you have enough spare time, try it with GetPixel/SetPixel, to see how bad is the performance.
Let me put it this way: instead of solving some problem in a bad way, better don't solve it at all.
—SA
defunktlemon at 25-Feb-13 17:14pm
   
so, can I go from the lockpixel into a new method to open and draw that image in a panel with a buttonclick method?
like, how do i get to see the image with the rectangle drawn on it from this point?
Sergey Alexandrovich Kryukov at 25-Feb-13 17:18pm
   
Same way you do it with GetPixel/SetPixel, only you get set pixels from byte array. It depends on pixel format. Please see the sample code, it should make it clear what to do.
—SA
defunktlemon at 25-Feb-13 18:28pm
   
hey! how's this Sergey
 
public Form1()
{
InitializeComponent();
}
private void LockUnlockBitsExample(PaintEventArgs e)
{
 
Bitmap myImage = new Bitmap("C:\\Users\\jason\\Documents\\IProject\\code\\imageAlign\\imageAlign\\bin\\Debug\\good.jpg");
 

// Lock the bitmap's bits.
Rectangle rect = new Rectangle(0, 0, myImage.Height, myImage.Width);
System.Drawing.Imaging.BitmapData bmpData =
myImage.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite,
myImage.PixelFormat);
 
// Get the address of the first line.
IntPtr ptr = bmpData.Scan0;
 
// Declare an array to hold the bytes of the bitmap.
int bytes = Math.Abs(bmpData.Stride) * myImage.Height;
byte[] rgbValues = new byte[bytes];
 
// Copy the RGB values into the array.
System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes);
 

// Set every third value to 255. A 24bpp bitmap will look red.
for (int counter = 2; counter < rgbValues.Length; counter += 3)
rgbValues[counter] = 255;
 

// Copy the RGB values back to the bitmap
System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, bytes);
 
// Unlock the bits.
myImage.UnlockBits(bmpData);
 
// Draw the modified image.
e.Graphics.DrawImage(myImage, 0, 150);
}
 
private void button1_Click(object sender, EventArgs e)
{
openFileDialog1.Filter = "JPEG IMAGES|*.jpg";
openFileDialog1.InitialDirectory = "C:\\Users\\jason\\Documents\\IProject\\code\\imageAlign\\imageAlign\\bin\\Debug";
openFileDialog1.Title = "Open Image";
if (openFileDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
panel1.BackgroundImage = Image.FromFile(openFileDialog1.FileName);
panel1.Invalidate();
}
Bitmap myImage;
myImage = (Bitmap)Image.FromFile(openFileDialog1.FileName);
panel1.BackgroundImage = myImage;
 
// Array for keeping the sums of each row of pixels
float[] resultArray = new float[myImage.Height];
 
// Populate the array with data from each row of pixels, using the brightness value
for (int i = 0; i < myImage.Height; i++)
{
float value = 0;
for (int j = 0; j < myImage.Width; j++)
{
value += myImage.GetPixel(j, i).GetBrightness();//get colour of pixel and that Hue-Saturation-Brightness values
}
resultArray[i] = value;
}
}
Sergey Alexandrovich Kryukov at 25-Feb-13 18:53pm
   
Well, you don't show where you call LockUnlockBitsExample, but looks fine from the first glance. Did you run it?
If you need to discuss any code, better move it to the question where you can format it, using "Improve question".
—SA
defunktlemon at 25-Feb-13 19:12pm
   
I ran it - it ran ok and loaded the image. but are the lockpicks and image display linked. they seem separate and unrelated. So, I run the lockpicks ok, but then run the buttonclick as a separate thing.
 
"better move it to the question where you can format it"
 
it was in the 'Have a Question or Comment'link. Is that wrong?
Sergey Alexandrovich Kryukov at 25-Feb-13 19:27pm
   
Yes, in comment it's not so readable, because you can't use "pre" tag, as in the body of the question.
I did not get what is the remaining problem. You are right, LockBits is not related to display, it only helps you to read or modify bitmap pixels. You can always use a bitmap never showing it. For example, you can generate some images and store them in some stream, file, database or network...
—SA

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

  Print Answers RSS
0 Sergey Alexandrovich Kryukov 335
1 Gihan Liyanage 332
2 OriginalGriff 236
3 ClimerChinna 222
4 vikinghunter 168
0 Sergey Alexandrovich Kryukov 8,243
1 OriginalGriff 7,109
2 CPallini 2,598
3 Richard MacCutchan 1,980
4 Abhinav S 1,778


Advertise | Privacy | Mobile
Web03 | 2.8.140827.1 | Last Updated 25 Feb 2013
Copyright © CodeProject, 1999-2014
All Rights Reserved. Terms of Service
Layout: fixed | fluid

CodeProject, 503-250 Ferrand Drive Toronto Ontario, M3C 3G8 Canada +1 416-849-8900 x 100