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) 在运行时调整 maxDistancecenter

例子

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. 模板图像(正面红色矩形,宽200100)
    # 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

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐