|
Visual Basic Express 2008 - Working With USB Cameras and JPG Images Part III - Motion Detection (Virtual Guitar) |
|
|
|
|
|
Download The VB Express Project Files
|
|
| Instructions on saving the state of check boxes and radio buttons between sessions. This is accomplished through property binding, which is not intuitive in VB Express. | |
| Return to: | |
| Motion Patrol | |
| Basic Video Capture | |
| Save and Retrieve USB Photos | |
Selections From The Project Are Listed here. Download the project files for complete project code.
The bitmap for an image contains header information followed by the actual pixel information. I'm using a USB camera with a height of 640 pixels by a width of 480 pixels. The pixel information is RGB, saved as 4 bytes. Blue is the first byte of each group, Green is the second byte, Red is the third and the 4th is not used. Each line of pixel data has 2560 bytes (640x4). The program skips the header information using (Dim ptr As IntPtr = bmpData.Scan0), and then sores the pixel information in a one dimension byte array named "rgbValues", using System.Runtime.InteropServices.Marshal.Copy. The image pixel information is then read and manipulated within the array before being displayed back to a picturebox.
Motion is detected by comparing the pixel information between consecutive images taken. The timer, Timer1, tick event controls the time between images. It has been set to a default of 1/10th of a second. Instead of comparing every pixel, only pixel information along 13 vertical lines is analyzed.
Private Sub InitializeTimer()
'Set Timer Interval 1000 = 1 sec
Timer1.Interval = 100
Timer1.Start()
End Sub
Private Sub Timer1_Tick(ByVal Sender As Object, ByVal e As EventArgs) Handles Timer1.Tick
'Use odd/even to flip flop between images captured. Capture 'one frame as dataA and the next as dataB for comparison If OddEvenTextBox.Text = "odd" Then
OddEvenTextBox.Text =
"even" ElseOddEvenTextBox.Text =
"odd" End IfCaptureImage()
End Sub
Private Sub CaptureImage()
Dim dataA As IDataObject Dim dataB As IDataObject Dim BitmapCaptureImageA As Bitmap Dim BitmapCaptureImageB As Bitmap
' Retreive Bitmap Images, first image A and then image B for comparison If OddEvenTextBox.Text = "odd" Then
'Capture image
dataA = CaptureImageA()
'Convert image to bitmapBitmapCaptureImageA = BitmapCapture(dataA)
'Get the horizontal and vertical line dataZ = GetLines(BitmapCaptureImageA)
ElseEnd If Dim C As String = "" ' Get the number of changed points in each horz and vert bar ' Each value in the array hold the total number of changed points on the bar Dim HBV(9) As Integer Dim VBV(12) As IntegerdataB = CaptureImageA()
BitmapCaptureImageB = BitmapCapture(dataB)
H2 = GetLines(BitmapCaptureImageB)
Try
Tolerance = SensitivityTextBox.Text
Catch ex As Exception End TryVBV = GetVB(Tolerance)
' Now find the vertical bar with the largest change Dim LargestCase As Integer = 0 Dim Largest As Integer = 0
For x As Integer = 0 To 12
If VBV(x) > Largest Then
Largest = VBV(x)
LargestCase = x
End If Next 'Play a note that represents the vertical bar with largest changeIf Largest > Tolerance And VertTones.Checked Then
PlayMe(LargestCase)
End IfLastVertPosition = LargestCase
If LastVertTextBox.Text <> LastVertPos Then
TrueMovementFlag =
Movement()
End IfLastLRMotion = LeftRightMot
'PrintHBands(HBV)PrintVBands(VBV)
End Sub
Private Function CaptureImageA() As IDataObject
Dim data As IDataObject '---copy the image to the clipboard---
SendMessage(hWnd, WM_CAP_EDIT_COPY, 0, 0)
'---retrieve the image from clipboarddata = Clipboard.GetDataObject()
Return data End Function
Private Function BitmapCapture(ByVal dataA As IDataObject) As Bitmap
'Convert Image to Bitmap
If dataA.GetDataPresent(GetType(System.Drawing.Bitmap)) Then
BitmapCaptureImage =
CType(dataA.GetData(GetType(System.Drawing.Bitmap)), Image) End If Return BitmapCaptureImage End Function
Private Function GetLines(ByVal BitmapCaptureImageD As Bitmap) As Byte()
Dim bmp As New Bitmap(BitmapCaptureImageD) 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)
' Get the address of the first line. Dim ptr As IntPtr = bmpData.Scan0 ' Declare an array to hold the bytes of the bitmap. Dim bytes As Integer = bmpData.Stride * bmp.Height Dim rgbValues(bytes - 1) As ByteSystem.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes)
Dim Arrayy(bmpData.Height, bmpData.Stride) As Byte Dim HB(12641) As Byte Dim Length As Integer = bmpData.Stride Dim Col As Integer = 0 Dim Row As Integer = 0 Dim VRowMax As Integer = 0 Dim VColMax As Integer = 0 Dim HRowMax As Integer = 0 Dim HColMax As Integer = 0
VidWidth = bmp.Width
VidHeight = bmp.Height
VertSpace = bmp.Height / 9 - (bmp.Height
Mod 9) * 0.1HorzSpace = bmp.Width / 12 - (bmp.Width
Mod 12) * 0.1'Get Vertical Band Information
Row = 0
Col = 1
For y As Integer = 1 To 12
For x As Integer = 1 To bmpData.Height - 1
HB(9 * bmp.Width + ((y - 1) * bmp.Height) + x) = rgbValues((Length * x) + (4 * VertSpace * y + 1))
If GridOn.Checked Then
'(Length * x) is the row of bitmap pixel data '4 * VertSpace * y is the vertical column of data for the line 'The 0,1,2 are the offsets for RGB data
rgbValues((Length * x) + (4 * VertSpace * y + 0)) = 255
'bluergbValues((Length * x) + (4 * VertSpace * y + 1)) = 0
'greenrgbValues((Length * x) + (4 * VertSpace * y + 2)) = 0
'red ' Make lines bold by doubling line widthrgbValues((Length * x) + (4 * VertSpace * y + 0) + 4) = 255
'bluergbValues((Length * x) + (4 * VertSpace * y + 1) + 4) = 0
'greenrgbValues((Length * x) + (4 * VertSpace * y + 2) + 4) = 0
'red End If Next Next ' Copy the RGB values back to the bitmapSystem.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, bytes)
' Unlock the bits.bmp.UnlockBits(bmpData)
'Flip the image so it looks like a mirrorbmp.RotateFlip(RotateFlipType.RotateNoneFlipX)
' Draw Stuff Like Bouncing Balls On Screen. Select From Check BoxesDrawOnBitmap(bmp)
'Now put it in the pictureboxPictureBox1.Image = bmp.GetThumbnailImage(320, 240,
Nothing, Nothing)LastVertTextBox.Text = BallLocationV
Return HB End Function
Private Function GetVB(ByVal Tolerance As Integer) As Integer() Dim VBvariance(12) As Integer Dim ptr As Integer = 0 'Return an array containing the number of changed pixels in each vertical line ' The ptr is used to orient the bar data from left to right
For j As Integer = 9 To 20
For k As Integer = 1 To VidHeightptr = 20 - j
If Math.Abs(CInt(Z(9 * VidWidth + ((j - 9) * VidHeight) + k)) - CInt(H2((9 * VidWidth) + ((j - 9) * VidHeight) + k))) >= Tolerance Then
VBvariance(ptr) += 1
End If Next Next Return VBvariance End Function
Private Sub PlayMe(ByVal tune As Integer)
' play a wav file 'If LastNote <> tune Then
Select Case tune
Case 0
My.Computer.Audio.Play("C:\ToneWavs\1.wav", _
AudioPlayMode.Background)
Case 1My.Computer.Audio.Play("C:\ToneWavs\2.wav", _
AudioPlayMode.Background)
Case 2My.Computer.Audio.Play("C:\ToneWavs\3.wav", _
AudioPlayMode.Background)
Case 3My.Computer.Audio.Play("C:\ToneWavs\4.wav", _
AudioPlayMode.Background)
Case 4My.Computer.Audio.Play("C:\ToneWavs\5.wav", _
AudioPlayMode.Background)
Case 5My.Computer.Audio.Play("C:\ToneWavs\6.wav", _
AudioPlayMode.Background)
Case 6My.Computer.Audio.Play("C:\ToneWavs\7.wav", _
AudioPlayMode.Background)
Case 7My.Computer.Audio.Play("C:\ToneWavs\8.wav", _
AudioPlayMode.Background)
Case 8My.Computer.Audio.Play("C:\ToneWavs\9.wav", _
AudioPlayMode.Background)
Case 9My.Computer.Audio.Play("C:\ToneWavs\10.wav", _
AudioPlayMode.Background)
Case 10My.Computer.Audio.Play("C:\ToneWavs\11.wav", _
AudioPlayMode.Background)
Case 11My.Computer.Audio.Play("C:\ToneWavs\12.wav", _
AudioPlayMode.Background)
Case 12My.Computer.Audio.Play("C:\ToneWavs\13.wav", _
AudioPlayMode.Background)
Case ElseMy.Computer.Audio.Play("C:\ToneWavs\13.wav", _
AudioPlayMode.Background)
End SelectLastNote = tune
End Sub
Private Sub Movement()
If CDec(LastVertTextBox.Text) = CDec(LastVertPos) - 1 Then
"Left"LRMotion =
LeftMotionCount += 1
LRMotionCount -= 1
ElseIf CDec(LastVertTextBox.Text) = CDec(LastVertPos) + 1 Then"Right"LRMotion =
RightMotionCount += 1
LRMotionCount += 1
End IfIf LRMotionCount < 0 Then
LRMotionCount = 0
ElseIf LRMotionCount > 9 ThenLRMotionCount = 9
End IfLastVertPos = LastVertTextBox.Text
End Sub
Private Sub PrintVBands(ByVal VBV() As Integer)
TextBox11.Text = VBV(0)
TextBox12.Text = VBV(1)
TextBox13.Text = VBV(2)
TextBox14.Text = VBV(3)
TextBox15.Text = VBV(4)
TextBox16.Text = VBV(5)
TextBox17.Text = VBV(6)
TextBox18.Text = VBV(7)
TextBox19.Text = VBV(8)
TextBox20.Text = VBV(9)
TextBox21.Text = VBV(10)
TextBox22.Text = VBV(11)
End Sub
Private Sub DrawOnBitmap(ByVal bmp As Bitmap)
Dim g As Graphics = Graphics.FromImage(bmp) Dim VertPosition As Integer = VidHeight / 2 Dim BallSize As Integer = VidHeight / 20 'Draw Ball On Screen For Position
If BallOn.Checked Then
'g.DrawEllipse(Pens.Yellow, LastVertPosition * 53, 240, 20, 20)
g.FillEllipse(Brushes.Snow, LastVertPosition * VertSpace, VertPosition, BallSize, BallSize)
BallLocationV = LastVertPosition
End IfEnd Sub