嗨,我写了这个简单的程序
主.cpp
std::vector<cv::Mat> PD_Classifier_VEC;
#define Folder_Address ""
int Main()
{
int overall_counter=0;
for(int j = 0 ; j < 600 ; j++)
{
QString address = Folder_Address + QString::number(overall_counter++) +".jpg";
cv::Mat image = cv::imread(address.toUtf8().constData(),0);
PD_Classifier_VEC.push_back(image);
PD();
}
}
局部放电功能
void PD()
{
static int Total_Frame_Number=0;
Total_Frame_Number++;
cv::Mat Point_MAT = cv::Mat(PD_Classifier_VEC[0].size(),CV_8UC1,cv::Scalar::all(0));
....//Some Calculation //
PD_Classifier_VEC[0].release();
PD_Classifier_VEC.erase(PD_Classifier_VEC.begin());
}
这段代码工作正常,直到 j=56,之后 Qt 显示此错误并退出!!
*** Error in `/home/parsa/QtProjects/QtVLPR/QtVLPR': corrupted double-linked list: 0x0000000000dcf880 ***
我在调试器模式下运行代码,并将此 if 语句代码添加到 PD() 函数中:
void PD()
{
static int Total_Frame_Number=0;
Total_Frame_Number++;
cv::Mat Point_MAT = cv::Mat(PD_Classifier_VEC[0].size(),CV_8UC1,cv::Scalar::all(0));
....//Some Calculation //
if(Total_Frame_Number==56)
{
std::cout<<Point_MAT<<"n"; //it displays the elements perfectly
int Nonz = cv::countNonZero(Point_MAT); //it runs too
cv::imshow("Point_MAT",Point_MAT); //here the error appears !!!
cv::waitKey();
}
PD_Classifier_VEC[0].release();
PD_Classifier_VEC.erase(PD_Classifier_VEC.begin());
}
如您所见,前两行上方提供的注释工作正常,但是当我尝试使用 imshow 显示图像时,程序崩溃并显示损坏的双链表错误 !!这里出了什么问题?
为什么我无法显示此图像,如果POINT_MAT图像已损坏,前两行如何正常工作?
附言如果我从 j=57 启动程序,它工作正常,直到它完成并且没有出现错误,所以
//some calculation
代码工作正常,我确信这一点。
我已经测试了许多其他函数,例如阈值,减法和...它适用于图像的数据部分,它们工作正常,但是当我添加一个适用于元数据+数据部分的函数时,损坏的双链表再次出现!!
cv::subtract(Point_MAT,Point_MAT,temp); //works fine because it only works on data part
Point_MAT.copyTo(Temp_MAT); //gives error cause it works on header part too ...
该错误来自标准 C 库,指示您已经损坏了堆。
具体来说,除非自己的代码中有匹配的addref()
,否则不应在Cv::mat
上调用release()
。 Cv::mat
的行为类似于Qt中常见的隐式共享值(如QImage
),您不必担心手动管理其引用计数。
显而易见的建议是删除"一些计算"部分。对于更多图像,您按原样显示的代码应该可以工作(没有release()
),而无需计算。
将你显示的代码转换为单独的单个文件项目,并确保它运行 - 因为它应该运行。然后,错误仅限于您的计算 - 它仅在您进行计算时才表现出来,这是计算问题的症状。
也许计算会分配内存?
下面是一个有效的、自包含的示例,它演示了显示的代码不仅正常,而且即使您一次在内存中存储一百张图像,一切正常。每个图像的大小为 2MB。
#include <QImage>
#include <QTemporaryFile>
#include <QDebug>
#include <vector>
#include <opencv2/opencv.hpp>
std::vector<cv::Mat> PD_Classifier_VEC;
void PD()
{
cv::Mat Point_MAT = cv::Mat(PD_Classifier_VEC[0].size(),CV_8UC1,cv::Scalar::all(0));
//Some Calculation //
std::stringstream stream;
stream<<Point_MAT<<"n";
int Nonz = cv::countNonZero(Point_MAT);
cv::imshow("Point_MAT",Point_MAT);
PD_Classifier_VEC.erase(PD_Classifier_VEC.begin());
}
int main()
{
QTemporaryFile file;
file.setFileTemplate(file.fileTemplate() + ".jpg");
const int N = 100;
for(int j = 0 ; j < N ; j++)
{
file.open();
QImage img(800, 600, QImage::Format_RGB32);
img.save(&file);
file.close();
QString address = file.fileName();
cv::Mat image = cv::imread(address.toStdString(),0);
PD_Classifier_VEC.push_back(image);
}
while (!PD_Classifier_VEC.empty()) PD();
cv::waitKey();
return 0;
}
Kuba的回答中很好地描述了潜在的问题。
就我而言,我将cv::Mat
作为参数传递给图像的函数。但是在主线程访问该垫子时,获取图像的工作线程已经删除了它。
解决方案是通过垫子的克隆。
...
cv::Mat const img = recordImage();
myWindow->setImage(img);
} // end of function, img will get deleted
...
cv::Mat const img = recordImage();
myWindow->setImage(img.clone());
} // img will get deleted, but the clone will persist