簡體   English   中英

如何使用opencv和c++每秒從視頻文件中捕獲圖像?

[英]how to capture images per second from video files by using opencv and c++?

我在設計程序時遇到過允許每秒從視頻文件(avi、mp4 等)中捕獲圖像。

首先,我能夠從視頻文件中逐幀捕獲圖像。 其次,我能夠同時分析同一文件夾中圖像的像素顏色值,並將像素值保存在 txt 文件中。

在這里我有一些問題。 我現在正試圖一次組合這兩個代碼,但我得到了奇怪的結果。 我參考下面的代碼。

int main(){
VideoCapture cap("D:\\data\\extra\\video200ul.avi"); 
if (!cap.isOpened())  
    return -1;

Ptr<BackgroundSubtractor> pMOG2 = createBackgroundSubtractorMOG2(20, 16, true);

Mat fg_mask;
Mat frame;
int count = 0;

String name, folder;

for (;;) {
    // Get frame
    cap >> frame; // get a new frame from video
    ++count;
    // Update counter

    // Background subtraction
    if (count % 2 == 0) {
        pMOG2->apply(frame, fg_mask, 0.001);

        cout << count << endl;

        if (!frame.empty()) {
            imshow("frame", frame);
            //      imshow("fg_mask", fg_mask);
        }
        // Save foreground mask
        name = "mask" + std::to_string(count) + ".png";
        //      string name = "mask_" + std::to_string(static_cast<long long>(count) + ".png";
        folder = imwrite("D:\\data\\extra\\" + name, frame);

    }
    anal(folder);
}   
waitKey(0);
return 0;

}

首先,我上面寫的代碼是用於從視頻文件中逐幀捕獲圖像。 但是,如果我每幀獲取圖像,我的文件夾中就會有很多圖片,所以我想每秒從視頻文件中捕獲一個圖像。 我曾嘗試使用 CV_CAP_PROP_POS_MSEC 而不是 cap << frame,但它對我不起作用。

其次,當我將此代碼合並到我在下面編寫的另一個代碼中時,它顯示了一些錯誤消息,例如“libpng 警告圖像寬度、長度、數據在 ihdr 中為零。”

int anal(String folder) {

folder = "D:\\data\\extra\\*.png"; 
vector<String> filenames;

glob(folder, filenames);

cv::Mat ori_image;

for (size_t i = 0; i < filenames.size(); ++i) {

    ori_image = imread(filenames[i], IMREAD_COLOR);

    if (ori_image.empty()) {
        cout << "Check your file again." << std::endl;
        return -1;
    }

    rectangle(ori_image, Point(215, 98), Point(245, 110), Scalar(0, 255, 255), 1); 

    imshow("Original Image", ori_image);

    cv::Scalar sums;
    sums = cv::sum(ori_image);

    double totalSum = sums[0] + sums[1] + sums[2];

    if (totalSum <= 0) {
        cout << "$$ RGB percentage $$" << " \n\n";
        cout << "R: " << 100.0 / 3 << " % \n";
        cout << "G: " << 100.0 / 3 << " % \n";
        cout << "B: " << 100.0 / 3 << " % \n\n";
    }
    else {
        cout << "$$ RGB percentage $$" << " \n\n"; // red value
        cout << "R: " << sums[2] / totalSum * 100 << " % \n"; // red value
        cout << "G: " << sums[1] / totalSum * 100 << " % \n"; // green value
        cout << "B: " << sums[0] / totalSum * 100 << " % \n\n"; // blue value
    }

}

在准備上面的代碼時,我嘗試計算視頻中所有捕獲圖像的紅色、藍色、綠色百分比。 但是,當我將這兩個代碼分開並運行時,它們運行良好,但是如果我將它們合並在一起,則會顯示錯誤消息。

我想結合這兩個代碼來分析每秒視頻中捕獲的圖像的顏色值。

請幫我解決這個問題。

先感謝您。

-----------編輯部分--------------

我使用了你的修訂版本並應用於我更新的代碼,

void imageAnalysis(std::string folder, cv::Mat frame){
cv::Mat ori_image = frame.clone();
std::string path = folder;
cv::rectangle(ori_image, Point(215, 105), Point(245, 120), Scalar(0, 255, 255), 1);

cv::imshow("Original Image", ori_image);
cv::waitKey(1);


String folder = "D:\\data\\dfdf\\*.png";
vector<String> filenames;
cv::glob(path, filenames);

for (size_t t = 0; t < filenames.size(); t++) {
    ori_image = imread(filenames[t], IMREAD_COLOR); // ori_image

    if (ori_image.empty()) {    //ori_image
        cout << "Check your file again." << "\n";
        break;
        //return -1;
    }

    rectangle(ori_image, Point(215, 105), Point(245, 120), Scalar(0, 255, 255), 1); 
    imshow("Original Image", ori_image);
    cv::waitKey(1);

    Mat image_HSV;
    cvtColor(ori_image, image_HSV, CV_BGR2HSV);

    double h = 0.0;
    double s = 0.0;
    double v = 0.0;

    int col = image_HSV.cols; // 480
    int row = image_HSV.rows; // 272

    int corow = ((col - 235) - 215) * ((row - 152) - 108);  

    Mat mask;
    inRange(image_HSV, Scalar(100, 0, 0), Scalar(100, 255, 255), mask); // convert binary
    image_HSV.setTo(Scalar(0, 0, 0), mask);

    for (int i = 108; i < row - 152; i++) {     
        for (int j = 215; j < col - 235; j++) {
            Vec3b hsv = image_HSV.at<cv::Vec3b>(i, j);

            h += (int)(hsv.val[0]);
            s += (int)(hsv.val[1]);
            v += (int)(hsv.val[2]);

            if (hsv[0] != 100) {
                hsv[0] = 0;
                hsv[1] = 0;
                hsv[2] = 0;
            }
        }
    }

    cout << "$$ Hue(H), Saturation(S), Brightness(V) $$" << filenames[t] << " !! \n\n";
    cout << "H: " << h / corow * 360 / 180 << " % \n";  // 
    cout << "S: " << s / corow * 100 / 255 << " % \n";
    cout << "V: " << v / corow * 100 / 255 << " % \n\n";

    std::ofstream file("D:\\data\\dfdf\\result_4.txt", std::ios_base::app);
    file << v / corow * 100 / 255 << " \n"; // v value
    file.close();
}   

}

正如您所看到的 imageAnalysis() 函數,我為從視頻剪輯中提取的圖像的路徑添加了 std::string 文件夾。 但是,當我應用此代碼時,我得到了如下所示的非常奇怪的結果。

在此處輸入圖片說明

我以為我應該從每 24 張圖像中獲取顏色值,但是正如您在上面看到的結果,我以隨機順序從所有圖像中獲取了顏色值。

先感謝您。

學習如何以有效的方式編碼真是太好了!!

只是為了清除您在評論中提到的關於CV_CAP_PROP_POS_MSEC的錯誤:

當我將 CV_CAP_PROP_POS_MSEC 應用於我的代碼時,我發現了一些錯誤消息,例如“未定義 CV_CAP_PROP_POS_MSEC”。

許多常量值都在 OpenCV 范圍內。 這意味着, CV_CAP_PROP_POS_MSEC沒有定義,但cv::CV_CAP_PROP_POS_MSEC是。 您還可以使用cv::CAP_PROP_FPS獲得 FPS。

現在到您的代碼,我實際上會做一些不需要保存和加載圖像的事情,而是傳遞要處理的圖像,如下所示:

#include "opencv2/opencv.hpp"
#include <iostream>

int main(){
  cv::VideoCapture cap("D:\\data\\extra\\video200ul.avi"); 
  if (!cap.isOpened())  
  {
    std::cout << "Could not open video" << std::endl;
    return -1;
  }

  cv::Ptr<cv::BackgroundSubtractor> pMOG2 = cv::createBackgroundSubtractorMOG2(20, 16, true);

  cv::Mat fg_mask, frame;
  int count = 0;
  const int fps = 24; // you may set here the fps or get them from the video

  std::string name, folder;

  // with cap.read you can check already if the video ended
  while (cap.read(frame)) {
    // Background subtraction
    if (count % fps == 0) {
        pMOG2->apply(frame, fg_mask, 0.001);
        // Save foreground mask
        name = "mask" + std::to_string(count) + ".png";
        bool result = cv::imwrite("D:\\data\\extra\\" + name, frame);
        imageAnalysis(frame, count);
    }
    // at the end of the loop so that the first image is used
    ++count;
  }   
  cv::waitKey(0);
  return 0;
}

imageAnalysis函數定義為:

// You can pass cv::Mat as value, it is almost like a smart pointer
void imageAnalysis(cv::Mat frame, int count)
{
  cv::Mat ori_image = frame.clone();
  cv::rectangle(ori_image, Point(215, 98), Point(245, 110), Scalar(0, 255, 255), 1); 
  // each imshow needs a waitKey to update the window in which it is being shown
  cv::imshow("Original Image", ori_image);
  cv::waitKey(1);

  cv::Scalar sums;
  sums = cv::sum(ori_image);
  double totalSum = sums[0] + sums[1] + sums[2];

  std::ofstream output("D:\\data\\extra\\mask" + std::to_string(count) + ".txt");
  if (totalSum <= 0) 
  {
    std::cout << "$$ RGB percentage $$" << std::endl << std::endl;
    std::cout << "R: " << 100.0 / 3 << std::endl;
    std::cout << "G: " << 100.0 / 3 << std::endl;
    std::cout << "B: " << 100.0 / 3 << std::endl << std::endl;
    output << "$$ RGB percentage $$" << std::endl << std::endl;
    output << "R: " << 100.0 / 3 << std::endl;
    output << "G: " << 100.0 / 3 << std::endl;
    output << "B: " << 100.0 / 3 << std::endl << std::endl;
  }
else {
    std::cout << "$$ RGB percentage $$" << std::endl << std::endl;
    std::cout << "R: " << sums[2] / totalSum * 100 << std::endl; // red value
    std::cout << "G: " << sums[1] / totalSum * 100 << std::endl; // green value
    std::cout << "B: " << sums[0] / totalSum * 100 << std::endl << std::endl; // blue value
    output  << "$$ RGB percentage $$" << std::endl << std::endl;
    output  << "R: " << sums[2] / totalSum * 100 << std::endl; // red value
    output  << "G: " << sums[1] / totalSum * 100 << std::endl; // green value
    output  << "B: " << sums[0] / totalSum * 100 << std::endl << std::endl; // blue value
  }
}

上面代碼的一些注釋,我將cap >> frame替換為cap.read(frame) 它是相同的功能,但后者給出了一個布爾結果,如果它無法抓取圖像,則該結果為假,例如視頻結束。 我在最后更改了計數添加,你得到了 0,23 幀,...這樣第一個也將被使用。 最后,您應該使用命名空間cv::std::等。這只是最佳實踐,它避免了某些庫可能出現的歧義和問題。

如果您不需要磁盤中的圖像,而只需要分析,則刪除保存部分並將每一幀傳遞給 imageAnalysis 函數,這樣您可能會有更多數據用於統計。 另外,考慮在函數中返回 cv:Scalar sums,然后您可以對整秒或整個視頻進行一些統計。

如果您有任何問題,請隨時在評論中提問。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM