Web Based Surveillance System with OpenCV, PHP and Javascript

Mar 6, 2009 | Tags: OpenCV, PHP, Projects | del.icio.us del.icio.us | digg Digg

This is a simple web based surveillance system using OpenCV, PHP and Javascript. The system is designed to be low cost and simple, using only a webcam attached to a PC as the client. For the server side, you can use any regular web hosting.

The system itself is very simple. It saves an image taken from the webcam in an interval of time. The image then submitted to web server and displayed in a web page to browser. Some Javascript code will refresh the image without reloading the whole page in an interval of time.

Such a system provides a low cost remote surveillance system. No need to buy expensive cameras or web hosting service that supports video streaming.

The Design of the System

The system follows the Client-Server model. The client is a PC with a webcam attached to it. This is where you want to monitor things. The server is a regular web hosting. You can view the "video stream" using any PC connected to the Internet. The block diagram is shown in Figure 1.

Block Diagram
Fig 1. Block Diagram

The are 4 parts of code, reside on the client and server side:

  • Frame Grabber (cam.c): Saves a frame to file in a specified interval of time.
  • Image Sender (sender.php): A daemon to POST the saved frame to web server.
  • Image Receiver (recv.php): Save the submitted image to disk.
  • Web Page (index.html): Page to display the image, with Javascript to auto refresh the image.

Frame Grabber (cam.c)

Just like the name, Frame Grabber grabs the frames from webcam and display the video. The full listing is shown below. It makes use OpenCV, an open source computer vision library from Intel.

Listing 1: Frame Grabber with Autosave

  1. /**
  2.  * Display the video from webcam and automatically save the frame
  3.  * every 3 seconds.
  4.  */
  5.  
  6. #include <stdio.h>
  7. #include "cv.h"
  8. #include "highgui.h"
  9.  
  10. int main(int argc, char** argv)
  11. {
  12.     CvCapture *capture;
  13.     IplImage  *frame;
  14.     double    t, ms = 0;
  15.     int       key;
  16.  
  17.     /* initialize webcam */
  18.     capture = cvCaptureFromCAM(0);
  19.     cvNamedWindow("video", 1);
  20.  
  21.     while (key != 'q') {
  22.         t = (double)cvGetTickCount();
  23.  
  24.         /* display video */
  25.         frame = cvQueryFrame(capture);
  26.         cvShowImage("video", frame);
  27.         key = cvWaitKey(1);
  28.  
  29.         /* get elapsed time */
  30.         t = (double)cvGetTickCount() - t;
  31.         ms += t/((double)cvGetTickFrequency() * 1000.0);
  32.  
  33.         /* autosave every 3 seconds */
  34.         if (ceil(ms) >= 3000) {
  35.             cvSaveImage("img.jpg", frame);
  36.             ms = 0;
  37.         }
  38.     }
  39.  
  40.     /* free memory */
  41.     cvReleaseCapture(&capture);
  42.     cvDestroyWindow("video");
  43.  
  44.     return 0;
  45. }
  46.  

The code above display the video from webcam, and automatically save the frame to img.jpg every 3 seconds. The saved image then submitted to server by sender.php, described in the following section. I want to make things simple, so I choose PHP.

Image Sender (sender.php)

This is a daemon (background process) that waits for a new image from the Frame Grabber. Once the image arrive, the script will send the image over HTTP to the server.

Basically, sender.php simulates a HTML form like this:

<form action="http://nashruddin.com/surveillance/recv.php" method="post">
<input type="file" name="img" value="" />
<input type="submit" />
</form>

When the new image has come, it fills the value of <input type="file" /> with img.jpg, and push the submit button. the code is shown below.

Listing 2: Image Sender

  1. <?php
  2. /**
  3.  * This script checks for a new image from Frame Grabber, and
  4.  * POST the image to server.
  5.  *
  6.  * Run this script as daemon (background process)
  7.  */
  8.  
  9. $recv = 'http://nashruddin.com/surveillance/recv.php';
  10. $file = 'img.jpg';
  11. $time = 0;
  12.  
  13. while (true) {
  14.     /* wait 1 second */
  15.     sleep(1);
  16.  
  17.     /* don't cache the file status */
  18.  
  19.     /* if newer image exists */
  20.     if (file_exists($file) && filemtime($file) > $time)
  21.     {
  22.         /* POST the file to server */
  23.         send_file($recv, $file);
  24.  
  25.         /* save the file's modification time */
  26.         $time = filemtime($file);
  27.     }
  28. }
  29.  

The script checks for new images by comparing the file's modification time. If a new image found, it will POST the image by calling send_file function.

send_file() is my custom function to make HTTP POST request. Of course one can use Curl library, but since Curl is not always available on some systems, I think it would be better to make a custom function when portability comes into mind.

Listing 3: Function to POST a file

  1. /**
  2.  * Function to POST a file to server
  3.  *
  4.  * Parameters:
  5.  * @handler   string  the remote script that handles the incoming file
  6.  * @filename  string  the file to be sent
  7.  */
  8. function send_file($handler, $filename) {
  9.     /* check if file exists */
  10.     if (!file_exists($filename)) return;
  11.  
  12.     /* get hostname and path of remote script */
  13.     $host = parse_url($handler, PHP_URL_HOST);
  14.     $path = parse_url($handler, PHP_URL_PATH);
  15.  
  16.     /* setup default path if empty */
  17.     if (empty($path)) $path = '/';
  18.  
  19.     /* setup request header and body */
  20.     $boundary = "---------0123456789";
  21.     $reqbody  = "--$boundary\r\n"
  22.               . "Content-Disposition: form-data; name=\"img\"; filename=\"$filename\"\r\n"
  23.               . "Content-Type: image/jpeg\r\n\r\n"
  24.               . file_get_contents($filename) . "\r\n"
  25.               . "--$boundary--\r\n";
  26.     $reqhead  = "POST $path HTTP/1.1\r\n"
  27.               . "Host: $host\r\n"
  28.               . "Content-Type: multipart/form-data; boundary=$boundary\r\n"
  29.               . "Content-Length: " . strlen($reqbody) . "\r\n"
  30.               . "Connection: Close\r\n\r\n";
  31.  
  32.     /* open socket connection to remote host on port 80 */
  33.     $fp = fsockopen($host, 80, $errno, $errmsg, 30);
  34.  
  35.     /* check the connection */
  36.     if (!$fp) die("Cannot connect to $host!\n");
  37.  
  38.     /* send request */
  39.     fwrite($fp, $reqhead);
  40.     fwrite($fp, $reqbody);
  41.  
  42.     /* close the connection */
  43.     fclose($fp);
  44. }
  45.  

You must run the script sender.php as daemon (runs forever in the background), before you run the FrameGrabber. Simply type the command below in your console:

php sender.php &

Note: remove the '&' if you use Windows.

Image Receiver (recv.php)

This part is very simple, it retrieves the submitted image and save it to disk.

Listing 4: Save the submitted file to disk

  1. <?php
  2. /**
  3.  * Save the submitted file to disk
  4.  */
  5. if (is_uploaded_file($_FILES['img']['tmp_name'])) {
  6.     move_uploaded_file($_FILES['img']['tmp_name'], "img.jpg");
  7. }
  8.  

Web Page (index.html)

This page displays the image to browser. Some javascript code will refresh the image every 3 seconds without reloading the whole page.

Listing 5: HTML page with autorefresh

  1. <html>
  2. <head>
  3. <title>Remote Surveillance System</title>
  4. </head>
  5. <body>
  6.  
  7. <img name="frame" src="" border="0" />
  8.  
  9. <script type="text/javascript">
  10. function showFrame() {
  11.     document.images.frame.src = "img.jpg?" + Math.random();
  12.     setTimeout("showFrame()", 3000);
  13. }
  14. showFrame();
  15. </script>
  16.  
  17. </body>
  18. </html>
  19.  

Related Articles

14 Comments

Cheba on Mar 21, 2009:

It may be possible to use sockets for video-streaming?
How?
any idea?

I have only experience with EmguCV/C#.

Nash on Mar 22, 2009:

Yes it is possible. Only I don't know how

Shiva on Mar 22, 2009:

Nice Simple and useful.

Innocent on Apr 11, 2009:

Dear Sir,
I just fall in your website through Hotspot.com. You rdoing a great job specially when your giving it out for free.

I am designing a Membership website. And I will like that any time a member sign in the webcam should automatically get a snapshoot of the member then save it in a database (in the distant server) plus the login time and date. More than one member can login at the same time from any part of the world. Can you please help me in some ways?

Thank you in advance for yo

Nash on Apr 13, 2009:

You can use flash/flex for the loginbox. See this flex app:

http://blog.flexexamples.com/2008/01/22/displaying-a-webcams-video-in-a-flex-videodisplay-control/

The flex app takes a snapshot from webcam. You can modify it by adding textboxes and submit the login info with the pic to server.

yalamber on Jun 17, 2009:

How does the c file works. Should i compile it or what. please provide the details.
thank you

Nash on Jun 24, 2009:

Yes you have to compile it. It's not an interpreted language

The code requires OpenCV library installed in your system. For more info and how to compile, see OpenCV wiki.

Espen on Jan 15, 2010:

It would be interesting to see something like this integrated with ZoneMinder. ZoneMinder is a GPL Linux video camera. It currently has motion detection that can trigger alarms, but lacks advanced features that are possible with OpenCV.

Paul on Apr 15, 2010:

Hi Nash, nice tutorial there. I was trying out in saving the image every 3 seconds, but have the error at cvSaveImage,

"Unhandled exception at 0x004f13e0 in TEST.exe: 0xC0000005: Access violation reading location 0xffffffff."

Can you help me on this?

Nash on Apr 16, 2010:

Check if the directory where you save the frames is valid/readable.

kishore on Apr 27, 2010:

Hi this is kishore i am really thankful to you

Matt on Sep 4, 2010:

Just curious, I love your tutorials btw. But is the code you posted here the only code? It seems so...short and effecient for something so complicated? but I guess thats the beauty of OpenCV?

or is there more code to it? sorry. i just had to ask

either way though. I love ur tutorials/code. It seems like OpenCV is the best API/Lib to use when it comes to capturing webcam information

allankliu on Nov 26, 2010:

I love this tutorial. Your solution is simple to deploy. I am trying to use multiple (dual) web cameras to broadcast a stereo (3D) video and/or panorama video to web. There are so many jobs to do, but I still stuck on building OpenCV on my PC.

I hope it works for mobile phones.

Mario on Dec 17, 2010:

Hi Nash,

on Ubuntu 10.04, libopencv4, etc., gcc showed me this error on compiling:

easydetect.c:35: error: too few arguments to function ‘cvSaveImage’

Adding a third parameter to function call cvSaveImage:

cvSaveImage("img.jpg", frame,0);

It compiled and worked fine.

Thanks for this content, I'm new to this topic and it helped me to get a quick start.

Leave a comment

Name (required)
Email (will not be published) (required)
Website

Characters left = 1000