hi every on I got the Webcam to work and I also made to take pictures
the only thing i need to do is have a clue where to start for finding movement detection :confused:
thx for the future help
Printable View
hi every on I got the Webcam to work and I also made to take pictures
the only thing i need to do is have a clue where to start for finding movement detection :confused:
thx for the future help
I haven't worked on it myself, and there is probably a better format, but consider it like this:
An image stored as a bitmap would be an array of color values. Movement happens when the new image doesn't match the existing image. You could compare byte by byte to look for change, but I suspect that you'd get plenty of noise that way. I would be trying a solution of averaging bytes in the image to compress it down to a smaller size, and comparing the averaged saved image to the new averaged image, while allowing for a little tolerance for change.
Maybe you could compare the file size of the images. Both my cams generate different sizes when something moves(appears) but maybe not all (cams) are like that.
I view my webcam in a picture box
i tryed converting the bmp into bytes and compare then but for some resons the bytes differ even when the cam is facing a white wall with no movements ...... it tryed to determine how much they differ , they match by only 12% or 8% :(
thx for the future help
I will post my code soon I am in my other computer ;)
Well, you're on your way. I expected that they would vary a pretty good amount. Even if you had one byte per pixel, a ten percent change might not be all that noticeable.
The next thing I would try would be to section the image into 9,16, or 25 square images (those are square numbers, of course). Then average all the bytes, and look for a change when the average changes by 10% or so. The idea being that the change in an individual pixel would probably be pretty silly, but the change in the average value of a region of the image would be significant.
If the camera was pointed at a blank wall, and the individual pixels are changing by 10% or so, would the average value change by 10%? Probably not, unless those changes are biased in one direction or the other. Therefore, averaging a bundle of pixels should dampen the fluctuations in any individual pixel. Thus, you want a number of pixels to average, but what number? Well, if your image is square, then divide it into sufficient sub-sections that a change in a single subsection would be significant. This could be as big as averaging the entire image, and looking for a change as small as 1% or so. Alternatively, if the field of view is wide enough, you might want to catch a change in a quarter of the image, a ninth of the image, etc.
An alternative to consider would be to think about what would happen if the camera was looking at a room, and a person walked into the room. They would intrude onto one side of the image, then move across the image. Therefore, averaging a couple of columns of pixels might also make sense.
The last consideration would be the rate of change. If a light is flipped on in the room with the camera, all pixels will jump upward by a considerable amount, as will the average (any average). However, if you are comparing images every half hour, then sunrise would have the same impact. Thus, do you compare by the second, the minute, etc. The answer depends on what you are expecting to capture.
It's a bit off the wall, but could you do an XOR operation on the two images? Any differences would indicate change therefore movement...
how do I that XOR ???
Shaggy Hiker I am trying urs now
The XOR solution won't work if you have as much fluctuation in your bytes as you report.
checking pixels by pixels took for ever :(
I don't know how to do that :(Quote:
The next thing I would try would be to section the image into 9,16, or 25 square images (those are square numbers, of course). Then average all the bytes, and look for a change when the average changes by 10% or so. The idea being that the change in an individual pixel would probably be pretty silly, but the change in the average value of a region of the image would be significant.
I am looking in internet to do that
Ive done an app that takes a picture every 10th second and it compares the picture with the previous one to detect changes. Im not on pc right now but when i am i can show u my code.
thx Atheist
If you have your pixels in a 2D array (equating to the x,y of the image), then the first thing I would try would be to calculate an average value for each x or each y by summing the pixels in the column/row, and dividing by the number of columns/rows. This is probably the fastest technique, and may well be sufficient. If the image is 320x240, then getting an average the 320 columns might be sufficient. I'd try that before going for anything more. However, I'd mostly try that because it would be relatively easy. By the way, if the array is only 1D, then you would average each N bytes, where N is the number of columns (320 in the above example).
A better technique would be to take a bundle of images real fast, and average them. If you could take a picture every 1/10th second, then you'd have ten in a second. Averaging them pixel by pixel would be SLOW, but ideal. For one thing, you could calculate the average and standard deviation of the pixels, and say that anything more that 2 standard deviations from the average is a change. However, like I said, this would be SLOW. However, why bother checking every pixel? How much area does a single pixel cover, a tenth of a centimeter? Less? You might divide the image into a bunch of regions (in your head, it doesn't have to be done in reality), and pick a pixel, or a couple of pixels in each region and only calculate the values for them. This would vastly reduce the number of calculations. A change in any one might be enough of a trigger, or you might go for a change in multiple regions, so that your detector is sensitive enough to catch a human moving through the region, but would let the cat through.
Funny thing about this question is that I have considered doing something like this myself, but I don't yet know whether I will or not. Thinking about this question has helped me think about how I will handle it if I ever do end up doing it. I'm leaning towards the idea of averaging the pixels and figuring the standard deviation, but I'd be looking for fish, so I'd have to use some pretty small regions, or all of the pixels. It would be easier in black and white since....well, I'm off onto a different issue.
Keep on posting.
I tryed the following
http://www.vbforums.com/showthread.php?t=435231
This is what I used to compare two images, I know it looks a bit **** and so...but keep in mind that it was a long time since i wrote it...and hey, it works for me :)
Ive written some explanation comments in the code, please ask if anything is unclear.
VB Code:
Private Sub ProcessImage() Dim file As String = SavedFilePath PicCap.Image = Nothing Dim bm As Bitmap Try bm = Image.FromFile(filename) Catch ex As Exception MessageBox.Show(ex.Message) Exit Sub End Try Dim y As Integer Dim r As Double = 0 Dim g As Double = 0 Dim b As Double = 0 Dim pxCount As Long = 0 'Loop through the image and add the rgb values to their respective variable. For x as Integer = 0 To 319 For y as Integer = 0 To 239 pxCount += 1 r += bm.GetPixel(x, y).R g += bm.GetPixel(x, y).G b += bm.GetPixel(x, y).B Next Next 'The current NewR, NewG and NewB values comes from the PREVIOUS image, so those values goes into the "old" variables instead. OldR = NewR OldG = NewG OldB = NewB 'And set the "New" variables with the current images R, G and B values divided by the number of pixels in the image. NewR = r / pxCount NewG = g / pxCount NewB = b / pxCount 'Exit the sub if OldR is -1(That means that there was no previous image) If OldR = -1 Then Exit Sub End If 'Here comes the code to compare the old and the new R, G and B values: If OldR > NewR Then If (OldR - NewR) >= Picky Then ListAdd(file) Exit Sub End If ElseIf NewR > OldR Then If (NewR - OldR) >= Picky Then ListAdd(file) Exit Sub End If End If If OldG > NewG Then If (OldG - NewG) >= Picky Then ListAdd(file) Exit Sub End If ElseIf NewG > OldG Then If (NewG - OldG) >= Picky Then ListAdd(file) Exit Sub End If End If If OldB > NewB Then If (OldB - NewB) >= Picky Then ListAdd(file) Exit Sub End If ElseIf NewB > OldB Then If (NewB - OldB) >= Picky Then ListAdd(file) Exit Sub End If End If 'Dispose the bitmap. bm.Dispose() End Sub
What im doing if it detects any changes is just to call the ListAdd sub, but you can ofcourse change it to whatever you like. And oh, almost forgot..the "Picky" (hehe) variable is a value that the user sets in settings to change how sensitive it should be. (A value from 1 to 24, where 4 is default, 1 is very sensitive and 25 is very unsensitive)..
Im almost embarrased to show this old code...but if its to any help to you then its good.
this code is perfect except It will take for ever .......
didn't u see my last post :) It is almost like that one I got it from the internet
thx for ur help ;)
this looks challenging
Yeah, that loop will take a looooong time because of the number of pixels, but do you need all of them? Why not just slap a Step 10 onto the end of both For statements.
As it stands, you will be looping a total of 76,800 times. By doing the step 10, you will cut that down to 768, a significant reduction. So what do you lose? Some resolution, but not all that much. You can figure out how much directly by taking the width of the field of view and divide by 320.
Make it a Step 12, and you cut it by a factor of 144, which would be even faster. Just figure out how wide a single pixel covers, and you can calculate the rough accuracy you need to capture the type of motion you are expecting. Then you can figure out how many pixels you really need to check.
You may be able to get a further minor speed increase by changing those If statements to:
If Math.Abs(NewG-OldG)>picky then
This removes one conditional in favor of an absolute value. Depending on the implementation of abs, this would probably be a bit faster.
yeah : but Not fast enough for what I am doing Comapring every 4 sec with that loop the user's computer will be messsssssed up :p
Any way for now I am going try and use this for now
the MD5 hash thing does not work
I am going to post my whole messed up code today take a look at it an inform me for any changes .....I did not do every thing by myself most of them is from internet but I now know how to do that :)
Good points here by shaggy. Nah I think it'll do just fine comparing it every 4th seconds, just put it in a thread..and set its priority to whatever is needed.
This code is my first tries with out adding atheist's code :)
VB Code:
Imports System.Runtime.InteropServices Imports System.IO Imports System.Text Imports System.Security.Cryptography Imports System.Threading.Thread Public Class Webcam Public Event cammove() Const WM_CAP As Short = &H400S Const WM_CAP_DRIVER_CONNECT As Integer = WM_CAP + 10 Const WM_CAP_DRIVER_DISCONNECT As Integer = WM_CAP + 11 Const WM_CAP_EDIT_COPY As Integer = WM_CAP + 30 Const WM_CAP_SET_PREVIEW As Integer = WM_CAP + 50 Const WM_CAP_SET_PREVIEWRATE As Integer = WM_CAP + 52 Const WM_CAP_SET_SCALE As Integer = WM_CAP + 53 Const WS_CHILD As Integer = &H40000000 Const WS_VISIBLE As Integer = &H10000000 Const SWP_NOMOVE As Short = &H2S Const SWP_NOSIZE As Short = 1 Const SWP_NOZORDER As Short = &H4S Const HWND_BOTTOM As Short = 1 Dim hHwnd As Integer Declare Function SendMessage Lib "user32" Alias "SendMessageA" _ (ByVal hwnd As Integer, ByVal wMsg As Integer, ByVal wParam As Integer, _ <MarshalAs(UnmanagedType.AsAny)> ByVal lParam As Object) As Integer Declare Function SetWindowPos Lib "user32" Alias "SetWindowPos" (ByVal hwnd As Integer, _ ByVal hWndInsertAfter As Integer, ByVal x As Integer, ByVal y As Integer, _ ByVal cx As Integer, ByVal cy As Integer, ByVal wFlags As Integer) As Integer Declare Function DestroyWindow Lib "user32" (ByVal hndw As Integer) As Boolean Declare Function capCreateCaptureWindowA Lib "avicap32.dll" _ (ByVal lpszWindowName As String, ByVal dwStyle As Integer, _ ByVal x As Integer, ByVal y As Integer, ByVal nWidth As Integer, _ ByVal nHeight As Short, ByVal hWndParent As Integer, _ ByVal nID As Integer) As Integer Declare Function capGetDriverDescriptionA Lib "avicap32.dll" (ByVal wDriver As Short, _ ByVal lpszName As String, ByVal cbName As Integer, ByVal lpszVer As String, _ ByVal cbVer As Integer) As Boolean Dim defaultid As Integer Function start(Optional ByVal Deviceid As Integer = 0) Try Timer1.Enabled = True Timer2.Enabled = True defaultid = Deviceid Dim iHeight As Integer = picCapture.Height Dim iWidth As Integer = picCapture.Width hHwnd = capCreateCaptureWindowA(Deviceid, WS_VISIBLE Or WS_CHILD, 0, 0, 640, _ 480, picCapture.Handle.ToInt32, 0) If SendMessage(hHwnd, WM_CAP_DRIVER_CONNECT, Deviceid, 0) Then SendMessage(hHwnd, WM_CAP_SET_SCALE, True, 0) SendMessage(hHwnd, WM_CAP_SET_PREVIEWRATE, 100, 0) SendMessage(hHwnd, WM_CAP_SET_PREVIEW, True, 0) SetWindowPos(hHwnd, HWND_BOTTOM, 0, 0, picCapture.Width, picCapture.Height, _ SWP_NOMOVE Or SWP_NOZORDER) Else DestroyWindow(hHwnd) End If Timer1.Enabled = True Return True Catch ex As Exception Return ex.Message End Try End Function Function stopwebcam() Try Dim Deviceid As Integer = defaultid SendMessage(hHwnd, WM_CAP_DRIVER_DISCONNECT, Deviceid, 0) DestroyWindow(hHwnd) Return True Catch ex As Exception Return ex.Message End Try End Function Function takephoto() Try Dim data As IDataObject Dim img SendMessage(hHwnd, WM_CAP_EDIT_COPY, 25, 25) data = Clipboard.GetDataObject() If data.GetDataPresent(GetType(System.Drawing.Bitmap)) Then img = CType(data.GetData(GetType(System.Drawing.Bitmap)), Image) End If Return img Catch ex As Exception Return ex.Message End Try End Function Dim hashone As String Dim hashtwo As String Dim issame As Boolean = False Dim buffer() As Byte Dim img1 Sub timer11() img1 = takephoto() Dim ic As New ImageConverter buffer = CType(ic.ConvertTo(p1.Image, GetType(Byte())), Byte()) Dim Md5 As New MD5CryptoServiceProvider() hashone = Convert.ToBase64String(Md5.ComputeHash(buffer)) ListBox1.Items.Add(hashone) l1.Text = hashone isnow = False End Sub Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick timer11() End Sub Dim isnow As Boolean = True Dim img2 Sub timer22() img2 = takephoto() Dim Md5 As New MD5CryptoServiceProvider() Dim ic As New ImageConverter Dim buffer2() As Byte buffer2 = CType(ic.ConvertTo(p2.Image, GetType(Byte())), Byte()) hashtwo = Convert.ToBase64String(Md5.ComputeHash(buffer2)) l2.Text = hashtwo ListBox2.Items.Add(hashtwo) comp(buffer, buffer2) isnow = True End Sub Private Sub Webcam_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load start() End Sub Private Sub comp(ByVal byte1() As Byte, ByVal byte2() As Byte) Dim i As Integer = 0 Dim total As Integer = 0 Dim average As Integer = 0 Dim totalbytes = byte1.GetUpperBound(0) - 1 Try For i = 0 To byte1.GetUpperBound(0) If byte1(i) = byte2(i) Then total = total + 1 End If Next average = CInt((total / totalbytes)) If average > 50 Then mo.Text = "" Else mo.Text = "moving" End If Catch ex As Exception End Try End Sub Private Sub Timer2_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer2.Tick timer22() End Sub End Class
Woooof, will that ever work? You already stated that comparing two bytes almost never produced an equality, yet you are doing it anyways without any wiggle room.
You can still improve the code by using Atheists 'picky' comparison. Just compare whether abs(byte1(i)-byte2(i))<Picky, where Picky is the amount of flux you are willing to allow for the two to still be considered a match.
You can also speed it up quite a bit by not comparing all the bytes, as I stated before. You don't get the same benefit from adding Step 10 to the loop in comp(), since it will only cut the pixel count by a factor of 10, rather than 100, but of course, you could fix that by increasing the Step.
yeah this was a messed up code