我正在尝试使用OpenCV 3.4.1快速处理视频文件,方法是抓取每一帧,转换为灰度,然后对其进行Canny边缘检测。为了实时显示图像,我创建了一个Mat类,其中包含3个额外的标题,其宽度是原始帧的三倍。这3个额外的标题代表了我想在合成中显示的图像,并位于合成的第1,第2和第3水平段。
但是,在图像处理之后,合成图像的显示不符合预期:the first segment (where the original frame should be) is completely black,而其他部分(已处理图像)的显示效果很好。另一方面,如果我display the ROIs one by one in separate windows,则所有图像看起来都很好。
这次,整个复合材料都是黑色的,什么也没显示。
int main() {
cv::VideoCapture vid("./Vid.avi");
if (!vid.isOpened()) return -1;
int frameWidth = vid.get(cv::CAP_PROP_FRAME_WIDTH);
int frameHeight = vid.get(cv::CAP_PROP_FRAME_HEIGHT);
int frameFormat = vid.get(cv::CAP_PROP_FORMAT);
cv::Scalar fontColor(250, 250, 250);
cv::Point textPos(20, 20);
cv::Mat frame;
cv::Mat compositeFrame(frameHeight, frameWidth*3, frameFormat);
cv::Mat compOrigPart(compositeFrame, cv::Range(0, frameHeight), cv::Range(0, frameWidth));
cv::Mat compBwPart(compositeFrame, cv::Range(0, frameHeight), cv::Range(frameWidth, frameWidth*2));
cv::Mat compEdgePart(compositeFrame, cv::Range(0, frameHeight), cv::Range(frameWidth*2, frameWidth*3));
while (vid.read(frame)) {
if (frame.empty()) break;
cv::cvtColor(frame, compBwPart, cv::COLOR_BGR2GRAY);
cv::Canny(compBwPart, compEdgePart, 100, 150);
compOrigPart = frame;
cv::putText(compOrigPart, "Original", textPos, cv::FONT_HERSHEY_PLAIN, 1, fontColor);
cv::putText(compBwPart, "GrayScale", textPos, cv::FONT_HERSHEY_PLAIN, 1, fontColor);
cv::putText(compEdgePart, "Canny edge detection", textPos, cv::FONT_HERSHEY_PLAIN, 1, fontColor);
cv::imshow("Composite of Original, BW and Canny frames", compositeFrame);
cv::imshow("Original", compOrigPart);
cv::imshow("BW", compBwPart);
cv::imshow("Canny", compEdgePart);
cv::waitKey(33);
}
}
答案 0 :(得分:0)
您的compBwPart和compEdgePart是灰度图像,因此Mat类型是CV8UC1-单通道,因此您的CompositeFrame也是灰度的。如果要将这两个图像与彩色图像组合在一起,则必须先将其转换为BGR,然后填充compOrigPart。
while (vid.read(frame)) {
if (frame.empty()) break;
cv::cvtColor(frame, compBwPart, cv::COLOR_BGR2GRAY);
cv::Canny(compBwPart, compEdgePart, 100, 150);
cv::cvtColor(compositeFrame, compositeFrame, cv::COLOR_GRAY2BGR);
frame.copyTo(compositeFrame(cv::Rect(0, 0, frameWidth, frameHeight)));
cv::putText(compOrigPart, "Original", textPos, cv::FONT_HERSHEY_PLAIN, 1, fontColor); //the rest of your code
答案 1 :(得分:0)
这是几个问题的组合。
第一个问题是将compositeFrame
的类型设置为vid.get(cv::CAP_PROP_FORMAT)
返回的值。不幸的是,该属性似乎并不完全可靠-我只是在打开彩色视频后获得3通道(CV_8UC1
)帧后才返回0(表示CV_8UC3
)。由于您想让compositeFrame
与输入框具有相同的类型,因此无法使用。
要解决此问题,而不是使用这些属性,我会在收到第一帧(根据其尺寸和类型)后懒惰初始化compositeFrame
和3个ROI。
下一组问题在于这两个语句:
cv::cvtColor(frame, compBwPart, cv::COLOR_BGR2GRAY);
cv::Canny(compBwPart, compEdgePart, 100, 150);
在这种情况下,假设frame
是BGR(因为您要进行转换),这意味着compositeFrame
及其ROI也是BGR。不幸的是,在两种情况下,您都将灰度图像写入ROI。这将导致重新分配,并且目标Mat
将不再是ROI。
要解决此问题,请为灰度数据使用临时Mat
,然后使用cvtColor
将其恢复为BGR以写入ROI。
类似的问题在于以下陈述:
compOrigPart = frame;
这是一个浅表副本,这意味着它只会使compOrigPart
再次引用frame
(因此它将不再是compositeFrame
的ROI)。
您需要的是使用copyTo
的深层副本(请注意,数据类型仍需要匹配,但是之前已解决)。
最后,即使您尝试在输入视频的类型上保持灵活性(根据vid.get(cv::CAP_PROP_FORMAT)
判断),其余代码也确实假定输入为3通道,否则将中断输入。
至少应该有一些断言来满足这一期望。
将所有内容放在一起:
#include <opencv2/opencv.hpp>
int main()
{
cv::VideoCapture vid("./Vid.avi");
if (!vid.isOpened()) return -1;
cv::Scalar fontColor(250, 250, 250);
cv::Point textPos(20, 20);
cv::Mat frame, frame_gray, edges_gray;
cv::Mat compositeFrame;
cv::Mat compOrigPart, compBwPart, compEdgePart; // ROIs
while (vid.read(frame)) {
if (frame.empty()) break;
if (compositeFrame.empty()) {
// The rest of code assumes video to be BGR (i.e. 3 channel)
CV_Assert(frame.type() == CV_8UC3);
// Lazy initialize once we have the first frame
compositeFrame = cv::Mat(frame.rows, frame.cols * 3, frame.type());
compOrigPart = compositeFrame(cv::Range::all(), cv::Range(0, frame.cols));
compBwPart = compositeFrame(cv::Range::all(), cv::Range(frame.cols, frame.cols * 2));
compEdgePart = compositeFrame(cv::Range::all(), cv::Range(frame.cols * 2, frame.cols * 3));
}
cv::cvtColor(frame, frame_gray, cv::COLOR_BGR2GRAY);
cv::Canny(frame_gray, edges_gray, 100, 150);
// Deep copy data to the ROI
frame.copyTo(compOrigPart);
// The ROI is BGR, so we need to convert back
cv::cvtColor(frame_gray, compBwPart, cv::COLOR_GRAY2BGR);
cv::cvtColor(edges_gray, compEdgePart, cv::COLOR_GRAY2BGR);
cv::putText(compOrigPart, "Original", textPos, cv::FONT_HERSHEY_PLAIN, 1, fontColor);
cv::putText(compBwPart, "GrayScale", textPos, cv::FONT_HERSHEY_PLAIN, 1, fontColor);
cv::putText(compEdgePart, "Canny edge detection", textPos, cv::FONT_HERSHEY_PLAIN, 1, fontColor);
cv::imshow("Composite of Original, BW and Canny frames", compositeFrame);
cv::imshow("Original", compOrigPart);
cv::imshow("BW", compBwPart);
cv::imshow("Canny", compEdgePart);
cv::waitKey(33);
}
}
复合窗口的屏幕截图(使用网络上的一些随机测试视频):