'How do I capture images in OpenCV and saving in pgm format?

I am brand new to programming in general, and am working on a project for which I need to capture images from my webcam (possibly using OpenCV), and save the images as pgm files.

What's the simplest way to do this? Willow Garage provides this code for image capturing:

http://opencv.willowgarage.com/wiki/CameraCapture

Using this code as a base, how might I modify it to:

  1. capture an image from the live cam every 2 seconds
  2. save the images to a folder in pgm format

Thanks so much for any help you can provide!



Solution 1:[1]

First of all, please use newer site - opencv.org. Using outdated references leads to chain effect, when new users see old references, read old docs and post old links again.

There's actually no reason to use old C API. Instead, you can use newer C++ interface, which, among other things, handles capturing video gracefully. Here's shortened version of example from docs on VideoCapture:

#include "opencv2/opencv.hpp"

using namespace cv;

int main(int, char**)
{
    VideoCapture cap(0); // open the default camera
    if(!cap.isOpened())  // check if we succeeded
        return -1;

    for(;;)
    {
        Mat frame;
        cap >> frame; // get a new frame from camera
        // do any processing
        imwrite("path/to/image.png", frame);
        if(waitKey(30) >= 0) break;   // you can increase delay to 2 seconds here
    }
    // the camera will be deinitialized automatically in VideoCapture destructor
    return 0;
}

Also, if you are new to programming, consider using Python interface to OpenCV - cv2 module. Python is often considered simpler than C++, and using it you can play around with OpenCV functions right in an interactive console. Capturing video with cv2 looks something like this (adopted code from here):

import numpy as np
import cv2

cap = cv2.VideoCapture(0)

while(True):
    # Capture frame-by-frame
    ret, frame = cap.read()
    # do what you want with frame
    #  and then save to file
    cv2.imwrite('path/to/image.png', frame)
    if cv2.waitKey(30) & 0xFF == ord('q'): # you can increase delay to 2 seconds here
        break

# When everything done, release the capture
cap.release()
cv2.destroyAllWindows()

Solution 2:[2]

Since ffriend's answer is only partially true, I'll add some more to it (in C++). The author of this question asks explicitly for exporting to PGM (PXM file format that stores each pixel in 8 bits) and not PNG (as ffriend describes in his/her reply). The main issue here is that the official documentation for imwrite is omho not clear about this matter at all:

For PPM, PGM, or PBM, it can be a binary format flag ( CV_IMWRITE_PXM_BINARY ), 0 or 1. Default value is 1.

If we read the sentence in normal English, we have a list of options: CV_IMWRITE_PXM_BINARY, 0 or 1. There is no mention that those can and actually are supposed to be combined! I had to experiment a little bit (I also needed to store 8-bit images for my project) and finally got to the desired solution:

std::vector<int> compression_params; // Stores the compression parameters

compression_params.push_back(CV_IMWRITE_PXM_BINARY); // Set to PXM compression
compression_params.push_back(0); // Set type of PXM in our case PGM
const std::string imageFilename = "myPGM.pgm"; // Some file name - C++ requires an std::string

cv::imwrite(imageFilename, myImageMatrix, compression_params); // Write matrix to file

My investigation was also fueled by this question where the author was (maybe still is) struggling with the very same issue and also by some basic information on the PXM format, which you can find here.

The result (only part of the image) is displayed below:

P2
32 100
255
121 237  26 102  88 143  67 224 160 164 238   8 119 195 138  16 176 244  72 106  72 211 168  45 250 161  37   1  96 130  74   8
126 122 227  86 106 120 102 150 185 218 164 232 111 230 207 191  39 222 236  78 137  71 174  96 146 122 117 175  34 245   6 125
124 121 241  67 225 203 118 209 227 168 175  40  90  19 197 190  40 254  68  90  88 242 136  32 123 201  37  35  99 179 198 163
97 161 129  35  48 140 234 237  98  73 105  77 211 234  88 176 152  12  68  93 159 184 238   5 172 252  38  68 200 130 194 216
160 188  21  53  16  79  71  54 124 234  34  92 246  49   0  17 145 102  72  42 105 252  81  63 161 146  81  16  72 104  66  41
189 100 252  37  13  91  71  40 123 246  33 157  67  96  71  59  17 196  96 110 109 116 253  30  42 203  69  53  97 188  90  68
101  36  84   5  41  59  80   8 107 160 168   9 194   8  71  55 152 132 232 102  12  96 213  24 134 208   1  55  64  43  74  22
92  77  30  44 139  96  70 152 160 146 142   8  87 243  11  91  49 196 104 250  72  67 159  44 240 225  69  29  34 115  42   2
109 176 145  90 137 172  65  25 162  57 169  92 214 211  72  94 149  20 104  56  27  67 218  17 203 182   5 124 138   2 130  48
121 225  25 106  89  76  69 189  34  25 173   8 114  83  72  52 145 154  64  40  91   2 251  53 251 237  20 124  82   2 194  42 ...

Which is exactly what is required in this case. You can see the "P2" marking at the top and also the values are clearly from 0 to 255, which is exactly 8 bits per pixel.

Solution 3:[3]

Read most of the answers but none of them could satisfy my requirement. Here's how I implemented it.

This program will use webcam as a camera and clicks picture when you press 'c' - we can change the condition, then make it to click pictures automatically after certain interval

# Created on Sun Aug 12 12:29:05 2018
# @author: CodersMine

import cv2

video_path = 0 # 0 internal cam, 1 external webcam
cap = cv2.VideoCapture(video_path) 
img_ctr = 0 # To Generate File Names

while(True):
    ret, frame = cap.read()
    cv2.imshow("imshow",frame)

    key = cv2.waitKey(1)

    if key==ord('q'): # Quit
        break

    if key==ord('c'): # Capture
        cv2.imshow("Captured",frame)
        flag = cv2.imwrite(f"image{img_ctr}.png", frame)
        print(f"Image Written {flag}")
        img_ctr += 1

# Release the Camera
cap.release()
cv2.destroyAllWindows()

Solution 4:[4]

If you don't need superaccurate 2seconds then simply put a sleep(2) or Sleep(2000) in the while(1) loop to wait fro 2seconds before each grab,

Write images with cvSaveImage() just put the extention .pgm on the filename and it will use pgm.

Solution 5:[5]

I believe that the format is chosen from the extension of the filename - so assuming your opencv lib's are linked against the appropriate libs you can do something like: (this is from memory, might not be correct.)

CvCapture* capture = cvCaptureFromCam(0);
IplImage* frame = cvQueryFrame(capture);
while (1) {
    frame = cvQueryFrame(capture);
    cvSaveImage("foo.pgm", &frame);
    sleep(2);
}
cvReleaseImage(&frame);
cvReleaseCapture(&capture);

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 ffriend
Solution 2 Community
Solution 3
Solution 4 Martin Beckett
Solution 5