我有奇怪的问题。我正在通过网络摄像头和OpenCV拍摄一系列连续事件的照片。将它们存储在矢量变量中。在捕获功能结束时,我得到的只是最后一次捕获。
我认为我的向量存在根本问题。功能如下
void eventCapture()
{
vector<cv::Mat> capturedAll;
getCaptures(capturedAll, 10, 500);
int csize = capturedAll.size();
// Here gives always the last capture
// It is not related with imshow
// imwrite also saves the last capture as wrong
for (int i = 0; i < 10; i++) {
cv::imshow("Images", capturedAll[i]);
string imgname = "imgcaps" + to_string(i) + ".jpg";
cv::imwrite(imgname, capturedAll[i]);
cv::waitKey(100);
}
}
void getCaptures(vector<cv::Mat>& capStore, int count, int tdif)
{
QElapsedTimer capTimer;
capTimer.start();
for (int i = 0; i < count; i++) {
capTimer.restart();
// get_capture takes a photo from webcam
cv::Mat capMat = webCam.get_capture();
capStore.push_back(capMat);
string imgname = "localsave" + to_string(i) + ".jpg";
// Saved image here is giving correct result
cv::imwrite(imgname, capMat);
while (!capTimer.hasExpired(tdif))
qApp->processEvents();
}
}
我也尝试使用迭代器,但它给出了同样错误的结果。
我认为问题是关于cv :: Mat的指针。改变下面部分解决了问题。但我完全不明白。每次在循环中我都会再次初始化capMat。
cv::Mat capMat = webCam.get_capture();
capStore.push_back(capMat.clone());
如果你在Qt工作(正如你的标签所示)最好的方法是完全避免这种情况是将图像深度复制到QImage
以避免创建cv::Mat
的副本。这是从QImage
创建cv::Mat
的安全方法,它还可以在删除最后一个QImage
引用时释放内存:
cv::Mat* capture;
size_t bufferSize = capture->cols * capture->rows * capture->channels();
auto pixelFormat = toPixelFormat(capture->format);
auto outputBuffer = new uchar[bufferSize];
// This will not work for sparse mats - you have to copy row-by-row
memcpy(outputBuffer, capture->data, bufferSize);
// Have to pass stride since QImage is padding the rows for non power-of-two sizes
QImage image(outputBuffer, capture->cols, capture->rows, capture->cols * capture->channels(), pixelFormat, DeleteImageData, outputBuffer);
你需要将cv::Mat
格式转换为正确的QImage::Format,例如:
QImage::Format ImageFilterPrivate::getOpenCVType(int openCvFormat) {
switch(openCvFormat) {
case CV_8UC4: return QImage::Format_ARGB32;
case CV_8UC3: return QImage::Format_RGB888;
// ... etc.
}
}
一些OpenCV格式(例如16位灰度级在Qt中没有匹配类型)。在QImage
的最后一次引用丢失后,您还需要提供一个删除已分配数据的函数,以避免内存泄漏(可以作为lambda传递):
void DeleteImageData(void* data) {
auto buffer = static_cast<unsigned char*>(data);
delete buffer;
}