opencv霍夫变换源码及注释

终于鼓起勇气看hough变换源码了,  之前自己还瞎写了一个检测椭圆中心的 =_=!  不过还好大致一样

static void

HoughLinesStandard( const Mat& img, float rho, float theta,

int threshold, std::vector<Vec2f>& lines, int linesMax,

double min_theta, double max_theta )

{

int i, j;

float irho = 1 / rho;

CV_Assert( img.type() == CV_8UC1 );        //检测输入的是否为 单通道 8-bit图像

const uchar* image = img.ptr();                   //读取img

int step = (int)img.step;

int width = img.cols;

int height = img.rows;

if (max_theta < min_theta ) {                                                                    //check if   max_theta > min_theta

CV_Error( CV_StsBadArg, "max_theta must be greater than min_theta" );

}

int numangle = cvRound((max_theta - min_theta) / theta);                    //对于angle提供多少个‘格子‘

int numrho = cvRound(((width + height) * 2 + 1) / rho);                          //对于 rho   提供多少个‘格子‘

//至于(width + height) * 2 + 1)我不太理解,数学上最少格子数吧

//theta --Angle resolution of the accumulator in radians.

//rho   --Distance resolution of the accumulator in pixels

AutoBuffer<int> _accum((numangle+2) * (numrho+2));                          //关于AutoBuffer请看最下面

//(numangle+2) * (numrho+2)   行*列

std::vector<int> _sort_buf;                                                                    //为后面排序的

AutoBuffer<float> _tabSin(numangle);

AutoBuffer<float> _tabCos(numangle);

int *accum = _accum;

float *tabSin = _tabSin, *tabCos = _tabCos;                                         //创建sin  cos 表

memset( accum, 0, sizeof(accum[0]) * (numangle+2) * (numrho+2) );      //分配内存?  并置零

float ang = static_cast<float>(min_theta);                                  // min_theta转成float 并赋值给ang

for(int n = 0; n < numangle; ang += theta, n++ )                        //初始化sin , cos 表

{

tabSin[n] = (float)(sin((double)ang) * irho);

tabCos[n] = (float)(cos((double)ang) * irho);

}

// stage 1. fill accumulator

for( i = 0; i < height; i++ )

for( j = 0; j < width; j++ )

{

if( image[i * step + j] != 0 )                                                      //当某像素值不为0时

for(int n = 0; n < numangle; n++ )

{

int r = cvRound( j * tabCos[n] + i * tabSin[n] );              //  ρ = x cos θ + y sin θ

r += (numrho - 1) / 2;                                                    //哈哈,这里让我想了好久

//  为什么这样安排呢?  可能是因为θ、ρ正负问题

accum[(n+1) * (numrho+2) + r+1]++;                         //对应的accumulator    +1

// n+1是为了第一行空出来

//numrho+2 是总共的列数

// r+1 是为了把第一列空出来

}                                                           //因为程序后面要比较前一行与前一列的数据,  这样省的越界

}                                                                  //因此空出首行和首列

// stage 2. find local maximums

for(int r = 0; r < numrho; r++ )

for(int n = 0; n < numangle; n++ )                                         //与theta对应的n

{

int base = (n+1) * (numrho+2) + r+1;                                //(n+1) * (numrho+2) + r+1  同前

if( accum[base] > threshold &&

accum[base] > accum[base - 1] &&

accum[base] >= accum[base + 1] &&

accum[base] > accum[base - numrho - 2] &&

accum[base] >= accum[base + numrho + 2] )

_sort_buf.push_back(base);

}

// stage 3. sort the detected lines by accumulator value

std::sort(_sort_buf.begin(), _sort_buf.end(), hough_cmp_gt(accum));

// stage 4. store the first min(total,linesMax) lines to the output buffer

linesMax = std::min(linesMax, (int)_sort_buf.size());

double scale = 1./(numrho+2);

for( i = 0; i < linesMax; i++ )

{

LinePolar line;

int idx = _sort_buf[i];                                                  //   第i个line对应的base,

//也就是对应accumulator的位置

int n = cvFloor(idx*scale) - 1;                               //(numangle+2) * (numrho+2)  行*列

//对应numangle +1

int r = idx - (n+1)*(numrho+2) - 1;                        // r
= idx - (n+1)*(numrho+2) - 1  同前

line.rho = (r - (numrho - 1)*0.5f) * rho;                            //ρ

line.angle = static_cast<float>(min_theta) + n * theta;   // θ

lines.push_back(Vec2f(line.rho, line.angle));

}

}

至此,  应该算是完整的注释了,  如果有什么错误欢迎留言  

/** @brief  Automatically Allocated Buffer Class

The class is used for temporary buffers in functions and methods.

If a temporary buffer is usually small (a few K‘s of memory),

but its size depends on the parameters, it makes sense to create a small

fixed-size array on stack and use it if it‘s large enough. If the required buffer size

is larger than the fixed size, another buffer of sufficient size is allocated dynamically

and released after the processing. Therefore, in typical cases, when the buffer size is small,

there is no overhead associated with malloc()/free().

At the same time, there is no limit on the size of processed data.

This is what AutoBuffer does. The template takes 2 parameters - type of the buffer elements and

the number of stack-allocated elements. Here is how the class is used:

\code

void my_func(const cv::Mat& m)

{

cv::AutoBuffer<float> buf; // create automatic buffer containing 1000 floats

buf.allocate(m.rows); // if m.rows <= 1000, the pre-allocated buffer is used,

// otherwise the buffer of "m.rows" floats will be allocated

// dynamically and deallocated in cv::AutoBuffer destructor

...

}

\endcode

*/

template<typename _Tp, size_t fixed_size = 1024/sizeof(_Tp)+8> class AutoBuffer

{

public:

typedef _Tp value_type;

//! the default constructor

AutoBuffer();

//! constructor taking the real buffer size

AutoBuffer(size_t _size);

//! the copy constructor

AutoBuffer(const AutoBuffer<_Tp, fixed_size>& buf);

//! the assignment operator

AutoBuffer<_Tp, fixed_size>& operator = (const AutoBuffer<_Tp, fixed_size>& buf);

//! destructor. calls deallocate()

~AutoBuffer();

//! allocates the new buffer of size _size. if the _size is small enough, stack-allocated buffer is used

void allocate(size_t _size);

//! deallocates the buffer if it was dynamically allocated

void deallocate();

//! resizes the buffer and preserves the content

void resize(size_t _size);

//! returns the current buffer size

size_t size() const;

//! returns pointer to the real buffer, stack-allocated or head-allocated

operator _Tp* ();

//! returns read-only pointer to the real buffer, stack-allocated or head-allocated

operator const _Tp* () const;

protected:

//! pointer to the real buffer, can point to buf if the buffer is small enough

_Tp* ptr;

//! size of the real buffer

size_t sz;

//! pre-allocated buffer. At least 1 element to confirm C++ standard reqirements

_Tp buf[(fixed_size > 0) ? fixed_size : 1];

};

时间: 2024-10-02 01:08:16

opencv霍夫变换源码及注释的相关文章

能把opencv的源码也进行调试吗?(需要pdb文件才行)

能把opencv的源码也进行调试吗?(需要pdb文件才行)1.我是用的Qt Creator,然后"工具\选项\调试器\概要\源码路径映射"中,选择"添加Qt源码",目标路径是Qt的源码路径,比如是"C:\Qt\Qt5.7.0\5.7\Src", 源路径是Qt Creator自动补充的.2.按照这种方法也可以将VC CRT源码给添加进来,目标路径是VC CRT的源码路径,比如是"C:\Program Files (x86)\Microso

Bootstrap的Model源码详细注释

工作中用到了Bootstrap的Model这个插件,想封装下,然后看了下源码不多,于是读了下源码并注释了下. 后端狗,前端不熟,注释的不好,请务必指出. /* ========================================================================  * Bootstrap: modal.js v3.2.0  * http://getbootstrap.com/javascript/#modals  * ==================

OpenCV Canny 源码注释与分析

1986年,John F.Canny 完善了边缘检测理论,Canny算法以此命名. Canny 算法的步骤: 1. 使用滤波器卷积降噪 2. 使用Sobel导数计算梯度幅值和方向 3. 非极大值抑制 + 滞后阈值 在正式处理前,用高斯滤平滑波器对图像做滤波降噪的操作,避免噪声点的干扰,但在OpenCV的canny源码中,没有进行高斯滤波,需要使用者自行滤波:有些资料将非极大值抑制和滞后阈值视为两个步骤也是可行的,但是在源码中非极大值抑制 和滞后阈值是同时进行的. canny源码的位置:\open

实验报告: 人脸识别方法回顾与实验分析 【OpenCV测试方法源码】

趁着还未工作,先把过去做的东西整理下出来~   Github源码:https://github.com/Blz-Galaxy/OpenCV-Face-Recognition (涉及个人隐私,源码不包含测试样本,请谅解~) 对实验结果更感兴趣的朋友请直接看 第5章 [摘要]这是一篇关于人脸识别方法的实验报告.报告首先回顾了人脸识别研究的发展历程及基本分类:随后对人脸识别技术方法发展过程中一些经典的流行的方法进行了详细的阐述:最后作者通过设计实验对比了三种方法的识别效果并总结了人脸识别所面临的困难与

Canny,先Scharr得梯度再Canny,三通道黑色背景展示结果(OpenCV案例源码edge.cpp)

有所更改,参数不求完备,但求实用.源码参考D:\source\opencv-3.4.9\samples\cpp\edge.cpp #include<opencv2\opencv.hpp> #include<iostream> using namespace cv; using namespace std; int edgeThresh = 1; int edgeThreshScharr = 1; Mat image, gray, blurImage, edge1, edge2, c

HOG+SVM(OpenCV案例源码train_HOG.cpp解读)

有所更改,参数不求完备,但求实用.源码参考D:\source\opencv-3.4.9\samples\cpp\train_HOG.cpp [解读参考]https://blog.csdn.net/xiao__run/article/details/82902267 [HOG原理]https://livezingy.com/hogdescriptor-in-opencv3-1/ https://cloud.tencent.com/developer/article/1434949 #include

Nginx 源码完全注释(11)ngx_spinlock

Nginx 是多进程模式的,一个 master 与多个 workers,一般工作在多核 CPU 上,所以自旋锁就是必须用到的.Nginx 中的自旋锁的定义,位于 ngx_spinlock.c 中,如下: void ngx_spinlock(ngx_atomic_t *lock, ngx_atomic_int_t value, ngx_uint_t spin) { #if (NGX_HAVE_ATOMIC_OPS) ngx_uint_t i, n; for ( ;; ) { // lock 即为锁

Nginx源码完全注释(6)core/murmurhash

下面是摘自 Google Code 的 Murmurhash 开源项目主页上的 Murmurhash2,Nginx 就是采用的这个. uint32_t MurmurHash2 ( const void * key, int len, uint32_t seed ) { // 'm' and 'r' are mixing constants generated offline. // They're not really 'magic', they just happen to work well

Nginx 源码完全注释(10)ngx_radix_tree

ngx_radix_tree.h // 未被使用的节点 #define NGX_RADIX_NO_VALUE (uintptr_t) -1 typedef struct ngx_radix_node_s ngx_radix_node_t; struct ngx_radix_node_s { ngx_radix_node_t *right; // 右子树的根节点 ngx_radix_node_t *left; // 左子树的根节点 ngx_radix_node_t *parent; // 父节点