Click here to Skip to main content
Sign Up to vote bad
good
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:18

Comments
Sergey Alexandrovich Kryukov - 25 Feb '13 - 12:24
You are doing it wrong. It will get you nowhere, because if unacceptable performance. SetPixel/SetPixel is too slow. —SA
Sergey Alexandrovich Kryukov - 25 Feb '13 - 12:25
And don't create Graphics... —SA
defunktlemon - 25 Feb '13 - 12:30
you want me to use LockPixels?
Sergey Alexandrovich Kryukov - 25 Feb '13 - 13:47
No, you want to use LockPixels. Of course. :-) I answered, please see Solution 1. —SA

1 solution

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  
Comments
defunktlemon - 25 Feb '13 - 16:34
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 - 25 Feb '13 - 16:42
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 - 25 Feb '13 - 16:41
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 - 25 Feb '13 - 16:43
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 - 25 Feb '13 - 16:50
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 - 25 Feb '13 - 17:03
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 - 25 Feb '13 - 17:14
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 - 25 Feb '13 - 17:18
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 - 25 Feb '13 - 18:28
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 - 25 Feb '13 - 18:53
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 - 25 Feb '13 - 19:12
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 - 25 Feb '13 - 19:27
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
Your Filters
Interested
Ignored
     
0 OriginalGriff 223
1 Ron Beyer 220
2 Aarti Meswania 200
3 Mahesh Bailwal 175
4 Rohan Leuva 170
0 Sergey Alexandrovich Kryukov 8,553
1 OriginalGriff 6,899
2 CPallini 3,648
3 Rohan Leuva 2,963
4 Maciej Los 2,308


Advertise | Privacy | Mobile
Web04 | 2.6.130516.1 | Last Updated 25 Feb 2013
Copyright © CodeProject, 1999-2013
All Rights Reserved. Terms of Use
Layout: fixed | fluid