【OpenCV-系列2】09 模板匹配及霍夫变换_对数极坐标模版匹配-程序员宅基地

技术标签: python  OpenCV3  opencv  

  学习目标:
  掌握模板匹配的原理,能完成魔板匹配的应用
  理解霍夫线变换的原理,了解霍夫圆检测
  知道OpenCV如何进行线和圆的检测

在这里插入图片描述

1 模板匹配

1.1 原理

  定义: 在给定的图片中,查找和模板最相似的区域,该算法的输入包括模板和图片,整个任务的思路就是按照滑动窗口的思路不断移动模板图片,计算与图像中对应区域的匹配度,最终将匹配度最高的区域选择为最终的结果。
  实现流程:
  (1)准备两张图像:一张原始图像,一张模板图像
在这里插入图片描述
  (2)滑动模板图像与原图像进行比对:将模板每次移动一个像素(从左往右,从上往下),在每个位置,都计算与模板图像的相似程度。
在这里插入图片描述
  (3)对于每个位置将计算的相似结果保存到矩阵R中,如果输入图像的大小(H×W)且模板图像的大小(w×h),则输出矩阵R的大小为(W-w+1,H-h+1),将R显示为图像为:
在这里插入图片描述
  (4)获取到结果矩阵后,查找最大值所在的位置,那么该位置对应的区域被认为是最匹配的。对应的区域就是以该点为顶点,长宽和模板图像一样大小的矩阵。

1.2 实现

  (1)API: res=cv2.matchTemplate(img,template,method)
  参数:
    img:进行模板匹配的图像
    template:模板
    method:实现模板匹配的算法。主要有:
      1.平方差匹配(CV_TM_SQDIFF):利用模板与图像之间的平方差进行匹配,最好的匹配是0,匹配越差,匹配的值越大。
      2.相关匹配(CV_TM_CCORR):利用模板与图像间的乘法进行匹配,数值越大表示匹配程度越高,越小表示匹配效果差。
      3. 利用相关系数匹配(CV_TM_CCOEFF):利用模板与图像之间的相关系数匹配,1表示匹配完美,1表示匹配最差。
  (2)cv2.minMaxLoc()方法查找最大值所在的位置。 如果使用平方差比较方法,则最小值位置是最佳匹配的位置

import cv2
import matplotlib.pyplot as plt
import numpy as np
#1. 读取图像,灰度形式
img=cv2.imread('template.png',1)#灰度值的方式读取图像
tem=cv2.imread('temp.png',1)
#2.模板匹配
r=cv2.matchTemplate(img,tem,cv2.TM_CCORR)
#3.寻找匹配后的最小值,最大值,及其位置
min_val,max_val,min_loc,max_loc=cv2.minMaxLoc(r)

# 4.寻找最佳匹配位置
top_left=max_loc
h,w=tem.shape[:2]
bottom_right=(top_left[0]+w,top_left[1]+h)

cv2.rectangle(img,top_left,bottom_right,color=(0,255,255))

cv2.imshow('origin',img)

cv2.waitKey(0)

在这里插入图片描述
  注意: 模板匹配不适合用于尺度变换、视角变换后的图像,这时需要用到关键点匹配算法.
   经典的关键点检测算法: 包括SIFT和SURF,主要的思路是首先通过关键点检测算法获取模板和测试图像中的关键点;然后使用关键点匹配算法处理即可,这些关键点可以很好的处理尺度变化、视角变换、旋转变换、光照变换,就有很好的不变性。

2 霍夫线检测

  用于提取直线或者圆形的:
在这里插入图片描述

2.1 原理

2.1.1 笛卡尔空间——>霍夫空间

  在笛卡尔坐标系中,一条直线由两个点A=(x1,y1)和B(x2,y2)确定,如下图所示:
在这里插入图片描述

  将直线y=kx+q可写成关于斜率和截距(k,q)的表达式:
在这里插入图片描述
  通过图形的直观的表示如下:
在这里插入图片描述
  (左为笛卡尔空间,右为霍夫空间)
  笛卡尔坐标系中的一条直线,对应于霍夫空间中的一个点。反过来,霍夫空间中的一个直线,对应于笛卡尔坐标系中的一个点:
在这里插入图片描述

2.1.2 举例

  
  (1)AB两点,对应霍夫空间的情景:(AB两点在霍夫空间中的交点,代表由AB两点构成的直线的斜率和截距)
在这里插入图片描述

  (2)ABC三点,,对应霍夫空间的情景:(ABC三点在霍夫空间中的交点,代表由ABC三点构成的直线的斜率和截距)
在这里插入图片描述
  (3)多个点,可能存在多个直线时:选择尽可能多的直线汇成的点,构成笛卡尔坐标系中的直线
在这里插入图片描述

2.1.3 极坐标空间——>霍夫空间

  笛卡尔空间映射到霍夫空间的问题:
在这里插入图片描述
  上述情况下,霍夫空间中难以确定直线的截距和斜率(k,q),因此考虑将笛卡尔坐标转换为极坐标。
  笛卡尔坐标系和极坐标系:
在这里插入图片描述
  在极坐标系中,极坐标中的点对应霍夫空间中的线,这时霍夫空间是(ρ,θ)的空间,ρ是原点到直线的垂直距离,θ代表直线与横轴顺时针方向的夹角,垂直线的角度为0度,水平线的角度是180度。
在这里插入图片描述

2.2 实现流程

  假设有一个大小为100×100的图片,使用霍夫变换检测图片中的直线,步骤如下:
  (1)直线在霍夫空间中可以使用坐标(ρ,θ)表示,首先创建一个2D数组,我们叫做累加器,初始化所有值为0,行表示ρ,列表示θ
在这里插入图片描述
  该数组的大小决定了结果的准确性,若希望角度的精度为1度,那就需要180列。对于ρ,最大值为图片对角线的距离,如果希望精度达到像素级别,行数应该与图像的对角线的距离相等。
  (2)取直线上的第一个点(x,y),将其带入直线在极坐标中的公式中,然后遍历θ的取值:0、1、2…180,分别求出对应的ρ值,如果这个数字在上述累加器中存在相应的位置,则在该位置上的数值加1。
  (3)取直线上的第二个点,重复上述步骤,更新累加器中的值,对图像中的直线上的每个店都执行以上步骤,每次更新累加器中的值。
  (4)搜索累加器中的最大值,并找到其对应的(ρ,θ),就可以将图像中但是直线表示出来。

2.3 霍夫线检测

  API: cv2.HoughLines(img,rho,theta,threshold)
  参数:
    img:检测的图像,要求是二值化图像,所以在调用霍夫变换之前首先要进行二值化,或者进行Canny边缘检测
    rho、thrta:ρ和θ的精确度
    threshold:阈值,只有累加器中的值高于该阈值时才认为是直线。
在这里插入图片描述

import cv2
import matplotlib.pyplot as plt
import numpy as np

#1. 读取图像,灰度形式
img2=cv2.imread('Hough_line.png')#
img=cv2.cvtColor(img2,cv2.COLOR_BGR2GRAY)#
#2.cannny边缘检测
canny=cv2.Canny(img,50,150)

#3.Hough直线检测,得到ρθ的矩阵
line=cv2.HoughLines(canny,0.8,np.pi/180,150)
print(line)
#4 绘制直线
for i in line:
    rho,theta=i[0]
    a=np.cos(theta)
    b=np.sin(theta)
    x=rho*a
    y=rho*b
    x1=int(x+1000*(-b))
    y1=int(y+1000*a)
    x2=int(x-1000*(-b))
    y2=int(y-1000*a)
    cv2.line(img2,(x1,y1),(x2,y2),(0,255,0))

cv2.imshow('origin',img2)
cv2.imshow('canny',canny)

cv2.waitKey(0)

在这里插入图片描述

3 霍夫圆检测

3.1 原理

  圆的表达式是:
  (x-a)2+(y-b)2=r
  其中a和b表示圆心坐标,r表示圆半径,因此标准的霍夫圆检测就是在这三个参数组成的三维空间累加器上进行圆形检测,此时效率就会很低,所有OpenCV中使用Hough梯度法进行原型检测。
  Huogh梯度法检测圆形流程:
  (1)检测圆心:圆心是圆周法线的交汇处,设置一个阈值,在某点的相交的直线的条数大于这个阈值就认为该交汇点为圆心。
  (2)源半径确定:圆心到圆周上的距离是相同的,确定一个阈值,只要相同的距离的数量大于阈值,就认为该距离是该圆心的半径。
  原则上:霍夫变换可以检测任何形状,但复杂的形状需要的参数很多,霍夫空间的维数就多,因此在程序实现上所需的内存空间以及运行效率上都不利于把标准的霍夫变换应用于复杂图形的检测中。霍夫梯度法是霍夫变换的改进,它的目的是减小霍夫空间的维度,提高效率。

3.2 霍夫圆检测

  API: circle=cv2.HoughCircles(image,method,dp,minDist,param1=100,param2=100,minRadius=0,maxRadius=0)
  参数:
    img:输入图像,应输入灰度图像
    method:使用霍夫变换圆检测的算法,它的参数是CV_HOUGH_GRADIENT
    dp:霍夫空间的分辨率,dp=1时表示霍夫空间与输入图像空间的大小一致,dp=2时霍夫空间是输入图像空间的一般,以此类推
    minDist:为圆心之间的最小距离,如果检测到两个圆心之间的距离小于该阈值,则认为他们是同一个源心
    param1:边缘检测时使用Canny算子的高阈值,低阈值为高阈值的一半
    param2:检测圆心和确定半径时所共有的阈值
    minRadius和maxRadius为所检测到的圆半径的最小值和最大值。

import cv2
import matplotlib.pyplot as plt
import numpy as np

#1. 读取图像,灰度形式
img2=cv2.imread('circle.png')#
img=cv2.cvtColor(img2,cv2.COLOR_BGR2GRAY)
#2.中值滤波
blur=cv2.medianBlur(img,7)

#3.Hough圆检测,
circles=cv2.HoughCircles(blur,cv2.HOUGH_GRADIENT,1,200,param1=100
                      ,param2=50,minRadius=0,maxRadius=100)
print(circles)
#[
# [圆心x,圆心y,半径]
# ...
# ]
#4 绘制直线
for circle in circles[0,:]:
    cv2.circle(img2,(circle[0],circle[1]),
               int(circle[2]),(0,255,0),2)
cv2.imshow('origin',img2)

cv2.waitKey(0)

在这里插入图片描述

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_36926037/article/details/120802071

智能推荐

IDEA 出现问题:报错unable to establish loopback connection解决方案_caused by: java.io.ioexception: unable to establis-程序员宅基地

文章浏览阅读2.4w次。错误信息:Caused by: java.io.IOException: Unable to establish loopback connectionat sun.nio.ch.PipeImpl$Initializer.run(PipeImpl.java:101)at sun.nio.ch.PipeImpl$Initializer.run(PipeImpl.java:68)at java.security.AccessController.解决方案_caused by: java.io.ioexception: unable to establish loopback connection

酒店智能门锁方案功能及其特点介绍_门锁发卡系统用什么语言开发出来的-程序员宅基地

文章浏览阅读1.1k次。世界上自有门锁以来,门锁的变革经历了:机械锁—光孔锁—磁片锁—电子锁—智能感应卡锁,门锁不断地更新换代。进入九十年代后,智能卡锁以其无余伦比的优势创建了门锁新概念。计算机、电子机械和智能卡的诞生,门锁形成了完美的梦幻组合。电子门锁集计算机、电子机械、磁电技术为一体,以智能来控制门锁的开启,即给管理者带来安全、迅捷、自动化的管理模式,也给使用者提供了极大方便。科技以人为本,智能电子门锁的产生,源于人..._门锁发卡系统用什么语言开发出来的

IDEA没有自动检查语法,自动关联报错_idea的自动检查不触发-程序员宅基地

文章浏览阅读4.4k次。1 问题藐视idea没有自动报错.例如随便写一段错误代码,其关联类没有报错;新加一个接口方法其实现类没有实现,没有报错;其实就是没有自动检查语法合法性、2 产生原因2.1 开启了省电模式开启了省电模式,关掉即可。2.2 没有开启自动编译项目 2.3 inspection功能故障单击右下角小人头,检查高亮等级是否在none(没有)上,移到Inspections.以上三个问题检查一遍,基本可以解决问题。..._idea的自动检查不触发

mysql修改字段名称脚本_mysql数据库修改字段及新增字段脚本-程序员宅基地

文章浏览阅读1.3k次。1.修改字段的长度ALTER TABLE MODIFY COLUMN 字段名 数据类型(修改后的长度)例句:ALTER TABLE test_table MODIFY COLUMN id INT(20)2.修改字段的名称alter table change 。例句:ALTER TABLE test_tableCHANGE attence_name NAME VARCHAR(20)3...._mysql 修改字段脚本

黑马程序员学习日记(4)--继承、多态-程序员宅基地

文章浏览阅读466次。---------------------- ASP.Net+Android+IO开发S、.Net培训、期待与您交流! -----------------------继承:用法。。父类派生子类;子类可以用父类的所有属性方法,还可以有自己的方法属性。子类除了不能继承父类的构造函数和析构函数外,可以继承父类所有的成员和方法。子类不能直接修改父类的私有成员,只能通过父类的公有方法对其

1028: C语言程序设计教程(第三版)课后习题8.2-程序员宅基地

文章浏览阅读675次。题目描述求方程 的根,用三个函数分别求当b^2-4ac大于0、等于0、和小于0时的根,并输出结果。从主函数输入a、b、c的值。输入a b c输出x1=? x2=?样例输入4 1 1样例输出x1=-0.125+0.484i x2=-0.125-0.484i 1 #include <stdio.h> 2 #include <math.h..._1028:c语言程序设计教程(第三版)课后习题8.2

随便推点

Qt学习之《C++ GUI Qt4编程》(第14章)多线程互斥量使用错误_qt使用互斥锁编译出错-程序员宅基地

文章浏览阅读408次。虽然一直使用VC,但很久之前有使用过Qt写过一些小工具,但没有完整看过Qt一些相关书籍,最近看书发现《C++ GUI Qt4编程》(第14章)多线程互斥量使用好像有问题。 《C++ GUI Qt4编程》(第14章)14.2 这一节将QMutex定义在了 Thread 类下,编译调试书本中的例子,发现使用QMutex Lock()方法会报错: The infer_qt使用互斥锁编译出错

源码解读腾讯 GT 的性能测试方案_service call surfaceflinger-程序员宅基地

文章浏览阅读4.5k次,点赞2次,收藏6次。前言本文将整理腾讯GT各个性能测试项的测试方法,目的是为了帮助移动性能专项测试同学快速过一遍腾讯GT各个性能数据是如何获取的。 一.GT性能测试方案之CPU测试1.简要流程 初始化cpu的数据 提供了两种方法获取CPU数据 getCpuUsage: 整机的CPU使用水平,主要用于实时刷新GT上的CPU数据。通过读取/proc/stat的数据,将每一个核的cpu使用跟闲..._service call surfaceflinger

PHP - 垃圾回收机制收集_gc_collect_cycles 是分进程吗-程序员宅基地

文章浏览阅读3.9k次。了解学习PHP[内存]垃圾回收机制, 帮助理解编程语言的运行机制, 提高开发水平._gc_collect_cycles 是分进程吗

Matlab 绘制两端带尖角(两端尖尖,尖色头条)的colorbar_matlab画图例带尖角-程序员宅基地

文章浏览阅读4.6k次,点赞6次,收藏22次。其实这样的colorbar可以直接手动画出来,不多说,直接上代码cmap = [69 117 180 116 173 203 171 217 233 254 224 144 253 174 77 244 109 67 215 48 39 165 0 38]/255;%画图的部分代码colormap(ax,cmap);xmin = -1..._matlab画图例带尖角

pb与java_Java中使用PB教程-程序员宅基地

文章浏览阅读1.6k次。前言之前在写Netty的时候,说过要写一篇关于PB的应用,所以现在兑现承诺。在应用的过程中,发现了很多问题,本文主要介绍两个最关键的问题。PB如何与java项目融合,自动刷新编译,以及pb文件如何与其他项目共用,互不影响。java中如何实现pb的Extension概述ProtocolBuff 是 google 提出的的一种数据交换格式,跨语言,跨平台,可扩展。基于这种特性广泛的用于网络数据通信。目..._java开发pb接口

线程的同步_package com.atguigu.java1; //死锁的演示 class a { publi-程序员宅基地

文章浏览阅读230次。线程的同步1.背景2.同步代码块和同步方法package com.atguigu.java;/** * 例子:创建三个窗口卖票,总票数为100张.使用实现Runnable接口的方式 * * 1.问题:卖票过程中,出现了重票、错票 -->出现了线程的安全问题 * 2.问题出现的原因:当某个线程操作车票的过程中,尚未操作完成时,其他线程参与进来,也操作车票。 * 3.如何解决:当一个线程a在操作ticket的时候,其他线程不能参与进来。直到线程a操作完ticket时,其他_package com.atguigu.java1; //死锁的演示 class a { public synchronized void