我正在進行生物識別登錄項目,其中人臉識別是其中的一部分。我們正在使用OpenCV 2.4.13。我們有一個Qt的GUI應用程序,它產生一個線程,並通過它的照片來驗證這樣的:OpenCV/QThread段落
void MainWindow::on_button_test_auth_clicked()
{
statusLabel->setText("Authenticating...");
statusLabel->repaint();
Mat* takenImage = cam->takePicture();
AuthThread *authThread = new AuthThread();
connect(authThread, SIGNAL(resultReady(const QString&)), this, SLOT(setLabelText(const QString&)));
connect(authThread, &AuthThread::finished, authThread, &QObject::deleteLater);
authThread->passTakenImage(*takenImage);
authThread->start();
delete takenImage;
}
AuthThread樣子:
class AuthThread : public QThread
{
Q_OBJECT
void run() Q_DECL_OVERRIDE {
Ptr<FaceRecognizer> model = createLBPHFaceRecognizer(4,8,8,8);
model->load(Config::getModelFile().toStdString());
int label = -1;
double distance = 0.0;
model->predict(takenImage, label, distance);
QString labelString;
QTextStream labelStream(&labelString);
double threshold = Config::getThreshold();
if(distance < threshold) {
labelStream << "Authenticated as " << label << "! " << QString::number((threshold - distance), 'f', 2) << " under threshold.";
} else {
labelStream << "Not authenticated! " << QString::number((distance - threshold), 'f', 2) << "over threshold.";
}
emit resultReady(labelString);
}
public:
void passTakenImage(Mat& img) {
takenImage = img;
}
private:
Mat takenImage;
signals:
void resultReady(const QString &s);
};
這一切工作正常上首次on_button_test_auth_clicked()
被調用,但第二次它段錯誤上model->predict(takenImage, label, distance);
我試着運行valgrind,看看究竟是怎麼回事,但我相當新的C++,所以我不能有多大意義的輸出,這是:
==6732== Thread 12 AuthThread:
==6732== Invalid read of size 8
==6732== at 0x8C94262: ??? (in /usr/lib/libtbb.so.2)
==6732== by 0x8C9432A: ??? (in /usr/lib/libtbb.so.2)
==6732== by 0x8C95E27: ??? (in /usr/lib/libtbb.so.2)
==6732== by 0x8C94C21: ??? (in /usr/lib/libtbb.so.2)
==6732== by 0x8C8F50F: ??? (in /usr/lib/libtbb.so.2)
==6732== by 0x8C8D724: tbb::internal::allocate_root_with_context_proxy::allocate(unsigned long) const (in /usr/lib/libtbb.so.2)
==6732== by 0x530D7DA: tbb::interface9::internal::start_for<tbb::blocked_range<int>, cv::calcHist1D_Invoker<float>, tbb::auto_partitioner const>::run(tbb::blocked_range<int> const&, cv::calcHist1D_Invoker<float> const&, tbb::auto_partitioner const&) (in /usr/lib/libopencv_imgproc.so.2.4.13)
==6732== by 0x531378A: cv::calcHist(cv::Mat const*, int, int const*, cv::_InputArray const&, cv::_OutputArray const&, int, int const*, float const**, bool, bool) (in /usr/lib/libopencv_imgproc.so.2.4.13)
==6732== by 0x5DABFA5: ??? (in /usr/lib/libopencv_contrib.so.2.4.13)
==6732== by 0x5DB5899: ??? (in /usr/lib/libopencv_contrib.so.2.4.13)
==6732== by 0x5DB64DD: cv::LBPH::predict(cv::_InputArray const&, int&, double&) const (in /usr/lib/libopencv_contrib.so.2.4.13)
==6732== by 0x428940: AuthThread::run() (auththread.h:28)
==6732== Address 0xfffffffffffffff7 is not stack'd, malloc'd or (recently) free'd
==6732==
==6732==
==6732== Process terminating with default action of signal 11 (SIGSEGV): dumping core
==6732== Access not within mapped region at address 0xFFFFFFFFFFFFFFF7
==6732== at 0x8C94262: ??? (in /usr/lib/libtbb.so.2)
==6732== by 0x8C9432A: ??? (in /usr/lib/libtbb.so.2)
==6732== by 0x8C95E27: ??? (in /usr/lib/libtbb.so.2)
==6732== by 0x8C94C21: ??? (in /usr/lib/libtbb.so.2)
==6732== by 0x8C8F50F: ??? (in /usr/lib/libtbb.so.2)
==6732== by 0x8C8D724: tbb::internal::allocate_root_with_context_proxy::allocate(unsigned long) const (in /usr/lib/libtbb.so.2)
==6732== by 0x530D7DA: tbb::interface9::internal::start_for<tbb::blocked_range<int>, cv::calcHist1D_Invoker<float>, tbb::auto_partitioner const>::run(tbb::blocked_range<int> const&, cv::calcHist1D_Invoker<float> const&, tbb::auto_partitioner const&) (in /usr/lib/libopencv_imgproc.so.2.4.13)
==6732== by 0x531378A: cv::calcHist(cv::Mat const*, int, int const*, cv::_InputArray const&, cv::_OutputArray const&, int, int const*, float const**, bool, bool) (in /usr/lib/libopencv_imgproc.so.2.4.13)
==6732== by 0x5DABFA5: ??? (in /usr/lib/libopencv_contrib.so.2.4.13)
==6732== by 0x5DB5899: ??? (in /usr/lib/libopencv_contrib.so.2.4.13)
==6732== by 0x5DB64DD: cv::LBPH::predict(cv::_InputArray const&, int&, double&) const (in /usr/lib/libopencv_contrib.so.2.4.13)
==6732== by 0x428940: AuthThread::run() (auththread.h:28)
==6732== If you believe this happened as a result of a stack
==6732== overflow in your program's main thread (unlikely but
==6732== possible), you can try to increase the size of the
==6732== main thread stack using the --main-stacksize= flag.
==6732== The main thread stack size used in this run was 8388608.
這似乎表明在libtbb.so,線程構建塊中出現了問題,我認爲這是爲QThread提供動力的。
奇怪的是,當我將AuthThread代碼移動到on_button_test_auth_clicked()
時,無論被調用多少次,它都可以正常工作。也許來自舊線程的東西繼續存在,第二次弄亂了東西?
opencv Ptr的工作方式與shared_ptr類似,應該在模型超出範圍後明確清理模型(明確釋放它並沒有幫助)。所有其他的東西都是堆棧分配的,所以他們不應該導致任何內存問題,據我所知。
我試過的另一件事是克隆圖像墊,以防它在需要之前被意外刪除。這也沒有幫助。
爲了增加趣味性,這個確切的代碼在我正在使用的傢伙的計算機上運行良好。任何幫助/提示將非常感激。
這是比較普遍的,但在解除引用之前始終要求空指針是一種很好的做法。 I.e .:在你嘗試去除之前,在任何地方放置一個「if(model)」。例如:'模型 - >預測(拍攝圖像,標籤,距離);'。這應該避免你遇到的段錯誤。希望這有助於調試。 – tobilocker
沒讀過你的代碼,你是否用互斥或原子操作來保護你的關鍵部分?也許一些線程正在讀取一個變量,而另一個線程正在寫它=>很大的麻煩 – Micka
@Micka我沒有寫這個代碼,但我會檢查是否是這種情況。似乎所有變量都是線程本身的本地,除了可能被拍攝,但我認爲一個是複製的。我認爲最奇怪的是這個代碼在其他兩臺運行它的機器上始終正常工作。 – Tom