Multi-threaded inference example.
Multi-threaded inference example.
This example demonstrates how to perform multi-threaded inference using the Mech-DLK SDK. It shows advanced usage patterns for:
The example takes no command-line arguments. Each worker thread loads images from resources/DefectSegmentation/ (located next to the executable or in its parent directory).
#include <vector>
#include <string>
#include <iostream>
#include <filesystem>
#include <thread>
#include <mutex>
#include <chrono>
#include <windows.h>
namespace fs = std::filesystem;
std::mutex cout_mutex;
fs::path getResourcePath()
{
wchar_t exePath[MAX_PATH];
GetModuleFileNameW(NULL, exePath, MAX_PATH);
fs::path exeDir = fs::path(exePath).parent_path();
fs::path resourcesPath = exeDir / "resources";
if (fs::exists(resourcesPath))
{
std::cout << "Resources path to use: " << resourcesPath << std::endl;
return resourcesPath;
}
resourcesPath = exeDir.parent_path() / "resources";
std::cout << "Resources path to use: " << resourcesPath << std::endl;
return resourcesPath;
}
fs::path getPackPath()
{
return getResourcePath() / "DefectSegmentation" / "defect_segmentation_model.dlkpack";
}
fs::path getImagePath(int index)
{
std::string filename;
if (index == 0)
{
filename = "defect_segmentation_image.jpg";
}
else
{
filename = "defect_segmentation_image_" + std::to_string(index) + ".jpg";
}
return getResourcePath() / "DefectSegmentation" / filename;
}
void threadSafePrint(const std::string &message)
{
std::lock_guard<std::mutex> lock(cout_mutex);
std::cout << message << std::endl;
}
void performInference(int threadId)
{
try
{
threadSafePrint("Thread " + std::to_string(threadId) + " starting...");
std::vector<MMindImage> images(4);
for (int i = 0; i < 4; ++i)
{
auto status = images[i].createFromPath(getImagePath(i).string());
{
threadSafePrint("Thread " + std::to_string(threadId) +
" failed to load image " + std::to_string(i) + ": " + std::to_string(static_cast<int>(status)));
return;
}
}
threadSafePrint("Thread " + std::to_string(threadId) + " loaded " +
std::to_string(images.size()) + " images");
engine.
create(getPackPath().wstring());
auto status = engine.
load();
{
threadSafePrint("Thread " + std::to_string(threadId) +
" failed to load model: " + std::to_string(static_cast<int>(status)));
return;
}
threadSafePrint("Thread " + std::to_string(threadId) + " loaded model successfully");
auto startTime = std::chrono::high_resolution_clock::now();
status = engine.
infer(images);
{
threadSafePrint("Thread " + std::to_string(threadId) +
return;
}
auto endTime = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(endTime - startTime);
threadSafePrint("Thread " + std::to_string(threadId) +
" inference completed in " + std::to_string(duration.count()) + "ms");
std::vector<MMindResult> results;
{
threadSafePrint("Thread " + std::to_string(threadId) +
" got " + std::to_string(results.size()) + " results");
for (size_t i = 0; i < results.size(); ++i)
{
threadSafePrint("Thread " + std::to_string(threadId) +
" result " + std::to_string(i) + ": " +
std::to_string(results[i].contours.size()) + " contours");
}
}
if (threadId == 0)
{
{
threadSafePrint("Thread " + std::to_string(threadId) + " showing results...");
images[0].show("Thread0_Result0");
images[1].show("Thread0_Result1");
images[2].show("Thread0_Result2");
images[3].show("Thread0_Result3");
}
}
threadSafePrint("Thread " + std::to_string(threadId) + " completed successfully");
}
catch (const std::exception &e)
{
threadSafePrint("Thread " + std::to_string(threadId) +
" exception: " + std::string(e.what()));
}
catch (...)
{
threadSafePrint("Thread " + std::to_string(threadId) + " unknown exception");
}
}
int main()
{
std::cout << "Starting multi-threaded inference example..." << std::endl;
std::cout << "This example will create 4 threads, each with its own inference engine." << std::endl;
if (!fs::exists(getPackPath()))
{
std::cerr << "Error: Model file not found at " << getPackPath().string() << std::endl;
return -1;
}
const int numThreads = 4;
std::vector<std::thread> threads;
std::cout << "Creating " << numThreads << " threads..." << std::endl;
for (int i = 0; i < numThreads; ++i)
{
threads.emplace_back(performInference, i);
}
std::cout << "All threads started. Waiting for completion..." << std::endl;
for (auto &thread : threads)
{
if (thread.joinable())
{
thread.join();
}
}
std::cout << "All threads completed. Program finished." << std::endl;
return 0;
}
Defines the inference engine for Mech-DLK model packages.
StatusCode create(const std::wstring &dlkpackPath)
Creates an inference engine for the specified model package.
StatusCode load()
Loads the model into memory and prepares it for inference.
StatusCode infer(const std::vector< MMindImage > &images)
Performs inference on the input images.
StatusCode resultVisualization(std::vector< MMindImage > &images)
Draws all module results onto the input images.
StatusCode getModuleResult(const std::string &moduleName, std::vector< MMindResult > &results)
Gets inference results for a specific module.
std::string statusCodeToString(const StatusCode statusCode)
Converts the status code to the corresponding string.