举个例子说明,在LPV中怎么实现算法结果的显示
在这个例子中,我们使用了模板算法,对OK和NG两种模板的图像进行了分类,在分类为完成后,需要绘制出定位到模板的边框和在对应位置显示OK/NG结果的效果,代码段如下
// ==================== 手动设置参数 ====================
// OK模板区域坐标 (起点110,560 宽140 高130)
double OK_TemplateX = 180.0;
double OK_TemplateY = 625.0;
double OK_TemplateWidth = 140.0;
double OK_TemplateHeight = 130.0;
double OK_TemplateAngle = 0.0;
// NG模板区域坐标 (起点440,560 宽140 高130)
double NG_TemplateX = 510.0;
double NG_TemplateY = 625.0;
double NG_TemplateWidth = 140.0;
double NG_TemplateHeight = 130.0;
// 匹配参数
int AcceptScore = 60;
int AngleTolerance = 90;
int MaxCount = 10;
int main()
{
// 初始化COM
CoInitialize(NULL);
// ============================================================
// 1. 读取图像
// ============================================================
ILImagePtr srcImage = LImage::Create();
if (!srcImage) {
std::cout << "Failed to create image object" << std::endl;
return -1;
}
LPVErrorCode err = srcImage->Load(L"D:\\LPV20260312\\Template\\image\\new_20260311.png");
if (err != LPVNoError) {
std::cout << "Failed to load image: " << (int)err << std::endl;
return -1;
}
std::cout << "[1] Image loaded successfully" << std::endl;
std::cout << " Image size: " << srcImage->GetWidth() << " x " << srcImage->GetHeight() << std::endl;
// ============================================================
// 2. RGB转灰度
// ============================================================
ILImageConvertPtr imgConvert = LImageConvert::Create();
ILImagePtr grayImage = LImage::Create();
imgConvert->BGRToGray(srcImage, grayImage);
std::cout << "[2] Image converted to gray" << std::endl;
// ============================================================
// 3. 创建模板ROI - 矩形区域+圆形区域做差集
// ============================================================
// 矩形区域: 起点(110,560) 宽130 高140
ILRectRegionPtr rectRegion = LRectRegion::Create();
rectRegion->SetPlacement(110, 560, 130, 140);
std::cout << "[3a] Rect region created at (110, 560), size 130x140" << std::endl;
// 圆形区域: 圆心(175,630) 半径60 (矩形中心)
ILCircleRegionPtr circleRegion = LCircleRegion::Create();
circleRegion->SetPlacement(175, 630, 60);
std::cout << "[3b] Circle region created at (175, 630), radius 60" << std::endl;
// 矩形 ∩ 圆形 = 交集区域 (使用Intersect做交集)
ILCompoundRegionPtr shapeRegion = rectRegion->Intersect(circleRegion);
std::cout << "[3c] Shape region created (rect ∩ circle)" << std::endl;
// 截图并保存模板图像 (使用交集区域)
ILImagePtr okTemplateImage = LImage::Create();
shapeRegion->ReduceImage(grayImage, &okTemplateImage, NULL);
err = okTemplateImage->Save(L"D:\\LPV20260312\\Template\\template_ok.png", NULL);
if (err == LPVNoError) {
std::cout << "[3d] OK Template image saved to template_ok.png" << std::endl;
}
// ============================================================
// 4. 训练OK模板 - 使用圆形区域训练
// ============================================================
ILMatchPtr okMatchTool = LMatch::Create();
okMatchTool->PutAcceptScore(AcceptScore);
okMatchTool->PutAngleBias(180);
okMatchTool->PutAngleTolerance(AngleTolerance);
okMatchTool->PutMaxCount(MaxCount);
okMatchTool->PutMatchMethod(LPVPatMatchMixed); // 混合匹配
okMatchTool->PutGrayValueWeight(50); // 灰度权重50%
okMatchTool->PutDetailLevel(0.5);
okMatchTool->PutMaxDeformation(2);
okMatchTool->PutNoiseThreshold(10);
okMatchTool->PutOverlap(50);
// 使用圆形区域训练模板
err = okMatchTool->Learn(grayImage, circleRegion);
if (err != LPVNoError) {
std::cout << "[5] Failed to train OK template: " << (int)err << std::endl;
return -1;
}
std::cout << "[5] OK Template trained successfully" << std::endl;
// ============================================================
// 5. 使用Prune剔除边缘特征,只保留中间十字区域
// ============================================================
// 中心点(175, 630),保留半径60 (矩形中心)
double centerX = 175; // OK中心X = 110 + 130/2
double centerY = 630; // OK中心Y = 560 + 140/2
double pruneRadius = 60; // 保留半径
// 创建保留区域(中心小圆)
ILCircleRegionPtr keepRegion = LCircleRegion::Create();
keepRegion->SetPlacement(centerX, centerY, pruneRadius);
std::cout << "[5a] Keep region created at center (" << centerX << ", " << centerY << "), radius " << pruneRadius << std::endl;
// 使用Prune保留中间区域
err = okMatchTool->Prune(grayImage, keepRegion, NULL, NULL);
if (err != LPVNoError) {
std::cout << "[5b] Prune failed: " << (int)err << std::endl;
} else {
std::cout << "[5b] Prune successful - kept center region" << std::endl;
}
if (err != LPVNoError) {
std::cout << "[5] Failed to train OK template: " << (int)err << std::endl;
return -1;
}
std::cout << "[5] OK Template trained successfully" << std::endl;
// 获取并保存模板图像
ILImagePtr patImage = LImage::Create();
okMatchTool->GetPatImage(patImage);
if (patImage && patImage->Valid()) {
err = patImage->Save(L"D:\\LPV20260312\\Template\\template_image.png", NULL);
if (err == LPVNoError) {
std::cout << "[5a] Template image saved to template_image.png" << std::endl;
}
}
// ============================================================
// 4b. 创建NG模板ROI - 矩形区域+圆形区域做差集
// ============================================================
// NG矩形区域: 起点(440,560) 宽130 高140
ILRectRegionPtr ngRectRegion = LRectRegion::Create();
ngRectRegion->SetPlacement(440, 560, 130, 140);
std::cout << "[4a] NG Rect region created at (440, 560), size 130x140" << std::endl;
// NG圆形区域: 圆心(505,630) 半径60 (矩形中心)
ILCircleRegionPtr ngCircleRegion = LCircleRegion::Create();
ngCircleRegion->SetPlacement(505, 630, 60);
std::cout << "[4b] NG Circle region created at (505, 630), radius 60" << std::endl;
// 矩形 ∩ 圆形 = NG交集区域
ILCompoundRegionPtr ngShapeRegion = ngRectRegion->Intersect(ngCircleRegion);
std::cout << "[4c] NG Shape region created (rect ∩ circle)" << std::endl;
// 截图并保存NG模板图像
ILImagePtr ngTemplateImage = LImage::Create();
ngShapeRegion->ReduceImage(grayImage, &ngTemplateImage, NULL);
err = ngTemplateImage->Save(L"D:\\LPV20260312\\Template\\template_ng.png", NULL);
if (err == LPVNoError) {
std::cout << "[4d] NG Template image saved to template_ng.png" << std::endl;
}
// ============================================================
// 5. 训练NG模板
// ============================================================
ILMatchPtr ngMatchTool = LMatch::Create();
ngMatchTool->PutAcceptScore(AcceptScore);
ngMatchTool->PutAngleBias(180);
ngMatchTool->PutAngleTolerance(AngleTolerance);
ngMatchTool->PutMaxCount(MaxCount);
ngMatchTool->PutMatchMethod(LPVPatMatchMixed); // 混合匹配
ngMatchTool->PutGrayValueWeight(40); // 灰度权重50%
ngMatchTool->PutDetailLevel(0.5);
ngMatchTool->PutMaxDeformation(2);
ngMatchTool->PutNoiseThreshold(10);
ngMatchTool->PutOverlap(50);
// 使用Learn训练NG模板
err = ngMatchTool->Learn(grayImage, ngRectRegion);
if (err != LPVNoError) {
std::cout << "[5] Failed to train NG template: " << (int)err << std::endl;
return -1;
}
std::cout << "[5] NG Template trained successfully" << std::endl;
// ============================================================
// 6. 执行OK模板匹配
// ============================================================
ILMatchResultsPtr okMatchResults;
err = okMatchTool->Match(grayImage, NULL, &okMatchResults);
if (err != LPVNoError || !okMatchResults) {
std::cout << "[7] OK Match failed: " << (int)err << std::endl;
return -1;
}
int okMatchCount = okMatchResults->Count();
std::cout << "[7] OK Template found " << okMatchCount << " matches" << std::endl;
// 输出每个OK匹配结果
std::cout << "\n--- OK Template Match Details ---" << std::endl;
for (int i = 0; i < okMatchCount; i++) {
ILMatchResultPtr result = okMatchResults->Item(i);
std::cout << " Match " << (i+1) << ": X=" << result->Center->GetX()
<< ", Y=" << result->Center->GetY()
<< ", Score=" << result->Score
<< ", Angle=" << result->Angle << std::endl;
}
// ============================================================
// 6b. 执行NG模板匹配
// ============================================================
ILMatchResultsPtr ngMatchResults;
err = ngMatchTool->Match(grayImage, NULL, &ngMatchResults);
if (err != LPVNoError || !ngMatchResults) {
std::cout << "[7b] NG Match failed: " << (int)err << std::endl;
return -1;
}
int ngMatchCount = ngMatchResults->Count();
std::cout << "[7b] NG Template found " << ngMatchCount << " matches" << std::endl;
// 输出每个NG匹配结果
std::cout << "\n--- NG Template Match Details ---" << std::endl;
for (int i = 0; i < ngMatchCount; i++) {
ILMatchResultPtr result = ngMatchResults->Item(i);
std::cout << " Match " << (i+1) << ": X=" << result->Center->GetX()
<< ", Y=" << result->Center->GetY()
<< ", Score=" << result->Score
<< ", Angle=" << result->Angle << std::endl;
}
// ============================================================
// 7. 比较OK和NG分数,确定最终结果
// ============================================================
std::cout << "\n=== Classification ===" << std::endl;
// 找到每个OK匹配位置最近的NG匹配,比较分数
std::string finalResult = "Unknown";
double okBestScore = 0;
double ngBestScore = 0;
double finalX = 0;
double finalY = 0;
if (okMatchCount > 0 && ngMatchCount > 0) {
// 对于每个OK匹配,找最近的NG匹配
for (int i = 0; i < okMatchCount; i++) {
ILMatchResultPtr okResult = okMatchResults->Item(i);
double okX = okResult->Center->GetX();
double okY = okResult->Center->GetY();
double okScore = okResult->Score;
// 找最近的NG匹配
double minDist = 1e10;
double ngScore = 0;
for (int j = 0; j < ngMatchCount; j++) {
ILMatchResultPtr ngResult = ngMatchResults->Item(j);
double ngX = ngResult->Center->GetX();
double ngY = ngResult->Center->GetY();
double dist = sqrt((okX - ngX)*(okX - ngX) + (okY - ngY)*(okY - ngY));
if (dist < minDist) {
minDist = dist;
ngScore = ngResult->Score;
}
}
std::cout << " OK Match " << (i+1) << ": OK_Score=" << okScore
<< ", NG_Score=" << ngScore
<< ", Distance=" << minDist << std::endl;
if (okScore > okBestScore) {
okBestScore = okScore;
ngBestScore = ngScore;
finalX = okX;
finalY = okY;
}
}
if (okBestScore > ngBestScore) {
finalResult = "OK";
} else {
finalResult = "NG";
}
} else if (okMatchCount > 0 && ngMatchCount == 0) {
// 只有OK匹配
finalResult = "OK";
for (int i = 0; i < okMatchCount; i++) {
ILMatchResultPtr okResult = okMatchResults->Item(i);
if (okResult->Score > okBestScore) {
okBestScore = okResult->Score;
finalX = okResult->Center->GetX();
finalY = okResult->Center->GetY();
}
}
} else if (okMatchCount == 0 && ngMatchCount > 0) {
// 只有NG匹配
finalResult = "NG";
for (int i = 0; i < ngMatchCount; i++) {
ILMatchResultPtr ngResult = ngMatchResults->Item(i);
if (ngResult->Score > ngBestScore) {
ngBestScore = ngResult->Score;
finalX = ngResult->Center->GetX();
finalY = ngResult->Center->GetY();
}
}
}
std::cout << "Final Result: " << finalResult << std::endl;
std::cout << " Best OK Score: " << okBestScore << std::endl;
std::cout << " Best NG Score: " << ngBestScore << std::endl;
// ============================================================
// 8. 显示匹配结果
// ============================================================
std::cout << "\n显示匹配结果..." << std::endl;
ILDisplayPtr displayCtrl = LDisplay::Create();
if (!displayCtrl) {
std::cout << "显示控件创建失败,请检查LPVDisplay模块是否注册" << std::endl;
}
else {
// 设置显示图像
displayCtrl->SetImage(grayImage);
// 绘制OK模板ROI区域(调试信息)
// 矩形区域 center=(175, 630)
ILRectPtr okRect = LRect::Create();
okRect->Set(175, 630, 130, 140, 0);
IDispatch* pDispOkRect = okRect;
//displayCtrl->AddObject(pDispOkRect, 0);
// 绘制NG模板ROI区域(调试信息)
// 矩形区域 center=(505, 630)
ILRectPtr ngRect = LRect::Create();
ngRect->Set(505, 630, 130, 140, 0);
IDispatch* pDispNgRect = ngRect;
//displayCtrl->AddObject(pDispNgRect, 0);
// 绘制template_image截取位置文本
ILTextPtr debugText = LText::Create();
debugText->Text = L"Green: OK ROI, Red: NG ROI";
debugText->PosX = 10;
debugText->PosY = 10;
displayCtrl->AddObject(debugText, 0);
// 为每个匹配绘制ROI区域
if (okMatchCount > 0) {
for (int i = 0; i < okMatchCount; i++) {
ILMatchResultPtr result = okMatchResults->Item(i);
double x = result->Center->GetX();
double y = result->Center->GetY();
double score = result->Score;
// 创建新矩形 (宽度130, 高度140)
ILRectPtr rect = LRect::Create();
rect->Set(x, y, 130, 140, 0);
// 添加矩形到显示
IDispatch* pDisp = rect;
displayCtrl->AddObject(pDisp, 0);
// 创建文本标签 - 显示分数
ILTextPtr text = LText::Create();
wchar_t buffer[256];
swprintf(buffer, 256, L"%d: Score=%.1f", i+1, score);
text->Text = buffer;
text->PosX = (int)x;
text->PosY = (int)(y - 80);
text->Alignment = LPVAlignCenter;
displayCtrl->AddObject(text, 0);
// 对每个OK匹配,找最近的NG匹配,确定结果
double minDist = 1e10;
double ngScore = 0;
for (int j = 0; j < ngMatchCount; j++) {
ILMatchResultPtr ngResult = ngMatchResults->Item(j);
double ngX = ngResult->Center->GetX();
double ngY = ngResult->Center->GetY();
double dist = sqrt((x - ngX)*(x - ngX) + (y - ngY)*(y - ngY));
if (dist < minDist) {
minDist = dist;
ngScore = ngResult->Score;
}
}
// 显示结果文本在匹配位置
std::string resultAtPos = (score > ngScore) ? "OK" : "NG";
ILTextPtr resultText = LText::Create();
wchar_t resultBuffer[256];
swprintf(resultBuffer, 256, L"Result: %hs", resultAtPos.c_str());
resultText->Text = resultBuffer;
resultText->PosX = (int)x;
resultText->PosY = (int)(y + 80);
resultText->Alignment = LPVAlignCenter;
// 设置结果文本颜色
ILDrawablePtr drawable = resultText;
if (resultAtPos == "OK") {
drawable->SetPenColor(LPVGreen);
} else {
drawable->SetPenColor(LPVRed);
}
displayCtrl->AddObject(resultText, 0);
}
}
// 显示结果
displayCtrl->ShowDialog(L"模板匹配结果", 0, 0, 1500, 900);
}
return 0;
}
最终展示效果
