Это сочетание нескольких проблем.
Первая проблема заключается в том, что для типа compositeFrame
установлено значение, возвращаемое vid.get(cv::CAP_PROP_FORMAT)
. К сожалению, это свойство не кажется полностью надежным - я только что вернул 0 (что означает CV_8UC1
) после открытия цветного видео и получения 3-канальных (CV_8UC3
) кадров. Поскольку вы хотите, чтобы compositeFrame
был того же типа, что и входной кадр, это не сработает.
Чтобы обойти это, вместо использования этих свойств, я бы лениво инициализировал compositeFrame
и 3 области интереса после получения первого кадра (в зависимости от его размеров и типа).
Следующая группа проблем заключается в этих двух утверждениях:
cv::cvtColor(frame, compBwPart, cv::COLOR_BGR2GRAY);
cv::Canny(compBwPart, compEdgePart, 100, 150);
В этом случае предполагается, что frame
- это BGR (поскольку вы пытаетесь конвертировать), что означает compositeFrame
, а его ROI также являются BGR. К сожалению, в обоих случаях вы записываете изображение в градациях серого в ROI. Это приведет к перераспределению, и цель Mat
перестанет быть ROI.
Чтобы исправить это, используйте временные Mat
s для данных в градациях серого и используйте cvtColor
, чтобы вернуть их в BGR для записи в области ROI.
Аналогичная проблема заключается в следующем утверждении:
compOrigPart = frame;
Это мелкая копия, означающая, что она просто сделает compOrigPart
еще одной ссылкой на frame
(и, следовательно, она перестанет быть ROI compositeFrame
).
Вам нужна глубокая копия с использованием 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);
}
}
Снимок экрана составного окна (с использованием случайного тестового видео из Интернета):