kcwallace Posted December 2, 2005 Posted December 2, 2005 I have an array of data that I would like to turn into an image (*.bmp,*.jpg, etc.) . Any viewable image is fine. I have already written a method of converting an individual prixel to grayscale. THank you Quote Go Beavs!!!
jo0ls Posted December 2, 2005 Posted December 2, 2005 (edited) If it is 4bytes per pixel, so the array is an array of int32s (4bytes color per pixel) then: create a new bitmap of the correct dimensions and pixelformat create a bitmapdata object from the image get the scan0 (start address) of the bitmapdata use marshal.copy to transfer the array to the bitmapdata object unlock the bitmap data object Private Function Int32ArrayToBitmap(ByVal pixels As Integer(), _ ByVal width As Integer, ByVal height As Integer) as bitmap Dim bm1 As New Bitmap(width, height, Imaging.PixelFormat.Format32bppArgb) Dim bitmapdata1 As Imaging.BitmapData bitmapdata1 = bm1.LockBits(New Rectangle(0, 0, width, height), _ Imaging.ImageLockMode.WriteOnly, Imaging.PixelFormat.Format32bppArgb) Dim scan0 As IntPtr = bitmapdata1.Scan0 ' copy the array starting at 0 to the bitmapData, copy all pixels (wid*hei) Runtime.InteropServices.Marshal.Copy(pixels, 0, scan0, width * height) bm1.UnlockBits(bitmapdata1) 'bm1 now contains the image 'can save with e.g. bm1.Save("Blah.jpg", Imaging.ImageFormat.Jpeg) Return bm1 End Function Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load ' Test Dim array1(320 * 200) As Integer Dim randomgenerator As New Random For i As Integer = 0 To (320 * 200) - 1 Dim randColor As Integer randColor = (255 << 24) _ Or (randomgenerator.Next(0, 256) << 16) _ Or (randomgenerator.Next(0, 256) << 8) _ Or randomgenerator.Next(0, 256) array1(i) = randColor Next Me.BackgroundImage = Int32ArrayToBitmap(array1, 320, 200) End Sub If you have 3 bytes per pixel then it is different as each row of pixel data has to end on a 4 byte boundary. So it kind of depends on your array / pixelformat. Edited December 2, 2005 by jo0ls Quote
kcwallace Posted December 2, 2005 Author Posted December 2, 2005 Thank you. You guidance helped me significantly Quote Go Beavs!!!
kcwallace Posted December 2, 2005 Author Posted December 2, 2005 One More question I was converting the color to gray by doing the following, but is comes out multi colored GScale = (ODArr(X, Y) / 6 * 256) ODArrN(X, Y) = Color.FromArgb(GScale, GScale, GScale).ToArgb Do you have any suggestions? Quote Go Beavs!!!
Leaders snarfblam Posted December 2, 2005 Leaders Posted December 2, 2005 (edited) You need to find the average of the color channels. Assuming that this is an ARGB image stored in an array of Int32s (Integer), each Int32 holds information for the Alpha, Red, Green, and Blue channels. You probably want to maintain the Alpha channel, but Red, Green, and Blue channels should all be set to the average of the three. This is the quickest (to code) way that I can think of. Dim RGB As Int32 = OdArr(X, Y) Dim Alpha As Integer = RGB >> 24 RGB = ((RGB And 255) + ((RGB >> 8) And 255) + ((RGB >> 16) And 255)) \ 3 ODAnnR(X, Y) = Color.FromArgb(Alpha, RGB, RGB, RGB) I haven't tested this, though. Edited December 3, 2005 by snarfblam Quote [sIGPIC]e[/sIGPIC]
kcwallace Posted December 3, 2005 Author Posted December 3, 2005 You need to find the average of the color channels. Assuming that this is an ARGB image stored in an array of Int32s (Integer), each Int32 holds information for the Alpha, Red, Green, and Blue channels. You probably want to maintain the Alpha channel, but Red, Green, and Blue channels should all be set to the average of the three. This is the quickest (to code) way that I can think of. Dim RGB As Int32 = OdArr(X, Y) Dim Alpha As Integer = RGB << 24 RGB = ((RGB And 255) + ((RGB << 8) And 255) + ((RGB << 16) And 255)) \ 3 ODAnnR(X, Y) = Color.FromArgb(Alpha, RGB, RGB, RGB) I haven't tested this, though. THat did not work, it looked like the attached image. Quote Go Beavs!!!
jo0ls Posted December 3, 2005 Posted December 3, 2005 Hmm the shifts are going the wrong way: Dim Alpha As Integer = (RGB >> 24) And &HFF RGB = ((RGB And 255) + ((RGB >> 8) And 255) + ((RGB >> 16) And 255)) \ 3 but still, you shouldn't have any color, the shifts going the other way just clips the lighter greys. I did it this way to figure out what was going on: Private Sub ToGreyscale(ByRef pixels As Integer()) For i As Integer = 0 To pixels.Length - 1 Dim r, g, b As Byte r = (pixels(i) >> 16) And &HFF g = (pixels(i) >> 8) And &HFF b = pixels(i) And &HFF Dim grey As Integer = CInt((0.299 * r) + (0.587 * g) + (0.114 * b)) ' Or you could average: ' Dim average As Integer = CInt(R) + CInt(G) + CInt(B) ' average = average \ 3 ' integer division pixels(i) = (255 << 24) _ Or (grey << 16) _ Or (grey << 8) _ Or grey Next End Sub The method to get the grey from r, g and b uses an algorithm that emphasises colors that we don't see too well in b&w. I didn't use color.fromargb as it is slower and we are looping through lots of pixels. Anyway, the color must be coming from somewhere... What is in your array? Ints or bytes? How does one array item relate to the color of one pixel? Quote
Leaders snarfblam Posted December 3, 2005 Leaders Posted December 3, 2005 (edited) The method to get the grey from r' date=' g and b uses an algorithm that emphasises colors that we don't see too well in b&w. I didn't use color.fromargb as it is slower and we are looping through lots of pixels.[/quote'] Um... what? Your average RGB to grayscale conversion is (R + G + B) / 3, i.e. each channel becomes the average of the three. If you are dealing with a 32-bpp image in the form of a 32-bpp array then I had the right idea. I think I just used the wrong operator and the wrong byte order. Check this one out though: 'This structure is a union used to access color components and make 'pixels grayscale <StructLayout(LayoutKind.Explicit)> _ Public Structure ColorConv '32-bit color value <FieldOffset(0)> _ Dim ARGB As Integer 'Component access <FieldOffset(3)> _ Dim A As Byte <FieldOffset(2)> _ Dim R As Byte <FieldOffset(1)> _ Dim G As Byte <FieldOffset(0)> _ Dim B As Byte 'Make color gray Public Sub MakeGray() Dim Gray As Byte = CByte((CInt(R) + G + B) \ 3) R = Gray G = Gray B = Gray End Sub Public Shared Sub SlowMethodToMakeAnImageGrayScale(ByVal Image As System.Drawing.Bitmap) Dim ColorConverter As ColorConv 'Loop through pixels, loading them, making them gray, then storing them For I As Integer = 0 To Image.Width - 1 For J As Integer = 0 To Image.Height - 1 ColorConverter.ARGB = Image.GetPixel(I, J).ToArgb() ColorConverter.MakeGray() Image.SetPixel(I, J, Color.FromArgb(ColorConverter.ARGB)) Next Next End Sub 'This is approximately 2000 times faster Public Shared Sub MakeGrayFast(ByVal Image As Bitmap) Dim BmpData As Imaging.BitmapData = Image.LockBits(New Rectangle(0, 0, Image.Width, Image.Height), Imaging.ImageLockMode.ReadWrite, Imaging.PixelFormat.Format32bppArgb) Dim RawData As Integer() = New Integer(((BmpData.Stride \ 4) * Image.Height) - 1) {} System.Runtime.InteropServices.Marshal.Copy(BmpData.Scan0, _ RawData, 0, RawData.Length) Dim ColorProcessor As ColorConv For X As Integer = 0 To RawData.Length - 1 ColorProcessor.ARGB = RawData(X) ColorProcessor.MakeGray() RawData(X) = ColorProcessor.ARGB Next System.Runtime.InteropServices.Marshal.Copy(RawData, 0, _ BmpData.Scan0, RawData.Length) Image.UnlockBits(BmpData) End Sub End Structure http://www.geocities.com/marble_eater/dog.jpg Edited December 3, 2005 by snarfblam Quote [sIGPIC]e[/sIGPIC]
jo0ls Posted December 3, 2005 Posted December 3, 2005 I meant this one: Dim grey As Integer = CInt((0.299 * r) + (0.587 * g) + (0.114 * b)) and I meant that color.fromargb is slower than shoving bits around. Quote
kcwallace Posted December 5, 2005 Author Posted December 5, 2005 Thank you for your help. I cannot seem to make it work. I keep getting the attached image. The image is a blue shade of what I am trying to create. I am assuming that I am making an error in converting the underlying data into image data. THe underlying data starts out as a 40 x 1024 array of voltages. I then convert the voltages to Optical Density. Next I upsize the image to 1000x 1024 by interpolating the data inbetween the known datapoints. Up until this point I am confident that the caclulations are correct. I then convert the Optical Density to image data by using the following conversion. Private Function Norm(ByVal dblVal As Double, ByVal intNormFact As Double) As Double Return Math.Round(dblVal / intNormFact * 255) End Function dblVal = the Optical Density from the 40*1024 image array; intNormFact = the maximum value that dblVal can be. and I multiply by 255 to convert to a shade of gray because that is the range of inputs allowed into the rgb inputs to define a color. Am I doing it wrong? Quote Go Beavs!!!
kcwallace Posted December 5, 2005 Author Posted December 5, 2005 I made it work. See the attache image: Quote Go Beavs!!!
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.