 |
|
|
 |
|
|
Hello: I'm trying to use Fast Pixel and it seems to work for some of my bitmpas...while giving me this error for others:
Index was outside the boundws of the array(see ''it bombs on this line: ' to see exact line below). I understand that the array isn't big enough but i don't understand why it works for some of my bitmaps and not others. When I save my bitmaps, I save them as 24 bit rgb color 300 dpi. I don't know much about resolutions and what format is best to save them as.
Any thoughts are truly appreciated.
Public Function GetPixel(ByVal x As Integer, ByVal y As Integer) As Color If Not Me.locked Then Throw New Exception("Bitmap not locked.") Return Nothing End If
If Me.IsAlphaBitmap Then Dim index As Integer = ((y * Me.Width + x) * 4) Dim b As Integer = Me.rgbValues(index) Dim g As Integer = Me.rgbValues(index + 1) Dim r As Integer = Me.rgbValues(index + 2) Dim a As Integer = Me.rgbValues(index + 3) Return Color.FromArgb(a, r, g, b) Else Dim index As Integer = ((y * Me.Width + x) * 3) 'it bombs on this line: Dim b As Integer = Me.rgbValues(index) Dim g As Integer = Me.rgbValues(index + 1) Dim r As Integer = Me.rgbValues(index + 2) Return Color.FromArgb(r, g, b) End If End Function
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
I have a bitmap that is 641 X 480 Running the code as in the example yeilds different results when compared to just using the getpixel and setpixel on the bitmap object.
Here is the code to test and see the problem.
Dim fp As New FastPixel(bmp) Dim x As Integer, y As Integer Dim c As Color fp.Lock() For y = 0 To fp.Height - 1 Step 5 For x = 0 To fp.Width - 1 c = fp.GetPixel(x, y) If c.GetBrightness < 0.3 Then fp.SetPixel(x, y, Color.Red) End If Next Next fp.Unlock(True) PictureBox1.Image = fp.Bitmap
And the getpixel and setpixel off the bitmap object as
Dim x As Integer, y As Integer Dim c As Color For y = 0 To bmp.Height - 1 Step 5 For x = 0 To bmp.Width - 1 c = bmp.GetPixel(x, y) If c.GetBrightness < 0.3 Then bmp.SetPixel(x, y, Color.Red) End If Next Next
|
| Sign In·View Thread·PermaLink | 1.33/5 (3 votes) |
|
|
|
 |
|
|
Your article demonstrated an improvement over SetPixel/GetPixel() baby. A good piece of work. I gave it 5. Thanks for sharing.
I am just curious about how we can make this work on MFC/GDI. What is the counterpart of scan0() in GDI?
-- modified at 18:34 Saturday 6th January, 2007
I've found the counterpart GetBitmapBits/GetDIBits(), which return the entire bitmap bits, instead of individual pixels like GetPixel(). Similarly, they work much faster than GetPixel() calls.
Best, Jun
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
using System; using System.Drawing; using System.Drawing.Imaging;
class FastPixel { private byte[] rgbValues; private BitmapData bmpData; private IntPtr bmpPtr; private bool locked = false;
private bool _isAlpha = false; private Bitmap _bitmap; private int _width; private int _height;
public int Width { get { return this._width; } }
public int Height { get { return this._height; } }
public bool IsAlphaBitmap { get { return this._isAlpha; } }
public Bitmap Bitmap { get { return this._bitmap; } }
public FastPixel(Bitmap bitmap) { if (bitmap.PixelFormat == (bitmap.PixelFormat | PixelFormat.Indexed)) throw new Exception("Cannot lock an Indexed image.");
this._bitmap = bitmap; this._isAlpha = (this.Bitmap.PixelFormat == (this.Bitmap.PixelFormat | PixelFormat.Alpha)); this._width = bitmap.Width; this._height = bitmap.Height; }
public void Lock() { if (this.locked) throw new Exception("Bitmap already locked.");
Rectangle rect = new Rectangle(0, 0, this.Width, this.Height); this.bmpData = this.Bitmap.LockBits(rect, ImageLockMode.ReadWrite, this.Bitmap.PixelFormat); this.bmpPtr = this.bmpData.Scan0;
if (this.IsAlphaBitmap) { int bytes = (this.Width * this.Height) * 4; this.rgbValues = new byte[bytes]; System.Runtime.InteropServices.Marshal.Copy(this.bmpPtr, rgbValues, 0, this.rgbValues.Length); } else { int bytes = (this.Width * this.Height) * 3; this.rgbValues = new byte[bytes]; System.Runtime.InteropServices.Marshal.Copy(this.bmpPtr, rgbValues, 0, this.rgbValues.Length); } this.locked = true; }
public void Unlock(bool setPixels) { if (!this.locked) throw new Exception("Bitmap not locked.");
// Copy the RGB values back to the bitmap; if (setPixels) System.Runtime.InteropServices.Marshal.Copy(this.rgbValues, 0, this.bmpPtr, this.rgbValues.Length);
// Unlock the bits.; this.Bitmap.UnlockBits(bmpData); this.locked = false; }
public void Clear(Color colour) { if (!this.locked) throw new Exception("Bitmap not locked.");
if (this.IsAlphaBitmap) { for (int index = 0; index < this.rgbValues.Length; index += 4) { this.rgbValues[index] = colour.B; this.rgbValues[index + 1] = colour.G; this.rgbValues[index + 2] = colour.R; this.rgbValues[index + 3] = colour.A; } } else { for (int index = 0; index < this.rgbValues.Length; index += 3) { this.rgbValues[index] = colour.B; this.rgbValues[index + 1] = colour.G; this.rgbValues[index + 2] = colour.R; } } }
public void SetPixel(Point location, Color colour) { this.SetPixel(location.X, location.Y, colour); }
public void SetPixel(int x, int y, Color colour) { if (!this.locked) throw new Exception("Bitmap not locked.");
if (this.IsAlphaBitmap) { int index = ((y * this.Width + x) * 4); this.rgbValues[index] = colour.B; this.rgbValues[index + 1] = colour.G; this.rgbValues[index + 2] = colour.R; this.rgbValues[index + 3] = colour.A; } else { int index = ((y * this.Width + x) * 3); this.rgbValues[index] = colour.B; this.rgbValues[index + 1] = colour.G; this.rgbValues[index + 2] = colour.R; } }
public Color GetPixel(Point location) { return this.GetPixel(location.X, location.Y); }
public Color GetPixel(int x, int y) { if (!this.locked) throw new Exception("Bitmap not locked.");
if (this.IsAlphaBitmap) { int index = ((y * this.Width + x) * 4); int b = this.rgbValues[index]; int g = this.rgbValues[index + 1]; int r = this.rgbValues[index + 2]; int a = this.rgbValues[index + 3]; return Color.FromArgb(a, r, g, b); } else { int index = ((y * this.Width + x) * 3); int b = this.rgbValues[index]; int g = this.rgbValues[index + 1]; int r = this.rgbValues[index + 2]; return Color.FromArgb(r, g, b); } } }
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
I'm not sure I see the point of all this - for the speed differences to be manifest, surely you'd have to do a lot of pixel access, in which case writing your own code that doesn't add a function call or two for each pixel would be even faster ?
Christian Graus - Microsoft MVP - C++ Metal Musings - Rex and my new metal blog
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Err, the point of this code is to create something faster than Bitmap.GetPixel/Bitmap.SetPixel.
I think it's far succeeded it's requirement.
startmenuex.com
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
I have a need to convert images to 1 bit and do this now by looking pixel by pixel and determining how dark the pixel is and i set it white or black based on that. this is painfully slow, about 5 seconds per decent sized image. I am wondering if this method would help? I know in C# you can use pointers and unsafe methods to do some stuff that is more efficient, but i'm using VB.
Thanks!
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Yep,
I've done something very similar to that in VB.NET, it was over 6 months ago which means I have little memory of actual hows and whys. As I recall it decides which pixels are 'whiteish' and colours them green and which pixels are 'blackish' and colours them red (or maybe vice versa), oh and it keeps count, but it should be pretty simple to modify to your purposes. No promises as to quality of the code, I am sure there are others who can do that for you, but it did the job.
Alex
PS. it strikes me that I almost certainly modified code written by someone else to do this and I wouldn't wish to steal their thunder. If anyone recognises who the original source might be please comment to credit them.
Public Class blackish_whiteish
Public Shared BlackPix As Integer Public Shared WhitePix As Integer
Public Shared Function ProcessImage(ByRef b As Bitmap) As Bitmap Return bwProcessImage(b) End Function
Private Shared Function bwProcessImage(ByRef b As Bitmap) As Bitmap
'initialise BlackPix = 0 WhitePix = 0
'create array to store pixel data Dim resArray(b.Width) As Double
'lock bits Dim bmData As BitmapData = b.LockBits(New Rectangle(0, 0, b.Width, b.Height), _ System.Drawing.Imaging.ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb)
'width of bitmap row in memory Dim stride As Integer = bmData.Stride
'pointers to the start of the bitmap data Dim scan0 As IntPtr = bmData.Scan0
' array to hold the colors Dim pixels(stride * b.Height - 1) As Byte Marshal.Copy(scan0, pixels, 0, pixels.Length)
'store position of current pixel Dim position As Integer
' store the current pixels RGB: Dim R0, G0, B0 As Integer
'sort out black, white, blackish, whiteish
For x As Integer = 0 To b.Width - 1 'zero the array resArray(x) = 0 For y As Integer = 0 To b.Height - 1 'position of current pixel's first byte: position = (y * stride) + (x * 4)
B0 = pixels(position) G0 = pixels(position + 1) R0 = pixels(position + 2)
If (B0 + G0 + R0 = 765) Or (B0 + G0 + R0 = 0) Then 'black or white If (B0 + G0 + R0 = 0) Then BlackPix = BlackPix + 1 resArray(x) = resArray(x) + 1 Else WhitePix = WhitePix + 1 End If Else If (B0 + G0 + R0 > 382) Then pixels(position) = Convert.ToByte(0) pixels(position + 1) = Convert.ToByte(0) pixels(position + 2) = Convert.ToByte(255) WhitePix = WhitePix + 1 Else
pixels(position) = Convert.ToByte(0) pixels(position + 1) = Convert.ToByte(255) pixels(position + 2) = Convert.ToByte(0) BlackPix = BlackPix + 1 resArray(x) = resArray(x) + 1 End If End If Next 'height
Next 'width Marshal.Copy(pixels, 0, scan0, pixels.Length) histoArray = resArray b.UnlockBits(bmData)
Return b
End Function
-- modified at 6:08 Thursday 24th August, 2006
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Having had a quick look around my hard drive, I think this is where I got the basics from:-
http://vb-helper.com/howto_net_lockbits_images_class.html
Alex
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
beckerben wrote: This doesn't use fastpixel though, will it be quick for doing the conversion?
 True it doesn't use fastpixel, but it does use the same principle (lockbits). This is much quicker than setpixel.
If you do want to try it, I suspect I should mention you will need the following at the top of the blackish_whiteish class
Imports System.Drawing.Imaging Imports System.Runtime.InteropServices
then in your project
NewBmp = blackish_whiteish.ProcessImage(SourceBmp)
I'm sure you could do just as well, if not better, using fastpixel.
In your original post you asked
beckerben wrote: I have a need to convert images to 1 bit and do this now by looking pixel by pixel and determining how dark the pixel is and i set it white or black based on that. this is painfully slow, about 5 seconds per decent sized image. I am wondering if this method would help?
I was simply answering your question saying 'yes it would help I used the same method (lockbits) myself to do something very similar' then I thought it would be helpful to copy the code to show how I did it. I now feel that perhaps, rather than helping, I was confusing the issue, so in answer to your original post....
Yes, it would help, I used the same method (lockbits) myself to do something very similar.
Alex
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Copying whole bitmap using one Marshal.Copy operation is not 100% correct. Try to do this with 24 bpp bitmap with odd line width and you will see the problem. This can be done only when BitmapData.Stride = width * pixelSize. Otherwise, you need to copy every line using BitmapData.Stride property. You can see details here: http://www.codeproject.com/cs/media/csharpgraphicfilters11.asp[^]
-- modified at 10:07 Wednesday 16th August, 2006
|
| Sign In·View Thread·PermaLink | 5.00/5 (1 vote) |
|
|
|
 |
|
|
 |
|
|
I mean, if bitmap line width is not equal exactly to Stride, you need to copy every line separately. Beginning of the line must be calculated by formula: Scan0 + line_number * Stride. This happens because of bitmap line alignment.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
1. Allow file name to be specified as one of the contructors; 2. Allow method to return Image 3 Instead of Lock/SetPixel/Unlock include the Lock/Unlock in the body of SetPixel.
Other than that, good class maybe make a C# version.
We made the buttons on the screen look so good you'll want to lick them. Steve Jobs
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
norm .net wrote: 1. Allow file name to be specified as one of the contructors; 2. Allow method to return Image 3 Instead of Lock/SetPixel/Unlock include the Lock/Unlock in the body of SetPixel.
Other than that, good class maybe make a C# version.
Thanks
1. You could just use New FastPixel(New Bitmap("FILENAME")) 2. Bitmap returns a bitmap, you can convert this to an image if you like. 3. The purpose of using lock/setpixel/unlock is to speed up processing. You may have noticed that the pixel data only gets copied back to the bitmap when you unlock it.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
You say there's not much to talk about in your article. How about describing how it sets the pixel in locked mode? Is your code in an unsafe block? I've not looked at your code, but I'm familiar with the technique. You have to use a pointer from Scan0 and come up with an offset for the pixel, then set the bytes depending on the pixel format. There's a lot of information there that would be interesting to talk about.
How about performing the lock in a using() statement? The using will lock and unlock the BitmapData so you can do as many SetPixels within the block as you want.
Logifusion[^] If not entertaining, write your Congressman.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
I know it wasn't my post, but...
Dustin Metzgar wrote: Is your code in an unsafe block?
Yep, this technique (seemingly well-documented at this point on newgroups, forums, etc.) does make use of "unsafe" or unmanaged code. I used the same general principle in my master's thesis project.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
norm .net wrote: Instead of Lock/SetPixel/Unlock include the Lock/Unlock in the body of SetPixel
Sure about that one?
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Think so
We made the buttons on the screen look so good you'll want to lick them. Steve Jobs
|
| Sign In·View Thread·PermaLink | 2.00/5 (1 vote) |
|
|
|
 |