EasyLocateMultiThreadInference
Support |
|
Required licenses |
EasyLocate |
Recommended images |
In the Deep Learning Additional Resources, the images from the folder EasyLocate |
Location |
Deep Learning Inspection\EasyLocateMultiThreadInference \ |
- In C++, the sample EasySegmentSupervisedMultiThreadInference illustrates a multithread inference for EasySegment Supervised.
- In C#, the sample EasyClassifyMultiThreadInference illustrates a multithread inference for EasyClassify.
Purpose
This sample program demonstrates how to:
□ | Perform a multithread inference with EasyLocate. |
□ | Implement external and internal multithreading. |
Code highlights
1. | Launch one acquisition thread running the AcquisitionThread. |
// Acquisition thread creation
acquisitionThread_.reset(new AcquisitionThread(queue_.get(), images_));
connect(acquisitionThread_.get(), &AcquisitionThread::error, this, &MainWindow::showError);
acquisitionThread_->start();
2. | The AcquisitionThread pushes the images into a custom image queue type named ImageQueue. |
ImageInfo imageInfo;
imageInfo.ImageId = i;
EImageC24* img = new EImageC24();
img->Load(images_[i].toStdString());
imageInfo.Image.reset(img);
imageInfo.Timestamp = std::chrono::steady_clock::now();
queue_->addImage(imageInfo);
3. | The program launches NumExternalThreads ProcessingThread. |
// Processing threads creation
ProcessingThread::ExecutionParameters parameters;
parameters.NumInternalThreads = ui->internalThreads->value();
parameters.BatchSize = ui->batchSize->value();
parameters.Engine = ui->engines->currentText().toStdString();
parameters.Device = ui->devices->currentText().toStdString();
parameters.InferencePrecision = ui->precision->currentText().toStdString();
parameters.ToolFilename = toolFilename_.toStdString();
processingThreads_.clear();
numResults_ = 0;
numThreadFinished_ = 0;
for (int i = 0; i < ui->externalThreads->value(); i++)
{
processingThreads_.emplace_back(new ProcessingThread(queue_.get(), parameters));
...
processingThreads_.back()->start();
}
4. | The class ProcessingThread uses Qt signals and slots to pass the result to the method processResult of the main window. |
□ | The connection between the signal resultsReady and the slot processResult is made at the thread creation. |
connect(processingThreads_.back().get(), &ProcessingThread::resultsReady, this, &MainWindow::processResult);
5. | When the ProcessingThread completes the processing of an image, it emits a signal with the result. |
std::vector<ELocatorResult> results = locator->Apply(imgs);
for (int i = 0; i < imageInfo.size(); i++)
{
ImageResult result;
result.ImageId = imageInfo[i].ImageId;
result.Time = timing;
result.Timestamp = imageInfo[i].Timestamp;
result.Result.reset(new ELocatorResult(results[i]));
imageResults.push_back(result);
}
// Pass the result to another thread
emit resultsReady(imageResults);
6. | The methods processResult update the UI and save the result for display. |
void MainWindow::processResult(const QList<ImageResult>& results)
{
// Display the results
for (const auto& result: results)
{
int numObjects = result.Result->GetNumDetectedObjects();
ui->imageList->item(result.ImageId, 1)->setText(QString("%1 objects").arg(numObjects));
ui->imageList->item(result.ImageId, 2)->setText(QString("%1 ms").arg(result.Time));
ui->imageList->item(result.ImageId, 3)->setText(QString("%1 ms").arg(result.Time / results.size()));
results_[result.ImageId] = result;
numResults_ += 1;
}
...
}