【发布时间】:2019-06-15 00:02:33
【问题描述】:
我在设计程序时遇到过,允许每秒从视频文件(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
其次,当我将此代码合并到我在下面编写的另一个代码时,它显示了一些错误消息,例如“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 个图像中获取颜色值,但正如您在上面看到的结果,我从所有图像中以随机顺序获取颜色值。
提前谢谢你。
学习如何高效地编码真是太好了!
【问题讨论】:
-
您应该使用堆栈跟踪编写完整的错误。很难阅读大量代码并预见可能的问题。在这种情况下,我猜您正在保存一些空图像?您应该在第一个代码中包含
if(frame.empty()) break;之类的内容,以避免出现空图像问题。另外,CV_CAP_PROP_POS_MSEC有什么不适用的?这不是cap >> frame的替代品。还有一件事,真的需要图像并重新加载它们,将图像传递给其他函数不是更好吗? -
嗨 api55,非常感谢您的评论。我需要每秒保存图像,因为我需要呈现一些颜色退化的图像。所以,这就是我从视频文件中保存图像的原因。然后,我尝试计算每张图像的 RGB 百分比。所以,这就是为什么我需要每秒保存图像。其实我可以分别操作这两个代码,但是我想节省时间直接从视频文件中获取颜色数据。
-
我很感激我完全忘记添加“if(frame.empty()) break;”如你所说。
-
此外,当我将 CV_CAP_PROP_POS_MSEC 应用于我的代码时,我发现了一些错误消息,例如“CV_CAP_PROP_POS_MSEC 未定义”。所以,我试图在stackoverflow上用类似的问题来解决这个问题,但我找不到合适的答案。
-
而我昨天处理了这段代码,我没有错误信息并且运行良好,但是我仍然有一些问题。因此,我使用“if (count % 24 == 0)”语句每秒节省 24 帧。换句话说,我能够从视频文件中每秒保存图像。所以,我解决了我的第一个问题。但是,当我使用函数“anal(folder);”传输这些数据时,函数 anal() 会读取所有帧的 RGB 颜色。在这种情况下,我想提取每 24 帧(24、48、96、......)的颜色值。这是我的问题。
标签: c++ visual-studio opencv video