霍夫变换C#代码
Hough Transform C# code
让我们来看看this C# implementation,
... ...
// get source image size
int width = image.Width;
int height = image.Height;
int halfWidth = width / 2;
int halfHeight = height / 2;
// make sure the specified rectangle recides with the source image
rect.Intersect( new Rectangle( 0, 0, width, height ) );
int startX = -halfWidth + rect.Left;
int startY = -halfHeight + rect.Top;
int stopX = width - halfWidth - ( width - rect.Right );
int stopY = height - halfHeight - ( height - rect.Bottom );
int offset = image.Stride - rect.Width;
// calculate Hough map's width
int halfHoughWidth = (int) Math.Sqrt( halfWidth * halfWidth + halfHeight * halfHeight );
int houghWidth = halfHoughWidth * 2;
houghMap = new short[houghHeight, houghWidth];
// do the job
unsafe
{
byte* src = (byte*) image.ImageData.ToPointer( ) +
rect.Top * image.Stride + rect.Left;
// for each row
for ( int y = startY; y < stopY; y++ )
{
// for each pixel
for ( int x = startX; x < stopX; x++, src++ )
{
if ( *src != 0 )
{
// for each Theta value
for ( int theta = 0; theta < houghHeight; theta++ )
{
int radius = (int) Math.Round( cosMap[theta] * x - sinMap[theta] * y ) + halfHoughWidth;
if ( ( radius < 0 ) || ( radius >= houghWidth ) )
continue;
houghMap[theta, radius]++;
}
}
}
src += offset;
}
}
... ... ...
Q.1. rect.Intersect(new Rectangle( 0, 0, width, height));
- 为什么这条线很重要?
Q.2. 为什么在下面的代码中使用rect
修改值:
int startX = -halfWidth + rect.Left;
int startY = -halfHeight + rect.Top;
int stopX = width - halfWidth - ( width - rect.Right );
int stopY = height - halfHeight - ( height - rect.Bottom );
Q.3. 为什么 y 和 x 循环从负点开始?
问题 1.
此行只是确保边界矩形完全位于图像内部。如果您要跳过此步骤,并且 rect
(部分)在图像之外,您最终会超出索引范围。
请注意,像素访问是通过指针完成的,每次 x 增量时指针递增 1,每 y 增量递增 offset
。如果 rect
比图像大,我们将递增指针使其越过图像缓冲区。如果 rect
只是移出图像边界,但不是太大,我们会读取与我们使用的坐标不对应的像素。
问题 2.
注意
int stopX = width - halfWidth - ( width - rect.Right );
int stopY = height - halfHeight - ( height - rect.Bottom );
可以简化为
int stopX = - halfWidth + rect.Right;
int stopY = - halfHeight + rect.Bottom;
代码定义了图像中间的坐标系原点。这段代码将边界框(最初在 [0,width
) 和 [0,height
) 范围内定义)移动到新的坐标系。
通常霍夫变换是用左上角像素的原点定义的。但原则上,坐标系如何定义并不重要,这只是修改了一条线的参数化。为每个输入像素绘制的正弦曲线将不同,但对于与图像中的线对应的参数集,局部最大值仍会出现。
让我们来看看this C# implementation,
... ...
// get source image size
int width = image.Width;
int height = image.Height;
int halfWidth = width / 2;
int halfHeight = height / 2;
// make sure the specified rectangle recides with the source image
rect.Intersect( new Rectangle( 0, 0, width, height ) );
int startX = -halfWidth + rect.Left;
int startY = -halfHeight + rect.Top;
int stopX = width - halfWidth - ( width - rect.Right );
int stopY = height - halfHeight - ( height - rect.Bottom );
int offset = image.Stride - rect.Width;
// calculate Hough map's width
int halfHoughWidth = (int) Math.Sqrt( halfWidth * halfWidth + halfHeight * halfHeight );
int houghWidth = halfHoughWidth * 2;
houghMap = new short[houghHeight, houghWidth];
// do the job
unsafe
{
byte* src = (byte*) image.ImageData.ToPointer( ) +
rect.Top * image.Stride + rect.Left;
// for each row
for ( int y = startY; y < stopY; y++ )
{
// for each pixel
for ( int x = startX; x < stopX; x++, src++ )
{
if ( *src != 0 )
{
// for each Theta value
for ( int theta = 0; theta < houghHeight; theta++ )
{
int radius = (int) Math.Round( cosMap[theta] * x - sinMap[theta] * y ) + halfHoughWidth;
if ( ( radius < 0 ) || ( radius >= houghWidth ) )
continue;
houghMap[theta, radius]++;
}
}
}
src += offset;
}
}
... ... ...
Q.1. rect.Intersect(new Rectangle( 0, 0, width, height));
- 为什么这条线很重要?
Q.2. 为什么在下面的代码中使用rect
修改值:
int startX = -halfWidth + rect.Left;
int startY = -halfHeight + rect.Top;
int stopX = width - halfWidth - ( width - rect.Right );
int stopY = height - halfHeight - ( height - rect.Bottom );
Q.3. 为什么 y 和 x 循环从负点开始?
问题 1.
此行只是确保边界矩形完全位于图像内部。如果您要跳过此步骤,并且 rect
(部分)在图像之外,您最终会超出索引范围。
请注意,像素访问是通过指针完成的,每次 x 增量时指针递增 1,每 y 增量递增 offset
。如果 rect
比图像大,我们将递增指针使其越过图像缓冲区。如果 rect
只是移出图像边界,但不是太大,我们会读取与我们使用的坐标不对应的像素。
问题 2.
注意
int stopX = width - halfWidth - ( width - rect.Right );
int stopY = height - halfHeight - ( height - rect.Bottom );
可以简化为
int stopX = - halfWidth + rect.Right;
int stopY = - halfHeight + rect.Bottom;
代码定义了图像中间的坐标系原点。这段代码将边界框(最初在 [0,width
) 和 [0,height
) 范围内定义)移动到新的坐标系。
通常霍夫变换是用左上角像素的原点定义的。但原则上,坐标系如何定义并不重要,这只是修改了一条线的参数化。为每个输入像素绘制的正弦曲线将不同,但对于与图像中的线对应的参数集,局部最大值仍会出现。