目录

1 什么是霍夫变换

1.1 应用霍夫变换以检测图像中的线条

1.2 累加器

1.3 线条检测

1.4 圆环的检测

2 代码

3 参考


1 什么是霍夫变换

霍夫变换是用于检测图像中的简单形状(诸如圆形,线条等)的特征提取方法。“简单”形状是可以仅由几个参数表示的形状。例如,一条线可以用两个参数(斜率,截距)表示,一个圆有三个参数:中心坐标和半径(x,y,r)。霍夫变换在图像中找到这样的形状方面做得很好。使用Hough变换的主要优点是它对遮挡不敏感。让我们通过一个例子来看看霍夫变换是如何工作的。

1.1 应用霍夫变换以检测图像中的线条

极坐标中的线条方程如下:

这里表示线与原点的垂直距离(以像素为单位),是以弧度为单位测量的角度,如下图所示。

您可能会想问我们为什么不使用下面给出的熟悉的等式:

原因是斜率m可以取-到+之间的值。对于Hough变换,参数需要有界限。您可能还有一个后续问题。在形式上,是有界的,但是能取0到+之间的值吗?这在理论上可能是正确的,但在实践中,也是有限的,因为图像本身是有限的。

1.2 累加器

当我们说二维空间中的一条线用参数化表达时,意味着如果我们选择一个,它就对应一条线。想象一个二维数组, 想象一个二维数组,其中x轴具有所有可能的值,y轴具有所有可能的值。该2D阵列中的任何点坐标对应于一条线。

这个2D数组称为累加器,因为我们将使用此数组的bin来收集有关图像中存在哪些线条的信息。左上角的单元格对应于(-R,0),右下角对应于(R,)。稍后我们将看到bin()内的值随着参数而改变。

1.3 线条检测

执行以下步骤以检测图像中的线。

(1) 首先,我们需要创建一个累加器数组。您选择的单元格数量是一个设计决策。假设您选择了10×10累加器。这意味着获取10个不同的值。因此您将能够检测100种完全不同的线条。累加器的大小也取决于图像的分辨率。但如果你刚刚开始,不要担心完全正确。选择一个20×20的数字,看看你得到了什么结果。

(2) 检测边缘

现在我们已经设置了累加器,我们希望收集累加器的每个单元的信息,因为累加器的每个单元对应于一行。我们如何通过获取单元的信息,如果图像中有一条可见的线,边缘检测器应该在这条线的边界检测到边缘像素点。这些边缘像素为线条的存在提供了证据。边缘检测的输出是边缘像素的阵列 

(3) 边缘像素投票

对于上述数组中的每个边缘像素(x,y),我们改变从0到的值,并根据线条极坐标公式计算。我们改变三个像素点的(由三条彩色曲线表示),并获得对应的值。如下图所示。下图中三条线代表三个像素点不同的取值,其中横坐标为值,纵坐标为值(r值)。如果三个点在一条直线上,那么三个点的曲线就会相交于一点。

通常,我们有数百个边缘像素,越多的曲线交于一点就意味着这个交点表示的直线由更多的点组成,通过累加器统计交于一点的曲线数,并设定阈值来决定是否检测到一条直线。

更多霍夫曼变换说明见:

https://blog.csdn.net/u013263891/article/details/82867251

在OpenCV中,使用Hough变换的线检测在函数HoughLines和HoughLinesP中实现。此函数采用以下参数:

  • edge:边缘检测器的输出(灰度图)。
  • lines:用于存储行开头和结尾坐标的向量。
  • rho:图像单位分辨率参数,以像素为单位。我们选择2像素点
  • theta以弧度表示的参数单位分辨率。我们选择2度
  • 阈值:检测线的最小交叉点数。

下面我们展示了使用霍夫变换进行线检测的结果。请记住,检测到的线条的质量在很大程度上取决于边缘图的质量。因此,在现实世界中,当您可以控制环境并因此获得一致的边缘图时,或者当您可以为您正在寻找的特定类型的边缘训练边缘检测器时,使用Hough变换。

1.4 圆环的检测

在线Hough变换的情况下,我们需要两个参数,()但是为了检测圆,我们需要三个参数

  • 圆心的坐标。
  • 半径。

可以想象,圆形探测器需要一个3D累加器,每个参数一个。

圆的方程由下式给出:

按照以下步骤检测图像中的圆圈:

1.借助边缘检测器(Canny)找到给定图像中的边缘。

2.为了检测图像中的圆,我们设置半径的最大值和最小值的阈值。

3.信息收集在3D累加器阵列中,以确定是否存在具有不同中心和半径的圆。

在OpenCV中使用HoughCircles函数来检测图像中的圆圈。它需要以下参数:

image:输入图像。

methods:检测方法。

dp:累加器分辨率和图像分辨率的反比。

mindst:检测到圆圈的中心之间的最小距离。

param_1和param_2:这些是特定于方法的参数。

min_Radius:要检测的圆的最小半径(以像素为单位)。

max_Radius:要检测的最大半径(以像素为单位)。

使用Hough变换的圆检测结果如下所示。结果的质量在很大程度上取决于您可以找到的边缘质量,以及您对要检测的圆的大小有多少先验知识。

2 代码

所有代码见:

https://github.com/luohenyueji/OpenCV-Practical-Exercise

线条检测:

C++:

#include "pch.h"
#include <opencv2/opencv.hpp>
#include <stdio.h>
#include <iostream> using namespace cv;
using namespace std; // variables to store images
Mat dst, cimg, gray, img, edges; int initThresh;
const int maxThresh = 1000;
double th1, th2; // create a vector to store points of line
vector<Vec4i> lines; void onTrackbarChange(int, void*)
{
//复制目标图像
cimg = img.clone();
//结果图像
dst = img.clone(); th1 = initThresh;
th2 = th1 * 0.4;
//canny边缘检测
Canny(img, edges, th1, th2); // apply hough line transform 霍夫曼变换
HoughLinesP(edges, lines, 2, CV_PI / 180, 50, 10, 100); // draw lines on the detected points 画线
for (size_t i = 0; i < lines.size(); i++)
{
//提取线条坐标点
Vec4i l = lines[i];
line(dst, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(0, 0, 255), 1, LINE_AA);
} // show the resultant image
imshow("Result Image", dst);
imshow("Edges", edges);
} int main()
{
// Read image (color mode) 读图
img = imread("./image/lanes.jpg", 1);
dst = img.clone(); if (img.empty())
{
cout << "Error in reading image" << endl;
return -1;
} // Convert to gray-scale 转换为灰度图像
cvtColor(img, gray, COLOR_BGR2GRAY); // Detect edges using Canny Edge Detector
// Canny(gray, dst, 50, 200, 3); // Make a copy of original image
// cimg = img.clone(); // Will hold the results of the detection
namedWindow("Edges", 1);
namedWindow("Result Image", 1); // Declare thresh to vary the max_radius of circles to be detected in hough transform
// 霍夫曼变换阈值
initThresh = 500; // Create trackbar to change threshold values
//滑动条
createTrackbar("threshold", "Result Image", &initThresh, maxThresh, onTrackbarChange);
onTrackbarChange(initThresh, 0); while (true)
{
int key;
key = waitKey(1);
if ((char)key == 27)
{
break;
}
}
destroyAllWindows();
return 0;
}

Python:

import cv2
import numpy as np def onTrackbarChange(max_slider):
global img
global dst
global gray dst = np.copy(img) th1 = max_slider
th2 = th1 * 0.4
edges = cv2.Canny(img, th1, th2) # Apply probabilistic hough line transform
lines = cv2.HoughLinesP(edges, 2, np.pi/180.0, 50, minLineLength=10, maxLineGap=100) # Draw lines on the detected points
for line in lines:
x1, y1, x2, y2 = line[0]
cv2.line(dst, (x1, y1), (x2, y2), (0,0,255), 1) cv2.imshow("Result Image", dst)
cv2.imshow("Edges",edges) if __name__ == "__main__": # Read image
img = cv2.imread('./image/lanes.jpg') # Create a copy for later usage
dst = np.copy(img) # Convert image to gray
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # Create display windows
cv2.namedWindow("Edges")
cv2.namedWindow("Result Image") # Initialize threshold value
initThresh = 500 # Maximum threshold value
maxThresh = 1000 cv2.createTrackbar("threshold", "Result Image", initThresh, maxThresh, onTrackbarChange)
onTrackbarChange(initThresh) while True:
key = cv2.waitKey(1)
if key == 27:
break cv2.destroyAllWindows()

圆环检测:

C++:

#include "pch.h"
#include <opencv2/opencv.hpp>
#include <stdio.h>
#include <iostream>
#include <string> using namespace cv;
using namespace std; // Declare variables to store images
Mat gray, cimg, img, edges; int initThresh;
const int maxThresh = 200;
double p1, p2; // Vector to store circle points
vector<Vec3f> circles; void onTrackbarChange(int, void*)
{
cimg = img.clone(); p1 = initThresh;
p2 = initThresh * 0.4; // Detect circles using HoughCircles transform 霍夫曼变换
HoughCircles(gray, circles, HOUGH_GRADIENT, 1, cimg.rows / 64, p1, p2, 25, 50); //画圆
for (size_t i = 0; i < circles.size(); i++)
{
Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));
int radius = cvRound(circles[i][2]);
// Draw the outer circle
circle(cimg, center, radius, Scalar(0, 255, 0), 2);
// Draw the center of the circle
circle(cimg, center, 2, Scalar(0, 0, 255), 3);
} // Display output image
imshow("Image", cimg); // Edge image for debugging
Canny(gray, edges, p1, p2);
imshow("Edges", edges);
} int main()
{
//读图
img = imread("./image/brown-eyes.jpg", IMREAD_COLOR); if (img.empty())
{
cout << "Error reading image" << endl;
return -1;
} // Convert to gray-scale 转换为灰度图
cvtColor(img, gray, COLOR_BGR2GRAY); // Will hold the results of the detection
namedWindow("Edges", 1);
namedWindow("Image", 1); //初始阈值
initThresh = 105;
//滑动条
createTrackbar("Threshold", "Image", &initThresh, maxThresh, onTrackbarChange);
onTrackbarChange(initThresh, 0); imshow("Image", img);
while (true)
{
int key;
key = waitKey(0);
if ((char)key == 27)
{
break;
}
} destroyAllWindows();
return 0;
}

Python:

import cv2
import numpy as np
import sys def onTrackbarChange(max_slider):
cimg = np.copy(img) p1 = max_slider
p2 = max_slider * 0.4 # Detect circles using HoughCircles transform
circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, 1, cimg.shape[0]/64, param1=p1, param2=p2, minRadius=25, maxRadius=50) # If at least 1 circle is detected
if circles is not None:
cir_len = circles.shape[1] # store length of circles found
circles = np.uint16(np.around(circles))
for i in circles[0, :]:
# Draw the outer circle
cv2.circle(cimg, (i[0], i[1]), i[2], (0, 255, 0), 2)
# Draw the center of the circle
cv2.circle(cimg, (i[0], i[1]), 2, (0, 0, 255), 3)
else:
cir_len = 0 # no circles detected # Display output image
cv2.imshow('Image', cimg) # Edge image for debugging
edges = cv2.Canny(gray, p1, p2)
cv2.imshow('Edges', edges) if __name__ == "__main__":
# Read image
img = cv2.imread("./image/brown-eyes.jpg") # Convert to gray-scale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # Create display windows
cv2.namedWindow("Edges")
cv2.namedWindow("Image") # Trackbar will be used for changing threshold for edge
initThresh = 105
maxThresh = 200 # Create trackbar
cv2.createTrackbar("Threshold", "Image", initThresh, maxThresh, onTrackbarChange)
onTrackbarChange(initThresh) while True:
key = cv2.waitKey(1)
if key == 27:
break cv2.destroyAllWindows()

3 参考

https://www.learnopencv.com/hough-transform-with-opencv-c-python/

https://blog.csdn.net/u013263891/article/details/82867251

[OpenCV实战]33 使用OpenCV进行Hough变换的更多相关文章

  1. [OpenCV实战]51 基于OpenCV实现图像极坐标变换与逆变换

    在图像处理领域中,经常通过极坐标与笛卡尔直角坐标的互转来实现图像中圆形转为方形,或者通过极坐标反变换实现方形转圆形.例如钟表的表盘,人眼虹膜,医学血管断层都需要用到极坐标变换来实现圆转方. 文章目录 ...

  2. [OpenCV实战]46 在OpenCV下应用图像强度变换实现图像对比度均衡

    本文主要介绍基于图像强度变换算法来实现图像对比度均衡.通过图像对比度均衡能够抑制图像中的无效信息,使图像转换为更符合计算机或人处理分析的形式,以提高图像的视觉价值和使用价值.本文主要通过OpenCV ...

  3. [OpenCV实战]50 用OpenCV制作低成本立体相机

    本文主要讲述利用OpenCV制作低成本立体相机以及如何使用OpenCV创建3D视频,准确来说是模仿双目立体相机,我们通常说立体相机一般是指双目立体相机,就是带两个摄像头的那种(目就是指眼睛,双目就是两 ...

  4. [OpenCV实战]48 基于OpenCV实现图像质量评价

    本文主要介绍基于OpenCV contrib中的quality模块实现图像质量评价.图像质量评估Image Quality Analysis简称IQA,主要通过数学度量方法来评价图像质量的好坏. 本文 ...

  5. [OpenCV实战]45 基于OpenCV实现图像哈希算法

    目前有许多算法来衡量两幅图像的相似性,本文主要介绍在工程领域最常用的图像相似性算法评价算法:图像哈希算法(img hash).图像哈希算法通过获取图像的哈希值并比较两幅图像的哈希值的汉明距离来衡量两幅 ...

  6. [OpenCV实战]47 基于OpenCV实现视觉显著性检测

    人类具有一种视觉注意机制,即当面对一个场景时,会选择性地忽略不感兴趣的区域,聚焦于感兴趣的区域.这些感兴趣的区域称为显著性区域.视觉显著性检测(Visual Saliency Detection,VS ...

  7. [OpenCV实战]44 使用OpenCV进行图像超分放大

    图像超分辨率(Image Super Resolution)是指从低分辨率图像或图像序列得到高分辨率图像.图像超分辨率是计算机视觉领域中一个非常重要的研究问题,广泛应用于医学图像分析.生物识别.视频监 ...

  8. [OpenCV实战]19 使用OpenCV实现基于特征的图像对齐

    目录 1 背景 1.1 什么是图像对齐或图像对准? 1.2 图像对齐的应用 1.3 图像对齐基础理论 1.4 如何找到对应点 2 OpenCV的图像对齐 2.1 基于特征的图像对齐的步骤 2.2 代码 ...

  9. [OpenCV实战]20 使用OpenCV实现基于增强相关系数最大化的图像对齐

    目录 1 背景 1.1 彩色摄影的一个简短而不完整的历史 1.2 OpenCV中的运动模型 2 使用增强相关系数最大化(ECC)的图像对齐 2.1 findTransformECC在OpenCV中的示 ...

随机推荐

  1. NLP之基于TextCNN的文本情感分类

    TextCNN @ 目录 TextCNN 1.理论 1.1 基础概念 最大汇聚(池化)层: 1.2 textCNN模型结构 2.实验 2.1 实验步骤 2.2 算法模型 1.理论 1.1 基础概念 在 ...

  2. 8.gitlab服务器搭建(基于centos7)

    gitlab服务硬件要求 建议服务器最低配置:2核 2G以上内存(不包含2GB,2GB内存运行的时候内存直接爆掉) 官网给出的推荐配置:4核 4GB内存 支持500个用户,8核 8GB内存 支持100 ...

  3. awk模式pattern

    awk模式pattern 再来回顾下awk的语法 awk [option] 'pattern[action]' file ... awk是按行处理文本,刚才讲解了print动作,现在讲解特殊的patt ...

  4. Debian 参考手册之第6章Debian档案库

    来源:https://www.debian.org/doc/manuals/debian-faq/ftparchives#oldcodenames 第 6 章 Debian 档案库 目录 6.1. 有 ...

  5. VB6查看桌面分辨率和工作区大小 2022.08.22 name.vt

    VB6查看桌面分辨率和工作区大小 2022.08.22 name.vt Form1 内代码如下: ' 2022年8月22日 15时15分 ' 作者:name.vt Private Sub cmdCle ...

  6. apijson 初探

    apijson 初探 本文试着用 5W1H 方式切入,试图快速建立自己对 apijson 的整体认知,所以这不是一趟快速入门的 demo 之旅,而是显得比较务虚的探索式知识体系整合过程. 持续更新中. ...

  7. 3.JS

    1.简介 JavaScript 因为互联网而生,紧随着浏览器的出现而问世 1997年7月,ECMAScript 1.0发布. 1998年6月,ECMAScript 2.0版发布. 1999年12月,E ...

  8. perl中ENV的使用

    在打印环境变量的时候可以用到.实际上是%ENV,perl中的哈希变量,里面保存的是环境变量.键是环境变量名,值是环境变量值.例如,有一个环境变量是PATH,其值为C:\windows,那么,打印这个环 ...

  9. SpringCloud——Eureka Feign Ribbon Hystrix Zuul等关键组件的学习与记录

    SpringCloud--Eureka Feign Ribbon Hystrix Zuul等关键组件的学习与记录 前言:本篇是对近日学习狂神SpringCloud教程之后的感想和总结,鉴于对Sprin ...

  10. windows安装wsl,在windows中使用ubuntu

    WSL(Windows Subsystem for Linux)即适用于 Linux 的 Windows 子系统,它是随 Windows 操作系统一起提供. WSL是windows操作系统的子系统,算 ...