PDA

View Full Version : تشخیص دایره در تصویر با استفاده از تبدیل هاف دایروی



asefy2008
جمعه 07 مرداد 1390, 15:30 عصر
سلام دوستان
می خواستم بدونم کسی کلاس تشخیص دایره که از تبدیل هاف دایروی برای تشخیص دایره استفاده کرده باشه داره؟
(نکته : حتی الامکان با سی شارپ باشه)

در ضمن می خواستم بدونم دوستان راه بهتری دارند؟

مصطفی ساتکی
جمعه 07 مرداد 1390, 17:12 عصر
سورسش موجوده ولي تجربه ميگه كه hough circle يك روش robust براي localize كردن دايره در صفحه نيست هم بار محاسباتي بالايي داره و هم اينكه دقت مناسب رو نداره و همچنين به ميران دايره بودن blob هدف نيز خيلي حساسه.
راه بهتر اينه كه لبه ها رو در تصوير پيدا كنيد و سپس نقاط رو با distance مشخصي نمونه برداري كنيد سپس هر سه نقطه مجاور با distance موردنظر عمود منصف رو بدست بياريد سپس نقاط تقاطع اين عمود منصف ها رو در يك accumulator انباشت كنيد مجموعه نقاط ماكزيمم در اين accumulator مجموعه اي از مراكز دايره ها موجود در صفحه هستند حالا براي اينكه fake maximum رو fade كنيد بايستي روي كل accumulator گوسين رو اعمال كنيد حالا همه نقاط صحت دارند.
حالا از اين نقاطي كه بدست آمده شما بايستي به دنبال دايره هايي با شعاع مشخص باشيد از نقاط بدست آمده به صورت radial كليه نقاط مربوط به صفحه نمونه برداري رو كه دربازه minimum radius و maximum radius قرار دارند رو نگه داريد و بقيه نقاط رو پاك كنيد سپس به ازاي هر نقطه كليه نقاطي رو كه در عمليات فيلتر مرحله قبل رو در يك آرايه بريزيد و به صورت سيگنال باهاش رفتار كنيد حال دوباره روي اين نقاط median رو اعمال كنيد و ماكزيمم رو در اين سيگنال بدست بياريد اين maximum ميشه شعاع مدنظر شما.(نكته : چون شعاع هاي بزرگتر تعداد sample هاشون بيشتر هميشه ديگر شعاع رو محو مي كنند بهترين راه اينه كه اين شعاع ها رو با توجه به degree شون quantize كنيد و شعاعي انتخاب شه كه بتونه بيشتر 2 پي رو پوشش بده)


namespace AForge.Imaging
{
using System;
using System.Collections;
using System.Drawing;
using System.Drawing.Imaging;

/// <summary>
/// Hough circle.
/// </summary>
///
/// <remarks>Represents circle of Hough transform.</remarks>
///
public class HoughCircle : IComparable
{
/// <summary>
/// Circle center's X coordinate.
/// </summary>
public readonly int X;

/// <summary>
/// Circle center's Y coordinate.
/// </summary>
public readonly int Y;

/// <summary>
/// Circle's radius.
/// </summary>
public readonly int Radius;

/// <summary>
/// Line's absolute intensity.
/// </summary>
public readonly short Intensity;

/// <summary>
/// Line's relative intensity.
/// </summary>
public readonly double RelativeIntensity;

/// <summary>
/// Initializes a new instance of the <see cref="HoughCircle"/> class.
/// </summary>
///
/// <param name="x">Circle's X coordinate.</param>
/// <param name="y">Circle's Y coordinate.</param>
/// <param name="radius">Circle's radius.</param>
/// <param name="intensity">Circle's absolute intensity.</param>
/// <param name="relativeIntensity">Circle's relative intensity.</param>
///
public HoughCircle( int x, int y, int radius, short intensity, double relativeIntensity )
{
X = x;
Y = y;
Radius = radius;
Intensity = intensity;
RelativeIntensity = relativeIntensity;
}

/// <summary>
/// Compare the object with another instance of this class.
/// </summary>
///
/// <param name="value">Object to compare with.</param>
///
/// <returns><para>A signed number indicating the relative values of this instance and <b>value</b>: 1) greater than zero -
/// this instance is greater than <b>value</b>; 2) zero - this instance is equal to <b>value</b>;
/// 3) greater than zero - this instance is less than <b>value</b>.</para>
/// <para><note>The sort order is descending.</note></para></returns>
///
public int CompareTo( object value )
{
return ( -Intensity.CompareTo( ( (HoughCircle) value ).Intensity ) );
}
}

/// <summary>
/// Hough circle transformation.
/// </summary>
///
/// <remarks><para>Hough circle transformation allows to detect circles in image.</para>
/// <para>Sample usage:</para>
/// <code>
/// HoughCircleTransformation circleTransform = new HoughCircleTransformation( );
/// // apply Hough circle transform
/// circleTransform.ProcessImage( sourceImage );
/// Bitmap houghCirlceImage = circleTransform.ToBitmap( );
/// // get circles using relative intensity
/// HoughCircle[] circles = circleTransform.GetCirclesByRelativeIntensity( 0.5 );
///
/// foreach ( HoughCircle circle in circles )
/// {
/// // ..
/// }
///
/// </code>
/// </remarks>
///
public class HoughCircleTransformation
{
// circle radius to detect
private int radiusToDetect;

// Hough map
private short[,] houghMap;
private short maxMapIntensity = 0;

// Hough map's width and height
private int width;
private int height;

private int localPeakRadius = 4;
private short minCircleIntensity = 10;
private ArrayList circles = new ArrayList( );

/// <summary>
/// Minimum circles's intensity in Hough map to recognize a circle.
/// </summary>
///
/// <remarks><para>The value sets minimum intensity level for a circle. If a value in Hough
/// map has lower intensity, then it is not treated as a circle.</para>
/// <para>Default value is <b>10</b>.</para></remarks>
///
public short MinCircleIntensity
{
get { return minCircleIntensity; }
set { minCircleIntensity = value; }
}

/// <summary>
/// Radius for searching local peak value.
/// </summary>
///
/// <remarks><para>The value determines radius around a map's value, which is analyzed to determine
/// if the map's value is a maximum in specified area.</para>
/// <para>Default value is <b>4</b>. Minimum value is <b>1</b>. Maximum value is <b>10</b>.</para></remarks>
///
public int LocalPeakRadius
{
get { return localPeakRadius; }
set { localPeakRadius = Math.Max( 1, Math.Min( 10, value ) ); }
}

/// <summary>
/// Maximum found intensity in Hough map.
/// </summary>
///
public short MaxIntensity
{
get { return maxMapIntensity; }
}

/// <summary>
/// Initializes a new instance of the <see cref="HoughCircleTransformation"/> class.
/// </summary>
///
public HoughCircleTransformation( int radiusToDetect )
{
this.radiusToDetect = radiusToDetect;
}

/// <summary>
/// Found circles count.
/// </summary>
///
public int CirclesCount
{
get { return circles.Count; }
}

/// <summary>
/// Process an image building Hough map.
/// </summary>
///
/// <param name="image">Source image to process.</param>
///
public void ProcessImage( Bitmap image )
{
// check image format
if ( image.PixelFormat != PixelFormat.Format8bppIndexed )
throw new ArgumentException( "Pixel format of source image should be 8 bpp indexed" );

// lock source image
BitmapData imageData = image.LockBits(
new Rectangle( 0, 0, image.Width, image.Height ),
ImageLockMode.ReadOnly, PixelFormat.Format8bppIndexed );

// process the image
ProcessImage( imageData );

// unlock image
image.UnlockBits( imageData );
}

/// <summary>
/// Process an image building Hough map.
/// </summary>
///
/// <param name="imageData">Source image data to process.</param>
///
public void ProcessImage( BitmapData imageData )
{
if ( imageData.PixelFormat != PixelFormat.Format8bppIndexed )
throw new ArgumentException( "Pixel format of source image should be 8 bpp indexed" );

// get source image size
width = imageData.Width;
height = imageData.Height;

int srcOffset = imageData.Stride - width;

// allocate Hough map of the same size like image
houghMap = new short[height, width];

// do the job
unsafe
{
byte* src = (byte*) imageData.Scan0.ToPointer( );

// for each row
for ( int y = 0; y < height; y++ )
{
// for each pixel
for ( int x = 0; x < width; x++, src++ )
{
if ( *src != 0 )
{
DrawHoughCircle( x, y );
}
}
src += srcOffset;
}
}

// find max value in Hough map
maxMapIntensity = 0;
for ( int i = 0; i < height; i++ )
{
for ( int j = 0; j < width; j++ )
{
if ( houghMap[i, j] > maxMapIntensity )
{
maxMapIntensity = houghMap[i, j];
}
}
}

CollectCircles( );
}

/// <summary>
/// onvert Hough map to bitmap.
/// </summary>
///
/// <returns>Returns a bitmap, which shows Hough map.</returns>
///
public Bitmap ToBitmap( )
{
// check if Hough transformation was made already
if ( houghMap == null )
{
throw new ApplicationException( "Hough transformation was not done yet" );
}

int width = houghMap.GetLength( 1 );
int height = houghMap.GetLength( 0 );

// create new image
Bitmap image = AForge.Imaging.Image.CreateGrayscaleImage( width, height );

// lock destination bitmap data
BitmapData imageData = image.LockBits(
new Rectangle( 0, 0, width, height ),
ImageLockMode.ReadWrite, PixelFormat.Format8bppIndexed );

int offset = imageData.Stride - width;
float scale = 255.0f / maxMapIntensity;

// do the job
unsafe
{
byte* dst = (byte*) imageData.Scan0.ToPointer( );

for ( int y = 0; y < height; y++ )
{
for ( int x = 0; x < width; x++, dst++ )
{
*dst = (byte) System.Math.Min( 255, (int) ( scale * houghMap[y, x] ) );
}
dst += offset;
}
}

// unlock destination images
image.UnlockBits( imageData );

return image;
}

/// <summary>
/// Get specified amount of circles with highest intensity.
/// </summary>
///
/// <param name="count">Amount of circles to get.</param>
///
/// <returns>Returns arrary of most intesive circles. If there are no circles detected,
/// <b>null</b> is returned.</returns>
///
public HoughCircle[] GetMostIntensiveCircles( int count )
{
// lines count
int n = Math.Min( count, circles.Count );

if ( n == 0 )
return null;

// result array
HoughCircle[] dst = new HoughCircle[n];
circles.CopyTo( 0, dst, 0, n );

return dst;
}

/// <summary>
/// Get circles with relative intensity higher then specified value.
/// </summary>
///
/// <param name="minRelativeIntensity">Minimum relative intesity of circles.</param>
///
/// <returns>Returns array of circles. If there are no circles detected,
/// <b>null</b> is returned.</returns>
///
public HoughCircle[] GetCirclesByRelativeIntensity( double minRelativeIntensity )
{
int count = 0, n = circles.Count;

while ( ( count < n ) && ( ( (HoughCircle) circles[count] ).RelativeIntensity >= minRelativeIntensity ) )
count++;

return GetMostIntensiveCircles( count );
}


// Collect circles with intesities greater or equal then specified
private void CollectCircles( )
{
short intensity;
bool foundGreater;

// clean circles collection
circles.Clear( );

// for each Y coordinate
for ( int y = 0; y < height; y++ )
{
// for each X coordinate
for ( int x = 0; x < width; x++ )
{
// get current value
intensity = houghMap[y, x];

if ( intensity < minCircleIntensity )
continue;

foundGreater = false;

// check neighboors
for ( int ty = y - localPeakRadius, tyMax = y + localPeakRadius; ty < tyMax; ty++ )
{
// continue if the coordinate is out of map
if ( ty < 0 )
continue;
// break if it is not local maximum or coordinate is out of map
if ( ( foundGreater == true ) || ( ty >= height ) )
break;

for ( int tx = x - localPeakRadius, txMax = x + localPeakRadius; tx < txMax; tx++ )
{
// continue or break if the coordinate is out of map
if ( tx < 0 )
continue;
if ( tx >= width )
break;

// compare the neighboor with current value
if ( houghMap[ty, tx] > intensity )
{
foundGreater = true;
break;
}
}
}

// was it local maximum ?
if ( !foundGreater )
{
// we have local maximum
circles.Add( new HoughCircle( x, y, radiusToDetect, intensity, (double) intensity / maxMapIntensity ) );
}
}
}

circles.Sort( );
}

// Draw Hough circle:
// http://www.cs.unc.edu/~mcmillan/comp136/Lecture7/circle.html (http://www.cs.unc.edu/%7Emcmillan/comp136/Lecture7/circle.html)
//
// TODO: more optimizations of circle drawing could be done.
//
private void DrawHoughCircle( int xCenter, int yCenter )
{
int x = 0;
int y = radiusToDetect;
int p = ( 5 - radiusToDetect * 4 ) / 4;

SetHoughirclePoints( xCenter, yCenter, x, y );

while ( x < y )
{
x++;
if ( p < 0 )
{
p += 2 * x + 1;
}
else
{
y--;
p += 2 * ( x - y ) + 1;
}
SetHoughirclePoints( xCenter, yCenter, x, y );
}
}

// Set circle points
private void SetHoughirclePoints( int cx, int cy, int x, int y )
{
if ( x == 0 )
{
SetHoughPoint( cx, cy + y );
SetHoughPoint( cx, cy - y );
SetHoughPoint( cx + y, cy );
SetHoughPoint( cx - y, cy );
}
else if ( x == y )
{
SetHoughPoint( cx + x, cy + y );
SetHoughPoint( cx - x, cy + y );
SetHoughPoint( cx + x, cy - y );
SetHoughPoint( cx - x, cy - y );
}
else if ( x < y )
{
SetHoughPoint( cx + x, cy + y );
SetHoughPoint( cx - x, cy + y );
SetHoughPoint( cx + x, cy - y );
SetHoughPoint( cx - x, cy - y );
SetHoughPoint( cx + y, cy + x );
SetHoughPoint( cx - y, cy + x );
SetHoughPoint( cx + y, cy - x );
SetHoughPoint( cx - y, cy - x );
}
}

// Set point
private void SetHoughPoint( int x, int y )
{
if ( ( x >= 0 ) && ( y >= 0 ) && ( x < width ) && ( y < height ) )
{
houghMap[y, x]++;
}
}
}
}

asefy2008
جمعه 07 مرداد 1390, 19:03 عصر
چند سوال داشتم :
1.منظور از با distance مشخص نمونه برداری کنیم یعنی چی؟(فرض کنید عکس لبه یابی شده را داریم حالا باید چطوری این کار را اجام بدیم)
2. منظور از سه نقطه کنار هم، هم در راستای محور xها و هم در راستای محور yها هست دیگه و همچنین مورب رو هم شامل میشه؟
3. fake maximum و fade یعنی چی ؟
4.
حالا براي اينكه fake maximum رو fade كنيد بايستي روي كل accumulator گوسين رو اعمال كنيد حالا همه نقاط صحت دارند.

اگه میشه در مورد این جمله بیشتر توضیح بدید؟

مصطفی ساتکی
شنبه 08 مرداد 1390, 09:24 صبح
جواب اول : sampling یا نمونه برداری یعنی اینکه از کل نمونه ها ، نمونه خاصی را انتخاب کنیم در اینجا لبه های متوالی که داریم رو با فواصل مشخص نمونه برداری می کنیم.
جواب دوم : نقاط مجاور یعنی که نقاطی که در یک مسیر بدون فاصله پشت سرهم قرار گرفتن در ضمن نقاطی که در راستای x یا y قرار دارند یا در زاویای K*pi/4 قرار دارند جز همسایگی محسوب نمیشن.
جواب سوم : یعنی اینکه maximum هایی که ساختگی هستند و صحت ندارند حذف می شن
جواب چهارم : از این روش جهت حذف نویز استفاده میشه

asefy2008
سه شنبه 25 مرداد 1390, 22:22 عصر
ممنون از جوابتون

جواب اول : sampling یا نمونه برداری یعنی اینکه از کل نمونه ها ، نمونه خاصی را انتخاب کنیم در اینجا لبه های متوالی که داریم رو با فواصل مشخص نمونه برداری می کنیم.
منظور از لبه های متواالی که داریم با فواصل مشخص نمونه برداری می کنیم این هست که مثلا در لبه ها 5 یا 10 سلول متوالی را به عنوان یک نمونه انتخاب می کنیم؟

مصطفی ساتکی
چهارشنبه 26 مرداد 1390, 08:50 صبح
بله sampling در واقع به همین معناست

asefy2008
جمعه 28 مرداد 1390, 23:49 عصر
ممون
در قطعه کدی که قرار دادید من از قطعه کد زیر برای اجرا اون و تشخیص دایره استفاده کردم :


HoughCircleTransformation circleTransform = new HoughCircleTransformation( 35 ); // apply Hough circle transform circleTransform.ProcessImage( sourceImage ); Bitmap houghCirlceImage = circleTransform.ToBitmap( ); // get circles using relative intensity HoughCircle[] circles = circleTransform.GetCirclesByRelativeIntensity( 0.5 ); foreach ( HoughCircle circle in circles ) { // ... }


ولی در processimage از فرمت عکس ایراد می گیره علتش چیه و چطور میشه رفعش کرد.

نکته : من یک تغییراتی تو اون قسمت دادم و درست شد ولی به هیچ عنوان نمی تونه دایره رو درست تشخیص بده من شکل داخل سایت aforge (http://www.aforgenet.com/framework/docs/html/9b9aedc2-0048-acc8-4d35-0e41788d69da.htm) رو دادم بهش ولی اون جواب رو بهم نداد در صورتی که برای مثالی که خود سایت aforge داده درست کار می کنه(من مثال خود سایت رو دانلود کردم و پایین قرار دادم).

اینم کتغییراتی که من در کد دادم :

public void ProcessImage( Bitmap image )
{
// check image format
if ( image.PixelFormat != PixelFormat.Format32bppArgb )
throw new ArgumentException( "Pixel format of source image should be 8 bpp indexed" );

// lock source image
BitmapData imageData = image.LockBits(
new Rectangle( 0, 0, image.Width, image.Height ),
ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb );

// process the image
ProcessImage( imageData );

// unlock image
image.UnlockBits( imageData );
}

مصطفی ساتکی
شنبه 29 مرداد 1390, 08:54 صبح
من اگر توجه کرده باشید در پست شماره 2 به شما عرض کردم که hough circle ط یک localizer خوبی نیست در همون پست برای شما نحوه پیاده یازی circle finder رو توضیح دادم من خودم به شخصه در کارهام از چندین نوع circle finder استفاده می کنم که توسط خودم پیاده شده و طرحش هم از خودم بوده با توجه به شرایط شما می تونید rule هایی رو به هر کدام از circle finder ها اعمال کنید که در همون زمینه مشخص جوابهای robust ی رو به شما میده

asefy2008
یک شنبه 23 بهمن 1390, 00:28 صبح
با تشکر از شما
می خواستم ببینم نمونه کد تبدیل هاف دایروی رو با متلب دارید(یا هر کدی با متلب که بتوننه دایره رو تشخیص بده)؟

در ضمن ممنون از توضیحات قبلیتون که واقعا کمکم کرد وتونستم یک راه جدید برای کارم پیداکنم.

مصطفی ساتکی
دوشنبه 24 بهمن 1390, 21:27 عصر
خواهش می کنم.
من با C++ کار می کنم ولی به c اگر بخاید می تونم راهنمایی تون کنم

asefy2008
دوشنبه 24 بهمن 1390, 23:13 عصر
ممنون میشم اگه کمک بفرمایید.
فکر کنم بالاخره باید برم سمت C++‎ اکثر کدها چه در اینترنت و چه دوستان می فرماین به متلب و سی هست.

من سرانجام تونستم پروژه تشخیص هویت از طریق عنبیه رو تکمیل کنم ولی بزرگترین مشکلش کندی در پیدا کردن دایره که واقعا برنامه رو کند کرد.(البته دایره داخلی رو با کمک های شما خیلی سریع پیدا می کنه.)

alibagherian
جمعه 04 مرداد 1392, 22:22 عصر
سلام به دوستان
كسي برنامه تشخيص دايره با متلب را داره ؟