Я работаю над биометрическим проектом входа, в котором распознавание лиц является частью. Мы используем OpenCV 2.4.13. У нас есть приложение Qt GUI, который порождает поток и передает его изображение, чтобы проверить, как это:OpenCV/QThread segfault
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, должен позаботиться о том, чтобы очистить модель после того, как она выходит из сферы действия (явно освобождение ее не помогает). Все остальные вещи выделены в стеке, поэтому они не должны вызывать проблем с памятью, насколько я знаю.
Еще одна вещь, которую я пробовал, - это клонирование изображения Mat, на случай, если он случайно удалится как-то раньше, чем понадобится. Это тоже не помогло.
Чтобы добавить в удовольствие, этот точный код отлично работает на компьютерах ребята, с которыми я работаю. Любая помощь/советы были бы очень оценены.
Это более общий, но рекомендуется всегда запрашивать пустой указатель перед разыменованием. I.e .: поместите 'if (model)' где-нибудь перед тем, как вы попытаетесь устранить проблему. Например: 'model-> pred (tookImage, label, distance);'. Это должно избегать segfault, который вы испытываете. Надеюсь, что это помогает при отладке. – tobilocker
не читал ваш код, вы защитили свои критические разделы с помощью мьютексов или атомных операций? Может быть, какой-то поток читает переменную, в то время как другой поток пишет ее => большая проблема – Micka
@ Мичка Я не писал этот код, но я проверю, так ли это. Кажется, что все переменные являются локальными для самого потока, за исключением, может быть, takeImage, но я думаю, что все они копируются в любом случае. Я думаю, что самым странным является тот факт, что этот код работает отлично все время на двух других машинах, которые его запускают. – Tom