A command line cam image grabber

EDIT (20-11-2011) : Since posting this, I have created a new DirectShow command line image grabber called CommandCam, which I recommend you use instead of this one. It’s also completely free. Get CommandCam here (binary download and source code available).

Earlier today, I was looking for a command line image grabber for Windows to use with a webcam in a batch file. To my amazement, I simply could not find one that worked for me, so I’ve hacked together my own simple one in C using Microsoft’s venerable Video for Windows (VFW) API. Of course, there’s probably a “better” way of doing this, but this program is at least reasonably concise and to the point – basically, it’s what I needed. Thankfully, it’s much shorter than any of the video capture programs I ever wrote using DirectShow. The error checking is rudimentary to say the least – you might get an error message if something goes wrong.

Acknowledgement: My Win32 programming was never very good, but it’s extremely rusty right now, so theForger’s Win32 API Tutorial proved absolutely indispensible when I was writing this program. It’s a wonderful resource and is definitely my favourite Win32 programming guide – many thanks to theForger!

Here’s the executable file:

snapz.exe (24KB, date: 5-4-2011)

To use it, open a command window, move to the directory where snapz.exe is saved and simply type snapz. The program will open the default video capture device (e.g. a webcam) and grab a single snapshot at 640×480 resolution. The image will be saved to a device independent bitmap (DIB) file called snapz.dib in the same directory. This file format is uncompressed, so the file will be almost 1MB in size. You can convert it to a different format using another graphics program if you wish. I’m planning to use ImageMagick for that purpose in the batch file I’ll be using snapz in.

Here’s a screenshot of my command window. Note that the file snapz.dib appeared in the directory when I ran snapz.exe.

Here’s the image it captured (my arm, kettle, toaster):

Here’s the snapz code:

snapz.c (4KB, date: 5-4-2011)

I compiled it using gcc (MinGW version 5.1.4). The command to compile it is:

gcc -o snapz.exe snapz.c -lvfw32

If this turns out to be useful to you, please leave a comment to let me know.

Here’s the complete code:

//
// snapz.exe - a command line cam image grabber
// Written by Ted Burke, Last updated 5-4-2011
// ted.burke@dit.ie, batchloaf.wordpress.com
//
// To compile with MinGW:
//	gcc -o snapz.exe snapz.c -lvfw32
//

#include <windows.h>
#include <vfw.h>
#include <stdio.h>

// Window handles
HWND hWnd;
HWND hWndCap;

int capture_w = 640;
int capture_h = 480;
int capture_device = 0;	// default capture device
int time_delay = 0;	// delay in ms before snapshot
int preview_video = 0;	// Don't show on screen

// Message handling function
LRESULT CALLBACK WndProc(
    HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch(msg)
    {
    case WM_TIMER:
        // Save DIB snapshot, then exit from program
        capGrabFrame(hWndCap);
        capFileSaveDIB (hWndCap, "snapz.dib");
        DestroyWindow(hWnd);
        break;
    case WM_CLOSE:
        DestroyWindow(hWnd);
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, msg, wParam, lParam);
    }
    return 0;
}

int WINAPI WinMain(
    HINSTANCE hInstance, HINSTANCE hPrevInstance,
    LPSTR lpCmdLine, int nCmdShow)
{
    // Register window class
    WNDCLASSEX wc;
    wc.cbSize        = sizeof(WNDCLASSEX);
    wc.style         = 0;
    wc.lpfnWndProc   = WndProc;
    wc.cbClsExtra    = 0;
    wc.cbWndExtra    = 0;
    wc.hInstance     = hInstance;
    wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
    wc.lpszMenuName  = NULL;
    wc.lpszClassName = "snapzWindowClass";
    wc.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);
    if(!RegisterClassEx(&wc))
        fprintf(stderr, "Window Registration Failed!");

    // Create main window
    hWnd = CreateWindowEx(
        WS_EX_CLIENTEDGE,
        "snapzWindowClass",
        "snapz",
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT,
        capture_w + 100, capture_h + 100,
        NULL, NULL, hInstance, NULL);
    if (hWnd == NULL)
        fprintf(stderr, "Couldn't create main window.");

    // Create capture window
    hWndCap = capCreateCaptureWindow(
        NULL, WS_CHILD,
        0, 0, capture_w, capture_h,
        hWnd, 0);
    if (hWndCap == NULL)
        fprintf(stderr, "Couldn't create capture window.");

    // Connect to capture driver and set resolution
    capDriverConnect(hWndCap, capture_device);
    DWORD dwSize = capGetVideoFormatSize(hWndCap);
    LPBITMAPINFO lpbi = (LPBITMAPINFO)malloc(dwSize);
    capGetVideoFormat(hWndCap, lpbi, dwSize);
    lpbi->bmiHeader.biWidth = capture_w;
    lpbi->bmiHeader.biHeight = capture_h;
    capSetVideoFormat(hWndCap, lpbi, dwSize);
    free(lpbi);

    // Initialise and start video preview
    if (preview_video > 0)
    {
        // Set up video preview
        capPreviewRate(hWndCap, 1); // rate in ms
        capPreview(hWndCap, TRUE);
        ShowWindow(hWndCap, SW_SHOW);

        //Show main window
        ShowWindow(hWnd, nCmdShow);
        UpdateWindow(hWnd);
    }

    // Set timer to trigger snapshot
    SetTimer(hWnd, 1, time_delay, NULL);

    // Message loop
    MSG msg;
    while(GetMessage(&msg, NULL, 0, 0) > 0)
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    // Tidy up video capture stuff
    KillTimer(hWnd, 1);
    capPreview(hWndCap, FALSE);
    capDriverDisconnect(hWndCap);
    if (hWndCap) DestroyWindow(hWndCap);

    return msg.wParam;
}
About these ads
This entry was posted in Uncategorized and tagged , , , , , , , , , . Bookmark the permalink.

69 Responses to A command line cam image grabber

  1. Kiraichi says:

    nice coding man, this is what im looking for dude!

    btw, need ur little help again, do u mind if i add u on msn or ym? leave ur email or add me at kiraichi_gsx@hotmail.com or kiraichi_gsx@yahoo.com

    thanks batchloaf!

    • batchloaf says:

      Hi Kiraichi, thanks for your comment. I’m not on yahoo or msn and to be honest, I tend to be very busy. However, if there’s something simple you’d like added or changed in the program, just leave a comment here and I’ll see whether I can implement it. Thanks again.

  2. Rishipal yadav says:

    Sir,
    Is it posible to have imagecapture for more than one webcam attached to machine with your program, I dont have the compilation env .

    thanks

    • batchloaf says:

      Hi Rishipal,

      Do you mean that you want to simultaneously snap images from two or more cameras, or do you want to simply select one of a number of cameras that are connected to the machine? Selecting one camera from a number would be a simple change to make. Capturing images from more than one camera simultaneously is a bit more complicated, but I suppose I could give it a shot if that’s what you’re trying to do.

      Can you please explain in more detail what you need to do? I won’t get a chance to do anything about it for at least a couple of days, but I can try to revise the program during next week if it’s something reasonably straightforward. If so, I can post a revised compiled version.

      Thanks,
      Batchloaf

  3. James Tan says:

    Good day. First off, I would like to say that your software is just what I was looking for and I would like to thank you for that. However, why doesn’t the software close? It just continues on running. Any ideas would be nice.

    Best Regards,
    James Tan

    • batchloaf says:

      James, thanks for reporting the problem with the program not closing. I’d like to solve it, but unfortunately I can’t reproduce it on my computer. Could you please provide some further details? For example, which version of Windows you are running and maybe even a screen shot of the program running (and not closing) in the command window (click in the command window, press Alt-PrintScreen to copy an image of it to the clipboard, then paste it into MS Paint or something similar). There are a couple of thing I can try changing to see if they solve the problem, but I might need to ask you to try out the modified versions on your computer to tell me if they work. I would really appreciate your help in tracking down and solving this problem.

  4. Thanks for your reply
    Sir,
    There are 5 webcam attached to one PC and for my phd project I have to captur Imag from one webcam at one time depending upon the hardware event I have to do this through program and then do the measurement work using the captured image. I work in labview and have done the interfacing with hardware and the image processing work and tested it using the manually captured images. Your program is the wright thing for getting the images programatically by executing the command on commandline from labview env. But the problem I am facing is I am not getting able to select the required webcam on the command line along with the snapz command.
    I thought the simplest way could be to compile 5 diffrent versions of your program say snapz1.exe to snapz5.exe by compiling each version by setting the “capture_device” parameter value to 0,1,2,3,4. I tried to do this but I could not succed because I know little about C++ and also because I am trying this with VC++ version6 as I dont have gcc env.

    It could be a great help for me and people like me who wants to use your program if the facility to select the required webcam is provided as command line parameters.

    thanks

  5. Paul Hamill says:

    Thanks for open sourcing this handy script! Just what I was looking for to capture frames from a USB HP webcam.

  6. Rishipal Yadav says:

    Thanks for your reply
    Sir,
    I finally compiled your script with VC++ and reached to the same conclusion as you have stated in your post, but certainly the snapz code is the best way to capture the image from command line .
    Finally I succeeded in capturing image from multiple cameras from command line using the autoit script programming.

    with regards
    Rishipal yadav

    • batchloaf says:

      Hi Rishipal. Ok, well thanks very much for giving it a try. I’m delighted to hear that you found a solution to your problem anyway. I’m now having a go at rewriting snapz using DirectShow, so if you need a command line solution for multi-camera image capture again in the future, please do check back here. Best of luck in your research!

  7. Lawrence Reed says:

    Handy program. I am running in to a problem though, I can only seem to capture one picture and then something “breaks”. . On my xp machine it just stops working no pop ups, even a full shutdown doesnt help. I am guessing something in the VFW on my machines may not be resetting after the picture is taken.

    • batchloaf says:

      Hi Lawrence,

      Wow, that’s strange! I’m guessing that the problem you’re having is related to a driver issue on your machine – probably related to opening the camera device via VFW rather than DirectShow. Admittedly, that’s just speculation really, but I don’t think there’s anything unusual about how snapz opens and closes the VFW device. I would be curious to know if another (tried and tested) VFW-based program works correctly on your machine – do you happen to know if this is the case?

      Anyway, if you’re still looking for a program to do what snapz does, please check back over the nest few days – I should be posting a DirectShow-based version of snapz, which will hopefully be better behaved on a wider variety of machines.

      Thanks for the feedback!

      • Lawrence says:

        A DShow based version would be great. You are most likely right on the driver issue. I have tried some VFW capture programs and they do work but they all require a video window displayed on the screen to capture. The reason i wanted this was to be able to snap a picture of a thief that had stolen a clients laptop for the police.

  8. jef says:

    Hi, it’s exactly what I was searching for. Unfortunately, it only works when I connect a webcam through USB. With my built-in webcam, it asks to choose a device and when I choose my webcam an empty image is stored. Anyone else with the same problem?

    • batchloaf says:

      Hi Jef, thanks for the feedback and sorry for the delay in replying. I’ve been up to my eyes for the last few weeks, but once things settle down I’m planning to have a go at rewriting this application “properly” using DirectX, which should hopefully work with a wider variety of cameras. Please keep an eye out for the updated version – I’d appreciate knowing if it works for you.

      • jef says:

        Hi, thanks for replying. In the meantime I figured out it does work with my built-in webcam each first time I run it after restart, and afterwards it won’t. Strange, but actually it’s enough for me, because I wanted it to take a snapshot on startup and put it in my dropbox so I could see my laptop’s thief his face :-).

      • batchloaf says:

        Ha ha, what an interesting application!

        It sounds like the problem you were having is related to the fact that snapz accesses whatever camera it uses through the older Video For Windows (VFW) API. Windows does contain an adapter driver which can “wrap” a newer DirectShow driver allowing a camera that does not have a VFW driver to be accessed via that API. Anyway, I’m glad you found a solution!

  9. Wes says:

    Thanks! This is all I needed, but its surprising how difficult it was to get something to do this simple task. As far as I can tell it works perfectly on my computer with my default/built in webcam.

  10. Nathan Casselton says:

    Hello, I would like to know if you could adapt this executable to take multiple photos and save them as 001, 002, ect. It would help me out alot if this could me done.

    Thanks

    • batchloaf says:

      Hi Nathan, thanks for your comment. In response, I’ve just added a
      new post to my blog explaining how to do what you ask. It’s a bit of a hack, but hopefully it will work for you.

      Since there has been some consistent interest in snapz, I’m planning to have a go at writing it up as a slightly more complete piece of software, including some of the features that have been requested (support for more cameras, multiple simultaneous cameras, multiple sequential images, custom filenames, etc.)

  11. Fellow Snapz Fan says:

    Hey! Thanks for the Snapz program!
    However, I am facing some issues too.
    I can run snapz successfully for the first time, then when i try to run it again, a box appears and asks me to select the webcam (i only have 1).
    It then saves an empty snapz.dib to the computer.
    It seems that there is a problem with the VFW stuff.

    I was trying out simple capturing of webcam shots with Java’s JMF too. The same thing happened.
    First run = ok. Onwards = failures.

    Hope you can release the direct show version asap! It would be perfect if it works 100%.

    Thanks for the hard work! Keep it up!
    -A Snapz fan

    • batchloaf says:

      Hi Snapz Fan, thanks for your comment. Sorry it didn’t appear straight away – I though I had approved it, but I just noticed that it was still in the “pending approval” list, so I must have clicked the wrong thing. Anyway, hopefully the forthcoming DirectShow version will solve the problem you’re having. If you get a chance to try it out when I post it here, I’d be interested to hear whether it works for you.

  12. jawad says:

    Great work, man waited DirectShow version good luck,

  13. Dmitry says:

    Hi,
    Unfortunately, the snapz.exe program does not work for me. It creates a .dib file but it’s empty.
    I tried putting it into Visual Studio and it compiled and did the same thing. But in debug it gave me a memory allocation error on free(lpbi);
    It never gets to the selection of webcam in debug, although in the compiled version it does, thanks,

  14. batchloaf says:

    In case anyone’s waiting for it, I’ve now posted a DirectShow command line webcam image grabber.

  15. Chris says:

    Hi Batchloaf, I don’t know if you are still checking this board, but I was wondering if you knew of a way to set a built-in HP webcam to start recording at a specific time? I think a neighbor or someone has been letting themselves in recently and have narrowed down a time, but I am at work… I could start recording in the morning, but want to avoid the blank hours of tape as well as the extra GB’s that would surely take up.

    Any help would be greatly appreciated.
    Thanks

    • batchloaf says:

      Hi Chris. If you want to record video when someone is there, I think there are software tools that record only whenever something moves in front of the camera. They’re designed for just this sort of security application. However, I haven’t used them, so I’m afraid I can’t recommend a specific one. If you google “motion sensing video capture” or something like that, I’m sure you’ll find something like what I mean.

      CommandCam only captures still images, so it probably isn’t suitable for what you want. However, it does have an option to delay for a specified period of time before snapping an image. The latest version of CommandCam is here:

      http://batchloaf.wordpress.com/commandcam/

      Also, I have another program called RobotEyez, which can take a series of snapshots. It might do the trick. Here’s the link:

      http://batchloaf.wordpress.com/2011/11/27/ultra-simple-machine-vision-in-c-with-roboteyes/

      • Chris says:

        Thanks Batchloaf, I was able to find several free motion sensor programs to try. I will try a couple and post back which works the best. Appreciate the tip. Keep up the good work!

      • batchloaf says:

        Hi Chris. You’re very welcome. Best of luck getting it working!

  16. Chris says:

    Just wanted to give you an update. I found a great program called iSpy. It’s free and works great!
    I do recommend it.

    Thanks again for the assist in finding this.

    Take care.
    Chris

  17. Avinash Kumar says:

    Thanks for sharing this. This can be a great help for me.
    i want to pass the path and file name where i want to save the image file.
    how can i do this?
    Please comment asap.

    • batchloaf says:

      Hi Avinash,

      The easiest way to do this is to use my other webcam snapshot program, CommandCam. With CommandCam, you can do this:

      CommandCam /filename myimage.bmp
      

      The filename can include a full path, or it can just be a filename to save in the current folder.

      If you are determined to use snapz for some reason, you can just let it save to the default filename, then move the file to the desired location. Something like this will do it:

      snapz.exe; move snapz.dib c:\folder\subfolder\myimage.dib
      
  18. Nothing says:

    Can you give me a sound recorder

    • batchloaf says:

      Hi “Nothing”,

      Do you mean you’re looking for a command line audio recorder? If so, then perhaps Sox can do what you need? I haven’t used it for a couple of years, but it’s free and open source and really flexible. They describe it as the “Swiss Army knife of sound processing programs”, which is pretty accurate.

      Ted

      • Nothing says:

        I mean something like a sound recorder in .exe which secretly records your voice after you open it and save the result in a .wav file in your com. I don’t want those which need installation. Just the snapz.exe you posted.

  19. Nothing says:

    I mean something like snapz.exe

  20. ram says:

    HI,
    I am using snapz.exe, while capturing the images, the images are capturing in background,is any possible way to see the image streaming in Foreground.

    • batchloaf says:

      Hi Ram,
      I suggest that you try my other program, CommandCam, which is similar to snapz, but it provides a preview option. Here’s the link:

      http://batchloaf.wordpress.com/commandcam/

      Ted

      • ram says:

        Thanks for ur Fast Reply, I already used Commandcam still we are facing same problem.
        Exactly our requirement is to See the image(While Taking the Snap From .exe,)

      • batchloaf says:

        Hi Ram,

        When you use the preview option in CommandCam, you should be able to see the image onscreen before it is snapped. Is that working for you?
        If you only want the image too be snapped when the user (who is watching the preview) presses a button or something, that is a different problem and it’s not really what CommandCam is intended for. There are lots of other programs that do that (show a preview then take a snapshot when you click a button).

        Ted

      • ram says:

        how to check the preview option in CommandCam, i am unable to see that one

      • batchloaf says:

        You just run it with a command like this:

        CommandCam /preview
        

        Sometimes, the preview takes a few seconds to appear, so you may need to add something like:

        CommandCam /preview /delay 5000
        

        That would add a 5 second (5000ms) delay before the snapshot is taken.

        As I mentioned before, if you’re trying to take a snapshot interactively (i.e. when you manually press a key or click a button), CommandCam probably isn’t the best program for your purpose since it’s not designed for this purpose. CommandCam is designed for automatic snapshots without human interaction. There are other programs that provide this functionality (click a button to take a picture).

  21. John Lesac says:

    Thanks for the simple and easy code. I was able to change the resolution to 1920×1080 to match my new webcam and recompile the code. My first snapz produced an all black image for some reason. But the second turned out OK. I intend to use my webcam as a remote weather camera and need a simple interface that I can use via a dial-up PPP link. Your code will do the trick!

    Thanks again!
    John L

  22. sumit says:

    hi batchloaf, u have done a great job,
    even i want to write a program like this in linux(UBUNTU) to automate the process of accessing the webcam and streaming it using apache webserver.. can u give me some clue where to look for. i have tried a lot with no success

    • batchloaf says:

      Hi Sumit,

      There are definitely several free software tools available that do this in Linux. Try looking up “streamer”, “mplayer”, and “VLC”. I’m sure it’s possible with at least one of those, although it might take some messing around with command line options to find the exact command you need.

      I’ll have a look myself later on to see how I did this before.

      You can write a program yourself to read from the camera too, although I don’t think that will be necessary. If you decide to try this, look up Video4Linux and Video4Linux2. You should find some useful information. Try doing some simple video capture in VLC first though so that you can work out what device name your camera is using.

      Ted

      • sumit says:

        thanks for replying ..
        well i have already tried motion and webcam-server and motion seems to work fine but the webcam-server doesn’t work fine and gives some error regarding ioctl and vidio macros and my webcam is /dev/video0 on my mac. motion is a very big program while i need only basic functionality as per my need so was thinking about writing program on my own. being a beginner in linux please suggest me good resources related.

        Sumit

      • batchloaf says:

        If you really want to write your own program, you can find the V4L2 (Video for Linux API) documentation here:

        http://linuxtv.org/downloads/v4l-dvb-apis/

        However, please be aware that it will be complicated! Probably a good place to start is with a sample program. You can find one here (download the tar.gz file for version 0.4.1):

        http://alumnos.elo.utfsm.cl/~yanez/video-for-linux-2-sample-programs/

        Personally, I think it would be much easier to find one of the existing programs that is out there and work out how to use it. For example, you could use Streamer, which I mentioned in my previous reply. I believe mplayer can also be used to take snapshots from the command line.

        Whatever you decide to do, I think you should definitely begin by opening your camera for video capture in VLC as I suggested above. That way you will be sure what device name to use with other programs (including ones you have written). It would be absolutely crazy to try writing your own program without at least confirming that you can open the camera from VLC or some other existing program. There is no guarantee that the device name will be the same as it is in MacOS.

        Ted

      • sumit says:

        hey thanks so much for helping me out.
        basically i m doing a project that involves hosting a web server(site) which should provide the user with a link that redirects him to the video feed from a webcam or usb cam. i know i have to use php for the site part but how do i embed the stream on that page? totally clueless…

  23. Adriaan says:

    Thanks for this tool! But is there a way to change it so that it doesn’t replace that file, but rather create a new one for instance “snapz.dib” and then “snapz2.dib” etc?

  24. shiuth says:

    it would be nice if it save image file randomly other than replacing.. like image01, image02

  25. hasan-ahmed says:

    hello, is there a way to make batch file which captures screen portion to same file after certain time interval?

  26. [7d] says:

    WOW just what I was searching for. Came here
    by searching for canon fd lens

  27. sreejith says:

    How to use it in remote desktop situations. Maybe you can help…?

  28. Fadi says:

    Nice program. Adding a date/time stamp into the file name would make it even more useful.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s