简体   繁体   中英

Capturing real time video with opencv in c++?

I'am developing a plate number detection application using opencv and c++.

For the detection trial, I want to capture real time video from my webcam using VideoCapture() function like this:

int main(void)
{
  // input image
  cv::Mat imgOriginalScene;      

  cv::VideoCapture cap = cv::VideoCapture(0); 

  for (;;) {
    cv::Mat frame;
    cap.read(frame);
    double timestamp = cap.get(CV_CAP_PROP_POS_MSEC);

    if (cap.read(frame)) {
      imgOriginalScene = frame;
      cv::Size size(1000, 600);
      resize(imgOriginalScene, imgOriginalScene, size);

      if (imgOriginalScene.empty()) {              
        std::cout << "error: image not read from file\n\n";   
        return(0);                        
      }

      std::vector<PossiblePlate> vectorOfPossiblePlates = 
          detectPlatesInScene(imgOriginalScene);    
      vectorOfPossiblePlates = detectCharsInPlates(vectorOfPossiblePlates);                 

      cv::imshow("imgOriginalScene", imgOriginalScene);      

      if (vectorOfPossiblePlates.empty()) {                         
        std::cout << std::endl << "no license plates were detected" << std::endl;    
      }
      else {                                      
        std::sort(vectorOfPossiblePlates.begin(), vectorOfPossiblePlates.end(), 
            PossiblePlate::sortDescendingByNumberOfChars);

        // suppose the plate with the most recognized chars
        // (the first plate in sorted by string length descending order) 
        // is the actual plate
        PossiblePlate licPlate = vectorOfPossiblePlates.front();

        cv::imshow("imgPlate", licPlate.imgPlate);      
        cv::imshow("imgThresh", licPlate.imgThresh);

        // if no chars were found in the plate
        if (licPlate.strChars.length() == 0) {                            
          // show message
          std::cout << std::endl << "no characters were detected" << std::endl << std::endl;    
        }

        // draw red rectangle around plate
        drawRedRectangleAroundPlate(imgOriginalScene, licPlate);        

        // write license plate text to std out
        std::cout << std::endl << "license plate read from image = " << licPlate.strChars << std::endl;   
        std::cout << std::endl << "-----------------------------------------" << std::endl;
        outfile << licPlate.strChars << "  " << timestamp / 1000 << " Detik" << std::endl;

        // write license plate text on the image
        writeLicensePlateCharsOnImage(imgOriginalScene, licPlate);        

        // re-show scene image
        cv::imshow("imgOriginalScene", imgOriginalScene);             

        // write image out to file
        cv::imwrite("imgOriginalScene.png", imgOriginalScene);          
      }
      cvWaitKey(34);
    }
    else {
      cap.set(CV_CAP_PROP_POS_FRAMES, 1.0);
      cvWaitKey(1000);
    }
    if (cap.get(CV_CAP_PROP_POS_FRAMES) == cap.get(CV_CAP_PROP_FRAME_COUNT)) {
      break;
    }
  }

  outfile.close();

  // hold windows open until user presses a key
  cv::waitKey(0);         

  return(0);
}

But after running the code, the video shown from my webcam is stuck, like it just showing the very first frame and then stop. So I can't detect anything because the video is stuck.

Anyone facing the same problem?

Generally, when reading from a camera the steps are as follows :

  1. Open the cv::VideoCapture object and call isOpened() to verify successful open. I generally prefer declaring the capture object separately and then using open(0) to open it, but test what works for you.
  2. Read a frame into a cv::Mat object. You can use read() or you could implement an approaching using the << operator
  3. Verify that the frame is not empty using empty() .
  4. Process the image in your loop.

Using waitKey()

Remember that waitKey(0) will halt your program until the user presses a key. Placing waitKey(30) once at then end of your loop will display the images in the processed and queued up using imshow() . You do not need to use waitKey() multiple times throughout the loop and may want to you some other timer for timing purposes.

Possible Error Points

Your code may be hanging on your first if statement. You are calling cap.read(frame) back to back which may be too fast for the webcam to process... causing it to return false after the first iteration. Instead, try an implementation that uses frame.empty() instead to check if you have an image to process after calling cap.read(frame) .

cv::Mat imgOriginalScene;           // input image

cv::VideoCapture cap = cv::VideoCapture(0); 

if(!cap.isOpened()){
    cerr << "Error Opening Capture Device" << endl; //Use cerr for basic debugging statements
    return -1;
}

for (;;) {
    cv::Mat frame;
    cap.read(frame);
    double timestamp = cap.get(CV_CAP_PROP_POS_MSEC);

    if (frame.empty()) {
         /*... do something ...*/
    }
    else {
        cap.set(CV_CAP_PROP_POS_FRAMES, 1.0);
        cvWaitKey(1000);
    }
     //Try removing this for debug...
/*
    if (cap.get(CV_CAP_PROP_POS_FRAMES) == cap.get(CV_CAP_PROP_FRAME_COUNT)) {
        //break;

    }
*/  
    cv::waitKey(0);                 // hold windows open until user presses a key
}

outfile.close();
cv::waitKey(0);                 // hold windows open until user presses a key

return(0);

Update Log:

  • Per @api55's comment, added the isOpened() check for completeness
  • Added discussion for waitkey()
  • Suggested commenting out sections that break the loop for now

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM