Reading BMP image from file and convert it into array in VB.NET - vb.net-2010

I need code to read an image from a file and convert the image into an array of integers. The format of image is BMP and I'm using vb.net-2010

You can find a similar question and valuable answers (although the question and answers are for c# i think they will help you to understand the solution) at : How can I read image pixels' values as RGB into 2d array?
First you need to load the file to a System.Drawing.Bitmap object. Then you can read pixel values using GetPixel method. Note that every pixel data includes a Color value. You can convert this value to an integer value using ToArgb() method.
Imports System.Drawing;
...
Dim img As New Bitmap("C:\test.JPG")
Dim imageArray (img.Width, img.Height) As Integer
Dim i, j As Integer
For i = 0 To img.Width
For j = 0 To img.Height
Dim pixel As Color = img.GetPixel(i,j)
imageArray (i,j) = pixel.ToArgb()
Next j
Next i
...
and the case storing a 2D array to a BMP object(Assuming you have a 100x100 2D array imageArray)
Imports System.Drawing;
...
Dim img As New Bitmap(100,100)
Dim i, j As Integer
For i = 0 To img.Width
For j = 0 To img.Height
img.SetPixel(i,j,Color.FromArgb(imageArray(i,j)))
Next j
Next i
...

Related

Bit cost per pixel of PNG file

In the PNG file format wikipedia page I saw this conversion of an image to a representation of the cost of bits per pixel (red=expensive, blue=cheap).
I was wondering if it is doable to program that kind of converter.
At the moment I don't know where to look up information about that so I decided to ask here with the little VB.NET code that I have made:
Dim MyBitmap As Bitmap = New Bitmap(filename:="C:\Original.png")
Dim MyBinaryReader As BinaryReader = New BinaryReader(File.OpenRead(path:="C:\Original.png"))
Dim MyBytes() As Byte = MyBinaryReader.ReadBytes(count:=Convert.ToInt32(File.OpenRead(path:="C:\Original.png").Length))
Dim MyString As String = ""
For Each MyByte As Byte In MyBytes
MyString = MyString & Convert.ToString(value:=MyByte, toBase:=2).PadLeft(totalWidth:=8, paddingChar:="0"c)
Next
Debug.WriteLine(MyString)
'For MyHeight As Integer = 0 To MyBitmap.Height - 1
' For MyHeight As Integer = 0 To MyBitmap.Height - 1
' MyBitmap.SetPixel(x:=MyWidth, y:=MyHeight, color:=MyBitmap.GetPixel(x:=MyWidth, y:=MyHeight))
' Next
'Next
'MyBitmap.Save(filename:="C:\New.png")

Optimization of matrix multiplication in vb.net

I'm currently trying to do some work on a neural network class in visual basic. My main drag at the moment is the multiplication of the matrices is so slow! Here's the code I use right now;
Public Function MultiplyMatricesParallel(ByVal matA As Double()(), ByVal matB As Double()()) As Double()()
Dim matACols As Integer = matA(0).GetLength(0)
Dim matBCols As Integer = matB(0).GetLength(0)
Dim matARows As Integer = matA.GetLength(0)
Dim result(matARows - 1)() As Double
For i = 0 To matARows - 1
ReDim result(i)(matBCols - 1)
Next
Dim tempMat()() As Double = MatrixTranspose(matB)
Parallel.For(0, matARows, Sub(i)
For j As Integer = 0 To matBCols - 1
Dim temp As Double = 0
Dim maA() As Double = matA(i)
Dim maB() As Double = tempMat(j)
For k As Integer = 0 To matACols - 1
temp += maA(k) * maB(k)
Next
result(i)(j) += temp
Next
End Sub)
Return result
End Function
I just jagged arrays as they are quicker in vb than rectangular arrays. Of course they really are rectangular otherwise the matrix multiplication wouldn't work (or make sense). Any advice/help would be appreciated, for reference the matrix size can change but it's currently around 7,000 x 2,000 at the maximum.

Fast "for each pixel in bitmap" loop

I'm writing a Visual Basic application that takes a screenshot of the desktop and crops it down to a 200px by 200px image around the center of the screen. One part of the application would iterate through each pixel and check if the RGB of that pixel is a certain color (this is meant to take under a second for it to be efficient), and unfortunately Bitmap.Getpixel is not doing me any good whether or not It's being loaded into the memory via Bitmap.Lock or not.
Is there a faster (almost instantaneous) way of doing so? Thanks.
Sure there is. Typically what you do is :
for each pixel
Get device contex
Read Pixel
Release device contex (unless you want memory leak)
For this to work you need few external windows library calls, ex :
[DllImport("user32.dll")]
static extern IntPtr GetDC(IntPtr hwnd);
[DllImport("user32.dll")]
static extern Int32 ReleaseDC(IntPtr hwnd, IntPtr hdc);
[DllImport("gdi32.dll")]
static extern uint GetPixel(IntPtr hdc, int nXPos, int nYPos);
static public System.Drawing.Color getPixelColor(int x, int y) {
IntPtr hdc = GetDC(IntPtr.Zero);
uint pixel = GetPixel(hdc, x, y);
ReleaseDC(IntPtr.Zero, hdc);
Color color = Color.FromArgb((int)(pixel & 0x000000FF),
(int)(pixel & 0x0000FF00) >> 8,
(int)(pixel & 0x00FF0000) >> 16);
return color;
}
It would be much better to
GetDC
for each pixel
read pixel and store value
ReleaseDC
However I have found that get pixel method itself is slow. Therefore to get better performance just grab the entire screen into a bitmap and get the pixels from there.
Here is some sample code in c#, you can convert it in VB.net if you want using online converters:
var maxX=200;
var maxY=200;
var screensize = Screen.PrimaryScreen.Bounds;
var xCenterSub100 = (screensize.X-maxX)/2;
var yCenterSub100 = (screensize.Y-maxY)/2;
Bitmap hc = new Bitmap(maxX, maxY);
using (Graphics gf = Graphics.FromImage(hc)){
gf.CopyFromScreen(xCenterSub100, yCenterSub100, 0, 0, new Size(maxX, maxY), CopyPixelOperation.SourceCopy);
//...
for (int x = 0; x < maxX; x++){
for (int y = 0; y < maxY; y++){
var pColor = hc.GetPixel(x, y);
//do something with the color...
}
}
}
In Vb.net (using http://converter.telerik.com/) :
Dim maxX = 200
Dim maxY = 200
Dim screensize = Screen.PrimaryScreen.Bounds
Dim xCenterSub100 = (screensize.X - maxX) / 2
Dim yCenterSub100 = (screensize.Y - maxY) / 2
Dim hc As New Bitmap(maxX, maxY)
Using gf As Graphics = Graphics.FromImage(hc)
gf.CopyFromScreen(xCenterSub100, yCenterSub100, 0, 0, New Size(maxX, maxY), CopyPixelOperation.SourceCopy)
'...
For x As Integer = 0 To maxX - 1
For y As Integer = 0 To maxY - 1
Dim pColor = hc.GetPixel(x, y)
'do something with the color...
Next
Next
End Using
With c# on my old computer i got around 30 fps, run time is about 35ms. There are faster ways, but they start to abuse several things to get that speed. Note that you do not use the getPixelColor, it is here just for reference. You instead use the screen scraped image method.
If you don't wish to resort to p/invoke, you can use the LockBits method. This code sets each component of a 200 x 200 area at the center of a bitmap in a PictureBox to a random value. It runs in about 100 milliseconds (not counting the refresh of the PictureBox).
EDIT: I realized you were trying to read pixels, so I added a line to show how to do that.
Private Sub DoGraphics()
Dim x As Integer
Dim y As Integer
'PixelSize is 4 bytes for a 32bpp Argb image.
'Change this value appropriately
Dim PixelSize As Integer = 4
Dim rnd As New Random()
'This code uses a bitmap that is loaded in a picture box.
'Any bitmap should work.
Dim bm As Bitmap = Me.PictureBox1.Image
'lock an area of the bitmap for editing that is 200 x 200 pixels in the center.
Dim bmd As BitmapData = bm.LockBits(New Rectangle((bm.Width - 200) / 2, (bm.Height - 200) / 2, 200, 200), System.Drawing.Imaging.ImageLockMode.ReadOnly, bm.PixelFormat)
'loop through the locked area of the bitmap.
For y = 0 To bmd.Height - 1
For x = 0 To bmd.Width - 1
'Get the various pixel locations This calculation is for a 32bpp Argb bitmap
Dim blue As Integer = (bmd.Stride * y) + (PixelSize * x)
Dim green As Integer = blue + 1
Dim red As Integer = green + 1
Dim alpha As Integer = red + 1
'Set each component of the pixel to a random rgb value.
'There are 4 bytes that make up each pixel (32bpp Argb)
Marshal.WriteByte(bmd.Scan0, red, CByte(rnd.Next(0, 256)))
Marshal.WriteByte(bmd.Scan0, blue, CByte(rnd.Next(0, 256)))
Marshal.WriteByte(bmd.Scan0, green, CByte(rnd.Next(0, 256)))
Marshal.WriteByte(bmd.Scan0, alpha, 255)
'Use the ReadInt32() method to read back the entire pixel
Dim intColor As Integer = Marshal.ReadInt32(bmd.Scan0)
If intColor = Color.Blue.ToArgb() Then
'The pixel is blue
Else
'The pixel is not blue
End If
Next
Next
'Important!
bm.UnlockBits(bmd)
Me.PictureBox1.Refresh()
End Sub

Finding HEX value at a specific offset in VB.net

I'm trying to figure out how to read a section of bytes (Say 16) starting at a specific address, say 0x2050. I'd like to get the 16 bits output in hex values into a label.
I've been trying to figure out BinaryReader, and FileStreams but I'm not entirely sure what the difference is, or which one I should be using.
*I've seen a lot of threads mentioning file size could be an issue, and I'd like to point out that some files I'll be checking may be up to 4gb in size.
I've tried the following:
Dim bytes() As Byte = New Byte(OpenedFile.Length) {}
ListBox1.Items.Add(Conversion.Hex(OpenedFile.Read(bytes, &H2050, 6)))
But this simply writes 6 bytes to the file, and I'm not sure why. There is no output in the listbox.
How about something like the following?:
Sub Main()
Dim pos As Long = 8272
Dim requiredBytes As Integer = 2
Dim value(0 To requiredBytes - 1) As Byte
Using reader As New BinaryReader(File.Open("File.bin", FileMode.Open))
' Loop through length of file.
Dim fileLength As Long = reader.BaseStream.Length
Dim byteCount As Integer = 0
reader.BaseStream.Seek(pos, SeekOrigin.Begin)
While pos < fileLength And byteCount < requiredBytes
value(byteCount) = reader.ReadByte()
pos += 1
byteCount += 1
End While
End Using
Dim displayValue As String
displayValue = BitConverter.ToString(value)
End Sub

Reading pixel value of an image

Q> If showing all the RGB pixel value of a 60*66 PNG image takes 10-34 seconds then how Image Viewer shows image instantly ?
Dim clr As Integer ' or string
Dim xmax As Integer
Dim ymax As Integer
Dim x As Integer
Dim y As Integer
Dim bm As New Bitmap(dlgOpen.FileName)
xmax = bm.Width - 1
ymax = bm.Height - 1
For y = 0 To ymax
For x = 0 To xmax
With bm.GetPixel(x, y)
clr = .R & .G & .B
txtValue.AppendText(clr)
End With
Next x
Next y
Edit
Dim bmp As New Bitmap(dlgOpen.FileName)
Dim rect As New Rectangle(0, 0, bmp.Width, bmp.Height)
Dim bmpData As System.Drawing.Imaging.BitmapData = bmp.LockBits(rect,Drawing.Imaging.ImageLockMode.ReadWrite, bmp.PixelFormat)
Dim ptr As IntPtr = bmpData.Scan0
Dim bytes As Integer = Math.Abs(bmpData.Stride) * bmp.Height
Dim rgbValues(bytes - 1) As Byte
System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes)
For counter As Integer = 0 To rgbValues.Length - 1
txtValue.AppendText(rgbValues(counter))
Next
System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, bytes)
bmp.UnlockBits(bmpData)
The first code takes 10 seconds and the 2nd one around 34 seconds for showing all the value in a textbox for a 59*66 PNG image on AMD A6 3500 with 4 GB RAM !
The problem exist when reading from file and writing to a textbox takes place in same time !
The problem is that the feature you're using, GetPixel, is very slow if you need to access a lot of pixels. Try using LockBits. You can use that to gather image data nearly instantly.
Using the LockBits method to access image data.