Jump to content
Xtreme .Net Talk

Recommended Posts

Posted

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

Go Beavs!!!
Posted (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 by jo0ls
Posted

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?

Go Beavs!!!
  • Leaders
Posted (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 by snarfblam
[sIGPIC]e[/sIGPIC]
Posted
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.

Go Beavs!!!
Posted

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?

  • Leaders
Posted (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 by snarfblam
[sIGPIC]e[/sIGPIC]
Posted

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.

Posted

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?

Go Beavs!!!

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...