【问题标题】:Circle Detection without use Aforge Or OpenCv不使用 Aforge 或 OpenCv 的圆形检测
【发布时间】:2015-03-11 22:14:24
【问题描述】:

我想在没有库的情况下检测位图中的圆圈。首先,我使用 otsu thresold 进行二值化。二值化后,我使用了拉普拉斯边缘检测。现在我的位图中有一个圆圈。我怎样才能检测到这个圈子。

注意:我尝试画一个圆并浮动 x 和 y 坐标。但是这种方式太慢了,而且这种方式有半径问题。因为,如果我的 tempCircle 的 radius=10 和 real circle 的 radius=9,那么我的算法找不到圆。

    BitmapProcess bmpPro = new BitmapProcess((Bitmap)(pictureBox1.Image));
    bmpPro.LockBits();
    int black = 0, temp = 0,fixX=0,fixY=0;

    Bitmap bmp = (Bitmap)pictureBox1.Image;
    Graphics g = this.pictureBox1.CreateGraphics();
    Pen pen = new Pen(Color.Red, 10);
    int x = 0, y = 0;
    for (int a = 0; a < pictureBox1.Image.Width - 1; a += 1)
    {
        for (int b = 0; b < pictureBox1.Image.Height - 1; b++)
        {
            double radius = 10;

            temp = 0;
            for (double i = 0.0; i < 360.0; i += 1)
            {
                double angle = i * System.Math.PI / 180;
                x = (int)(a + radius * System.Math.Cos(angle));
                y = (int)(b + radius * System.Math.Sin(angle));
                Color aa = bmpPro.GetPixel(Math.Abs(x), Math.Abs(y));

                if (bmpPro.GetPixel(Math.Abs(x), Math.Abs(y))!=Color.Black) temp++;

            }
            if (temp > black)
            {
                black = temp;
                fixX = a;
                fixY = b;

            }

        }

    }
    g.DrawEllipse(pen,fixX,fixY,50,50);



using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace LockBitBitmap
{
    class BitmapProcess
    {
        public int b = 0;
        int TotalPixelLocked; 
        Bitmap source = null; //kaynak bmp
        IntPtr Iptr = IntPtr.Zero; //baslangıc adresi
        BitmapData bitmapData = null;

        public byte[] Pixels { get; set; }
        public int Depth { get; set; }
        public int Width { get; set; }
        public int Height { get; set; }

        public BitmapProcess(Bitmap source)
        {
            this.source = source;  //bitmapı dısardan al
        }

        public void LockBits()
        {
            //resmin en ve boyunu al
            Width = source.Width;
            Height = source.Height;

            //kilit için rectangle olustur
            Rectangle rect = new Rectangle(0,0,Width,Height);

            //kaynak bitmap ın pixel formatını al
            Depth = System.Drawing.Bitmap.GetPixelFormatSize(source.PixelFormat);

            //pixel basına bit sayısını bul(Bpp)
            if (Depth != 8 && Depth != 24 && Depth != 32)
            {
                return; //bit türü desteklenmiyor...
            }

            //bitmapı kilitle ve veriyi döndür...          
            bitmapData = source.LockBits(rect, ImageLockMode.ReadWrite, source.PixelFormat);

            //kilitlenecek pixel sayısını al
            TotalPixelLocked = Math.Abs(bitmapData.Stride) * source.Height;

            //pixel verilerini tutmak için byte dizisi olustur
            int step = Depth / 8;
            Pixels = new byte[TotalPixelLocked * step];
            Iptr = bitmapData.Scan0;

            //verileri pointerden diziye aktar
            Marshal.Copy(Iptr, Pixels, 0, TotalPixelLocked);

        }

        public Color GetPixel(int x, int y)
        {
            Color clr = Color.Empty; //boş renk

            //renkli nesne sayısını al
            int cCount = Depth / 8;

            //istenen pixelin baslangıc adresini bul
            int i = y * bitmapData.Stride + x * cCount;
            if (i > (Pixels.Length - cCount))
            {
                throw new IndexOutOfRangeException("index out of range ( dizi adresi geçersiz)");
            }
            if (Depth == 32) //r g b a
            {
                byte b = Pixels[i];
                byte g = Pixels[i + 1];
                byte r = Pixels[i + 2];
                byte a = Pixels[i + 3];
                clr = Color.FromArgb(a,r,g,b);
            }

            if (Depth == 24) //r g b 
            {
                byte b = Pixels[i];
                byte g = Pixels[i + 1];
                byte r = Pixels[i + 2];
                clr = Color.FromArgb(r, g, b);
            }

            if (Depth == 8) // r g b hepsi aynı
            {
                byte c = Pixels[i];
                clr = Color.FromArgb(c,c,c);
            }


            return clr;

        }

        public void SetPixel(int x, int y, Color color)
        {
            // renkli nesne sayısı
            int cCount = Depth / 8;

            // baslangıc indexini bul
            //int i = ((y * Width) + x) * cCount;
            int i = y * bitmapData.Stride + x * cCount;
            if (i > (Pixels.Length - cCount))
            {
                throw new IndexOutOfRangeException("index out of range ( dizi adresi geçersiz)");
            }
            if (Depth == 32) // r,g,b, (alpha)
            {
                Pixels[i] = color.B;
                Pixels[i + 1] = color.G;
                Pixels[i + 2] = color.R;
                Pixels[i + 3] = color.A;
            }
            if (Depth == 24) // r,g,b
            {
                Pixels[i] = color.B;
                Pixels[i + 1] = color.G;
                Pixels[i + 2] = color.R;
                b++;
            }
            if (Depth == 8)//r g b hepsi aynı
            {
                Pixels[i] = color.B;
            }
        }

        public Bitmap giveBitmap()
        {
            System.Runtime.InteropServices.Marshal.Copy(Pixels, 0, Iptr, TotalPixelLocked);
            source.UnlockBits(bitmapData);
            return source;
        }





    }
}

【问题讨论】:

    标签: c# image opencv image-processing aforge


    【解决方案1】:

    如果图片中只有几个圆圈,我建议使用RANSAC

    简要说明:从您的边缘像素中,随机选择 3 个点和适合这些点的find the equation of the circle。在所有剩余的边缘点上使用这个方程,看看它们中有多少位于圆上,即有多少满足方程。重复这个过程N次(N可以根据各种因素决定,包括边缘点的个数,圆的个数等),记录内点数最多的迭代(位于圆上的点)。这个最大迭代对应的方程就是你的最佳拟合圆。

    如果图像中有多个圆圈,请在删除或屏蔽所有与先前找到的圆圈相匹配的点后重复上述步骤。

    【讨论】:

      【解决方案2】:

      你为什么不看一看谢永红和季强写的一篇论文“一种新的高效椭圆检测方法”。 link

      我知道它的标题中有椭圆,但你肯定知道 cricle 只是非常特殊的椭圆;)。

      提示:处理的下一步应该是聚类边缘像素 - 这样您就可以知道哪些像素正在创建一个对象。我们知道对象有一些属性,您应该确定哪些对象属性使该对象成为圆形 - 然后在您的代码中实现这些基于属性的过滤器。

      【讨论】:

        猜你喜欢
        • 2017-07-01
        • 2017-05-24
        • 2016-06-01
        • 1970-01-01
        • 1970-01-01
        • 2015-08-06
        • 1970-01-01
        • 2018-03-20
        • 1970-01-01
        相关资源
        最近更新 更多