终于鼓起勇气看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];
};