【OpenCV 基础知识 6】形状匹配

文章目录

Demo1

program cv_MatchShapes;

{$APPTYPE CONSOLE}
{$R *.res}

uses
  System.SysUtils,
  ocv.highgui_c,
  ocv.core_c,
  ocv.core.types_c,
  ocv.imgproc_c,
  ocv.imgproc.types_c,
  uResourcePaths;

const
  const_original = cResourceMedia + 'matchshapes2.jpg';
  const_template = cResourceMedia + 'matchshapes_template.jpg';

var
  original: pIplImage = nil;
  template: pIplImage = nil;
  original_filename, template_filename: AnsiString;

  src: pIplImage = nil;
  dst: pIplImage = nil;
  binI: pIplImage = nil;
  binT: pIplImage = nil;
  rgb: pIplImage = nil;
  rgbT: pIplImage = nil;
  storageI: pCvMemStorage = nil;
  storageT: pCvMemStorage = nil;
  contoursI: pCvSeq = nil;
  contoursT: pCvSeq = nil;
  seq0: pCvSeq = nil;
  seqT: pCvSeq = nil;
  seqM: pCvSeq = nil;
  contoursCont: integer;
  font: TCvFont;
  counter: integer;
  perim, match0: double;
  perimT: double = 0;
  matchM: double = 1000;

begin
  try
    // 检查命令行参数,获取原始图像和模板图像的文件名
    // 如果提供了两个参数,则使用提供的文件名,否则使用默认值
    if ParamCount = 2 then
    begin
      original_filename := AnsiString(ParamStr(1));
      template_filename := AnsiString(ParamStr(2));
    end
    else
    begin
      original_filename := const_original;
      template_filename := const_template;
    end;

    // 加载原始图像
    original := cvLoadImage(pCVChar(original_filename), CV_LOAD_IMAGE_COLOR);
    WriteLn(Format('[i] 原始图像: %s', [original_filename]));

    // 加载模板图像
    template := cvLoadImage(pCVChar(template_filename), CV_LOAD_IMAGE_COLOR);
    WriteLn(Format('[i] 模板图像: %s', [template_filename]));

    // 创建并显示原始图像和模板图像窗口
    cvNamedWindow('原始图像', CV_WINDOW_AUTOSIZE);
    cvShowImage('原始图像', original);
    cvNamedWindow('模板图像', CV_WINDOW_AUTOSIZE);
    cvShowImage('模板图像', template);

    // 输出测试信息
    WriteLn('[i] 运行测试 cvMatchShapes()');

    // 克隆原始图像
    src := cvCloneImage(original);

    // 创建原始图像和模板的二值图像
    binI := cvCreateImage(cvGetSize(src), IPL_DEPTH_8U, 1);
    binT := cvCreateImage(cvGetSize(template), IPL_DEPTH_8U, 1);

    // 创建用于显示轮廓的RGB图像
    rgb := cvCreateImage(cvGetSize(original), IPL_DEPTH_8U, 3);
    cvConvertImage(src, rgb, CV_GRAY2BGR);
    rgbT := cvCreateImage(cvGetSize(template), IPL_DEPTH_8U, 3);
    cvConvertImage(template, rgbT, CV_GRAY2BGR);

    // 对原始图像和模板应用Canny边缘检测
    cvCanny(src, binI, 50, 200);
    cvCanny(template, binT, 50, 200);

    // 创建并显示原始图像的Canny边缘图像窗口
    // cvNamedWindow('CannyI', CV_WINDOW_AUTOSIZE);
    // cvShowImage('CannyI', binI);
    // 创建并显示模板图像的Canny边缘图像窗口
    // cvNamedWindow('CannyT', CV_WINDOW_AUTOSIZE);
    // cvShowImage('CannyT', binT);

    // 创建用于存储轮廓的内存存储
    storageI := cvCreateMemStorage(0);

    // 在原始图像中找到轮廓
    contoursCont := cvFindContours(binI, storageI, @contoursI, sizeof(TCvContour), CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE, cvPoint(0, 0));

    // 初始化字体
    cvInitFont(@font, CV_FONT_HERSHEY_PLAIN, 1.0, 1.0);

    // 在原始图像上显示轮廓
    if Assigned(contoursI) then
    begin
      // 遍历轮廓并在图像上绘制
      seq0 := contoursI;
      while Assigned(seq0) do
      begin
        cvDrawContours(rgb, seq0, CV_RGB(255, 216, 0), CV_RGB(0, 0, 250), 0, 1, 8, cvPoint(0, 0));
        seq0 := seq0.h_next;
      end;
    end;

    // 创建并显示包含轮廓的原始图像窗口
    // cvNamedWindow('Cont', CV_WINDOW_AUTOSIZE);
    // cvShowImage('Cont', rgb );

    // 转换回灰度
    cvConvertImage(src, rgb, CV_GRAY2BGR);

    // 创建用于存储轮廓的内存存储
    storageT := cvCreateMemStorage(0);

    // 在模板图像中找到轮廓
    cvFindContours(binT, storageT, @contoursT, sizeof(TCvContour), CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE, cvPoint(0, 0));

    // 遍历模板图像中的轮廓
    if Assigned(contoursT) then
    begin
      seq0 := contoursT;
      while Assigned(seq0) do
      begin
        perim := cvContourPerimeter(seq0);
        if perim > perimT then
        begin
          perimT := perim;
          seqT := seq0;
        end;
        // 遍历轮廓并在图像上绘制
        cvDrawContours(rgbT, seq0, CV_RGB(255, 216, 0), CV_RGB(0, 0, 250), 0, 1, 8, cvPoint(0, 0));
        seq0 := seq0.h_next;
      end;
    end;

    // 在模板图像中突出显示最大的轮廓
    cvDrawContours(rgbT, seqT, CV_RGB(52, 201, 36), CV_RGB(36, 201, 197), 0, 2, 8, cvPoint(0, 0));
    // cvNamedWindow('ContT', CV_WINDOW_AUTOSIZE);
    // cvShowImage('ContT', rgbT);

    // 遍历原始图像中的轮廓
    counter := 0;
    if Assigned(contoursI) then
    begin
      // 遍历轮廓并计算形状匹配度
      seq0 := contoursI;
      while Assigned(seq0) do
      begin
        WriteLn('Assigned seq0: ', Assigned(seq0), '(', IntToHex(Integer(seq0), 8), ')');
        WriteLn('Assigned seqT: ', Assigned(seqT), '(', IntToHex(Integer(seqT), 8), ')');
        match0 := cvMatchShapes(seq0, seqT, CV_CONTOURS_MATCH_I3);
        if match0 < matchM then
        begin
          matchM := match0;
          seqM := seq0;
        end;
        Inc(counter);
        WriteLn(Format('[i] %d 匹配度: %.2f', [counter, match0]));
        seq0 := seq0.h_next;
      end;
    end;

    // 在原始图像中突出显示最佳匹配的轮廓
    cvDrawContours(rgb, seqM, CV_RGB(52, 201, 36), CV_RGB(36, 201, 197), 0, 2, 8, cvPoint(0, 0));
    cvNamedWindow('查找结果', CV_WINDOW_AUTOSIZE);
    cvShowImage('查找结果', rgb);

    // 等待按键响应
    cvWaitKey(0);

    // 释放内存存储
    cvReleaseMemStorage(storageI);
    cvReleaseMemStorage(storageT);
    cvReleaseImage(src);
    cvReleaseImage(dst);
    cvReleaseImage(rgb);
    cvReleaseImage(rgbT);
    cvReleaseImage(binI);
    cvReleaseImage(binT);

    // 销毁所有窗口
    cvDestroyAllWindows();

    // 释放图像内存
    cvReleaseImage(original);
    cvReleaseImage(template);
    // 销毁所有窗口
    cvDestroyAllWindows();
  except
    on E: Exception do
      WriteLn(E.ClassName, ': ', E.Message);
  end;
end.

Demo2

program cv_MatchShapes2;

{$APPTYPE CONSOLE}
{$R *.res}

uses
  System.SysUtils,
  System.Math,
  ocv.highgui_c,
  ocv.core_c,
  ocv.core.types_c,
  ocv.imgproc_c,
  ocv.imgproc.types_c,
  ocv.utils,
  uResourcePaths;


procedure testMatch(original, templ: pIplImage);
Var
  src, dst: pIplImage;
  binI: pIplImage;
  binT: pIplImage;
  rgb: pIplImage;
  rgbT: pIplImage;

  storageI: pCvMemStorage;
  storageT: pCvMemStorage;
  contoursI: pCvSeq;
  contoursT: pCvSeq;
  contoursCont: Integer;
  font: TCvFont;
  counter: Integer;
  buf: string;
  seq0: pCvSeq;
  seqT: pCvSeq;
  perimT: double;
  perim: double;
  seqM: pCvSeq;
  matchM: double;
  match0: double;

  point: TCvPoint2D32f;
  rad: Float;

begin
  // 断言原始图像和模板图像非空
  assert(original <> nil);
  assert(templ <> nil);

  WriteLn('[i] test cvMatchShapes()\n');

  src := nil;
  dst := nil;

  // 克隆原始图像
  src := cvCloneImage(original);

  // 创建原始图像和模板的二值图像
  binI := cvCreateImage(cvGetSize(src), 8, 1);
  binT := cvCreateImage(cvGetSize(templ), 8, 1);

  // 创建用于显示轮廓的RGB图像
  rgb := cvCreateImage(cvGetSize(original), 8, 3);
  cvConvertImage(src, rgb, CV_GRAY2BGR);
  rgbT := cvCreateImage(cvGetSize(templ), 8, 3);
  cvConvertImage(templ, rgbT, CV_GRAY2BGR);

  // 对原始图像和模板应用Canny边缘检测
  cvCanny(src, binI, 50, 200);
  cvCanny(templ, binT, 50, 200);

  // 创建并显示原始图像的Canny边缘图像窗口
  cvNamedWindow('cannyI', 1);
  cvShowImage('cannyI', binI);

  // 创建并显示模板图像的Canny边缘图像窗口
  cvNamedWindow('cannyT', 1);
  cvShowImage('cannyT', binT);

  // 创建用于存储轮廓的内存存储
  storageI := cvCreateMemStorage(0);
  storageT := cvCreateMemStorage(0);
  contoursI := nil;
  contoursT := nil;

  // 在原始图像中找到轮廓
  contoursCont := cvFindContours(binI, storageI, @contoursI, sizeof(TCvContour), CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE, cvPoint(0, 0));

  // 初始化字体
  cvInitFont(@font, CV_FONT_HERSHEY_PLAIN, 1.0, 1.0);
  counter := 0;

  // 在原始图像上显示轮廓
  if (contoursI <> nil) then
  begin
    seq0 := contoursI;
    while seq0 <> nil do
    begin
      // 绘制轮廓
      cvDrawContours(rgb, seq0, CV_RGB(255, 216, 0), CV_RGB(0, 0, 250), 0, 1, 8, cvPoint(0, 0));
      // 计算并显示最小外接圆
      cvMinEnclosingCircle(seq0, @point, @rad);
      Inc(counter);
      cvPutText(rgb, c_str(IntToStr(counter)), cvPointFrom32f(point), @font, CV_RGB(0, 255, 0));
      seq0 := seq0^.h_next;
    end;
  end;

  // 创建并显示包含轮廓的原始图像窗口
  cvNamedWindow('cont', 1);
  cvShowImage('cont', rgb);

  // 转换回灰度
  cvConvertImage(src, rgb, CV_GRAY2BGR);

  // 在模板图像中找到轮廓
  cvFindContours(binT, storageT, @contoursT, sizeof(TCvContour), CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE, cvPoint(0, 0));

  seqT := nil;
  perimT := 0;

  // 在模板图像上显示轮廓
  if (contoursT <> nil) then
  begin
    seq0 := contoursT;
    while seq0 <> nil do
    begin
      perim := cvContourPerimeter(seq0);
      if (perim > perimT) then
      begin
        perimT := perim;
        seqT := seq0;
      end;
      // 绘制轮廓
      cvDrawContours(rgbT, seq0, CV_RGB(255, 216, 0), CV_RGB(0, 0, 250), 0, 1, 8, cvPoint(0, 0));
      seq0 := seq0^.h_next;
    end;
  end;

  // 在模板图像中突出显示最大的轮廓
  cvDrawContours(rgbT, seqT, CV_RGB(52, 201, 36), CV_RGB(36, 201, 197), 0, 2, 8, cvPoint(0, 0)); // 痂耋屐 觐眚箴
  cvNamedWindow('contT', 1);
  cvShowImage('contT', rgbT);

  seqM := nil;
  matchM := 1000;
  counter := 0;

  // 遍历原始图像中的轮廓
  if (contoursI <> nil) then
  begin
    seq0 := contoursI;
    while seq0 <> nil do
    begin
      // 计算形状匹配度
      match0 := cvMatchShapes(seq0, seqT, CV_CONTOURS_MATCH_I3);
      // 更新最佳匹配的轮廓
      if (match0 < matchM) then
      begin
        matchM := match0;
        seqM := seq0;
      end;
      Inc(counter);
      WriteLn(Format('[i] %d 匹配度: %.2f', [counter, match0]));
      seq0 := seq0^.h_next;
    end;
  end;

  // 在原始图像中突出显示最佳匹配的轮廓
  cvDrawContours(rgb, seqM, CV_RGB(52, 201, 36), CV_RGB(36, 201, 197), 0, 2, 8, cvPoint(0, 0));

  // 创建并显示带有最佳匹配轮廓的图像窗口
  cvNamedWindow('find', 1);
  cvShowImage('find', rgb);

  // 等待按键响应
  cvWaitKey(0);

  // 释放内存
  cvReleaseMemStorage(storageI);
  cvReleaseMemStorage(storageT);
  cvReleaseImage(src);
  cvReleaseImage(dst);
  cvReleaseImage(rgb);
  cvReleaseImage(rgbT);
  cvReleaseImage(binI);
  cvReleaseImage(binT);

  // 销毁窗口
  cvDestroyAllWindows();
end;

const
  const_original = cResourceMedia + 'matchshapes2.jpg';
  const_template = cResourceMedia + 'matchshapes_template.jpg';

Var
  original: pIplImage = nil;
  templ: pIplImage = nil;
  filename, filename2: String;

begin
  try
    // 获取文件名,如果没有提供则使用默认值
    filename := ifthen(ParamCount > 0, ParamStr(1), const_original);
    // 加载原始图像
    original := cvLoadImage(c_str(filename), 0);

    WriteLn('[i] 图像: ', filename);
    assert(Assigned(original));

    // 获取模板文件名,如果没有提供则使用默认值
    filename2 := ifthen(ParamCount > 1, ParamStr(2), const_template);
    // 加载模板图像
    templ := cvLoadImage(c_str(filename2), 0);

    WriteLn('[i] 模板: ', filename2);
    assert(Assigned(templ));

    // 创建并显示原始图像窗口
    cvNamedWindow('original', 1);
    cvShowImage('original', original);
    // 创建并显示模板图像窗口
    cvNamedWindow('template', 1);
    cvShowImage('template', templ);

    // 执行形状匹配测试
    testMatch(original, templ);

    // 释放图像内存
    cvReleaseImage(original);
    cvReleaseImage(templ);

    // 销毁所有窗口
    cvDestroyAllWindows();
  except
    on E: Exception do
      WriteLn(E.ClassName, ': ', E.Message);
  end;
end.
  • 5
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

D-Nolan

请我喝杯咖啡吧,鼓励一下创作!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值