org.openpnp.vision.pipeline.stages.MatchTemplate
在输入图像中检测与给定模板图像相似的区域。它基于 OpenCV 的归一化互相关模板匹配方法(TM_CCOEFF_NORMED),并集成了局部极大值检测和距离过滤,返回所有匹配位置(按得分降序排列)。该阶段常用于零件定位、模式识别等场景。以上图片和cv-pipeline脚本,检测出的匹配区域为右上角的矩形,但是那里并没有什么前景图片。MatchTemplate 要求输入图像和模板必须是 8位单通道(
·
文章目录
org.openpnp.vision.pipeline.stages.MatchTemplate
功能
在输入图像中检测与给定模板图像相似的区域。它基于 OpenCV 的归一化互相关模板匹配方法(TM_CCOEFF_NORMED),并集成了局部极大值检测和距离过滤,返回所有匹配位置(按得分降序排列)。该阶段常用于零件定位、模式识别等场景。
参数
| 参数名 | 类型 | 默认值 | 描述 |
|---|---|---|---|
templateStageName |
String |
无(必需) | 提供模板图像的前一阶段名称。该阶段必须输出包含图像(Result.image)的结果。 |
threshold |
double |
0.7 |
绝对匹配得分阈值(归一化相关系数)。匹配得分低于此值的区域将被忽略。取值范围 0~1。 |
corr |
double |
0.85 |
相对于全局最大匹配得分的比例阈值。实际动态阈值为 max(threshold, corr * maxVal)。例如,若最大得分为 0.9,corr=0.85,则动态下限为 0.765。 |
normalize |
boolean |
true |
是否将每个匹配得分除以全局最大匹配得分。若为 true,最高得分归一化为 1,其余为相对值;若为 false,输出原始相关系数。 |
maxDistance |
int |
10000 |
匹配矩形中心与预设中心(默认为图像中心)之间的最大允许欧氏距离(像素)。超过此距离的匹配将被丢弃。 |
propertyName |
String |
"" |
用于运行时动态覆盖参数的属性名前缀。若设置,可通过 pipeline.setProperty(propertyName + ".maxDistance", value) 或 pipeline.setProperty(propertyName + ".center", value) 在运行时调整 maxDistance 和 center。 |
例子
MatchTemplate 不支持旋转
MatchTemplate 要求输入图像和模板必须是 8位单通道(灰度)且类型一致
test1
不对的版本
生成测试图片
import cv2
import numpy as np
def generate_all_images():
# 1. 模板图像(正面红色矩形,宽200高100)
template = np.zeros((100, 200, 3), dtype=np.uint8)
cv2.rectangle(template, (0, 0), (200, 100), (0, 0, 255), -1)
cv2.imwrite("template_rect.png", template)
print("生成模板: template_rect.png")
# 2. 测试图像(蓝色背景 640x480)
img = np.full((480, 640, 3), (255, 0, 0), dtype=np.uint8)
# 红色矩形1:中心 (150, 150),尺寸 200x100,角度 0°
rect1 = ((150, 150), (200, 100), 0)
box1 = cv2.boxPoints(rect1)
box1 = np.int32(box1)
cv2.fillPoly(img, [box1], (0, 0, 255))
# 红色矩形2:中心 (480, 280),尺寸 200x100,角度 0°
rect2 = ((480, 280), (200, 100), 0)
box2 = cv2.boxPoints(rect2)
box2 = np.int32(box2)
cv2.fillPoly(img, [box2], (0, 0, 255))
# 绿色三角形(干扰物)
pts = np.array([[580, 430], [620, 460], [560, 460]], np.int32)
cv2.fillPoly(img, [pts], (0, 255, 0))
cv2.imwrite("test_multi_parts.png", img)
print("生成测试图像: test_multi_parts.png (两个200x100无旋转红色矩形 + 一个绿色三角形)")
if __name__ == "__main__":
generate_all_images()
cv-pipeline config
<cv-pipeline>
<stages>
<cv-stage class="org.openpnp.vision.pipeline.stages.ImageRead" name="readTemplateColor" enabled="true" file="D:\3rd\openpnp_prj\openpnp-official\openpnp-test-images\my_test\template_rect.png" color-space="Bgr" handle-as-captured="false"/>
<cv-stage class="org.openpnp.vision.pipeline.stages.ConvertColor" name="templateGray" enabled="true" conversion="Bgr2Gray"/>
<cv-stage class="org.openpnp.vision.pipeline.stages.ImageRead" name="readTestColor" enabled="true" file="D:\3rd\openpnp_prj\openpnp-official\openpnp-test-images\my_test\test_multi_parts.png" color-space="Bgr" handle-as-captured="false"/>
<cv-stage class="org.openpnp.vision.pipeline.stages.ConvertColor" name="testGray" enabled="true" conversion="Bgr2Gray"/>
<cv-stage class="org.openpnp.vision.pipeline.stages.MatchTemplate" name="match" enabled="true" template-stage-name="templateGray" threshold="0.7" corr="0.85" normalize="true" max-distance="10000" property-name=""/>
<cv-stage class="org.openpnp.vision.pipeline.stages.ImageRecall" name="recallOriginal" enabled="true" image-stage-name="readTestColor"/>
<cv-stage class="org.openpnp.vision.pipeline.stages.DrawTemplateMatches" name="drawMatches" enabled="true" template-matches-stage-name="match">
<color r="0" g="255" b="0" a="255"/>
</cv-stage>
<cv-stage class="org.openpnp.vision.pipeline.stages.ImageWrite" name="save" enabled="true" file="output_match_template.png"/>
</stages>
</cv-pipeline>
错误效果
以上图片和cv-pipeline脚本,检测出的匹配区域为右上角的矩形,但是那里并没有什么前景图片。
org.openpnp.vision.pipeline.stages.MatchTemplate对纯色模板支持错误
看cv-pipeline配置写法,没有发现错误,但是就是识别错误。
后来修改了模板不为纯色图形(实际的模板也不会是纯色图形, e.g. 单个电阻),然后就可以了。
生成测试图片
import cv2
import numpy as np
def generate_all_images():
# 模板图像(红色矩形 + 内部黑色小矩形)
template = np.zeros((100, 200, 3), dtype=np.uint8)
cv2.rectangle(template, (0, 0), (200, 100), (0, 0, 255), -1)
# 添加内部特征:中心画一个 20x20 的黑色方块
cv2.rectangle(template, (90, 40), (110, 60), (0, 0, 0), -1)
cv2.imwrite("template_rect.png", template)
# 1. 模板图像(正面红色矩形,宽200高100)
# template = np.zeros((100, 200, 3), dtype=np.uint8)
# cv2.rectangle(template, (0, 0), (200, 100), (0, 0, 255), -1)
# cv2.imwrite("template_rect.png", template)
# print("生成模板: template_rect.png")
# 2. 测试图像(蓝色背景 640x480)
img = np.full((480, 640, 3), (255, 0, 0), dtype=np.uint8)
# 红色矩形1:中心 (150, 150),尺寸 200x100
rect1 = ((150, 150), (200, 100), 0)
box1 = cv2.boxPoints(rect1)
box1 = np.int32(box1)
cv2.fillPoly(img, [box1], (0, 0, 255))
# 添加黑色小方块(中心在矩形中心)
cv2.rectangle(img, (140, 140), (160, 160), (0, 0, 0), -1)
# 红色矩形2:中心 (480, 280),尺寸 200x100
rect2 = ((480, 280), (200, 100), 0)
box2 = cv2.boxPoints(rect2)
box2 = np.int32(box2)
cv2.fillPoly(img, [box2], (0, 0, 255))
# 添加黑色小方块
cv2.rectangle(img, (470, 270), (490, 290), (0, 0, 0), -1)
# 绿色三角形(干扰物)
pts = np.array([[580, 430], [620, 460], [560, 460]], np.int32)
cv2.fillPoly(img, [pts], (0, 255, 0))
cv2.imwrite("test_multi_parts.png", img)
print("生成测试图像: test_multi_parts.png (两个200x100无旋转红色矩形 + 一个绿色三角形)")
if __name__ == "__main__":
generate_all_images()
cv-pipeline config
<cv-pipeline>
<stages>
<cv-stage class="org.openpnp.vision.pipeline.stages.ImageRead" name="readTemplateColor" enabled="true" file="D:\3rd\openpnp_prj\openpnp-official\openpnp-test-images\my_test\template_rect.png" color-space="Bgr" handle-as-captured="false"/>
<cv-stage class="org.openpnp.vision.pipeline.stages.ConvertColor" name="templateGray" enabled="true" conversion="Bgr2Gray"/>
<cv-stage class="org.openpnp.vision.pipeline.stages.ImageRead" name="readTestColor" enabled="true" file="D:\3rd\openpnp_prj\openpnp-official\openpnp-test-images\my_test\test_multi_parts.png" color-space="Bgr" handle-as-captured="false"/>
<cv-stage class="org.openpnp.vision.pipeline.stages.ConvertColor" name="testGray" enabled="true" conversion="Bgr2Gray"/>
<cv-stage class="org.openpnp.vision.pipeline.stages.MatchTemplate" name="match" enabled="true" template-stage-name="templateGray" threshold="0.7" corr="0.8" normalize="true" max-distance="10000" property-name=""/>
<cv-stage class="org.openpnp.vision.pipeline.stages.ImageWrite" name="saveTestGray" enabled="true" file="D:\3rd\openpnp_prj\openpnp-official\openpnp-test-images\my_test\testGray_debug.png"/>
<cv-stage class="org.openpnp.vision.pipeline.stages.ImageRecall" name="recallOriginal" enabled="true" image-stage-name="readTestColor"/>
<cv-stage class="org.openpnp.vision.pipeline.stages.DrawTemplateMatches" name="drawMatches" enabled="true" template-matches-stage-name="match">
<color r="0" g="255" b="0" a="255"/>
</cv-stage>
<cv-stage class="org.openpnp.vision.pipeline.stages.ImageWrite" name="save" enabled="true" file="output_match_template.png"/>
</stages>
</cv-pipeline>
效果





match阶段,参数corr = 0.8

备注
stages.MatchTemplate对纯色模板支持不好的问题,在实际应用中不是致命问题。
因为实际视觉识别时,作为模板的图像(e.g. 单个电阻),都不可能是纯色的。
如果感兴趣,可以将MatchTemplate拷贝一份,实现自己的myMatchTemplate. 然后试一下对纯色模板的匹配效果。
在同一个包 org.openpnp.vision.pipeline.stages 下,复制 MatchTemplate.java,重命名为 MyMatchTemplate.java。
将 public class MatchTemplate extends CvStage 改为 public class MyMatchTemplate extends CvStage。
在 process 方法修改匹配方法:
Imgproc.matchTemplate(mat, template, result, Imgproc.TM_SQDIFF_NORMED);
增加MyMatchTemplate在openpnp中的注册
// CvPipelineEditor.java
@SuppressWarnings("serial")
public class CvPipelineEditor extends JPanel {
static {
stageClasses = new HashSet<>();
// Parameter stages.
registerStageClass(ParameterNumeric.class);
registerStageClass(ParameterBool.class);
// Vision stages.
// ...
registerStageClass(MatchTemplate.class);
END
更多推荐
所有评论(0)