Learning opencv续不足(十二)找圆工具的设计

在我们人类抽象世界里,随处都是直线和圆的影子。就拿最近的视觉世界镜头的标定板,有两种,方格子和圆,方格子是直线形成的,再譬如,手机板上用来定位的,很多使用“”字,这也是两条交叉的直线。这或许是“无以规矩,不成方圆”的暗示吧。

现在,我们的金箍棒又要增加新功能了,那就是变形,把找线工具(通格本)变形成一段弧线,这个描述不准确,应该称为文人墨客纸扇的扇面更恰当。更多的扇面,就可以围成一个圆。当你把这个圆形的扇面拖动到图像中有近似圆的东西上,穿越点便把这个圆show给了眼睛,这是计算与视觉的心照不宣。譬如说,晶圆上的电极就很像一个圆。这种找圆工具的设计思想,来源于“点线圆”逻辑的顺理成章。这只不过是线图像威力的继续发酵。

近期因为对找圆工具又有了新发现。所以对找圆工具又复习了一遍,趁热打铁,顺便把他贴出来,再加强记忆,要不我的记忆曲线快把他忘完了。界面上画圆使用的是计算机图形学基础中点画圆算法。找线工具中使用的操作小矩形在此也更新为小圆圈

为了区别找线工具的roibase类,我们设计了找圆工具的roibase2类。如下:

 public class RoiBase2//SelfCirleRoi
    {        public PointF m_Center;//圆心
        public float m_Radius;//半径
        public PointF another;//arc center point;介于 arcStart和arcEnd 之间(1/2弧处),此处会有一个操作小圆,用来操作圆的弹性
        public PointF arcEnd;//arc End point;弧结束点
        public float m_tolerance;//弹性
        //        arcC
        //     arcD    arcB
        // arcE      O      arcA                             //圆示意,圆弧上八个点和中心
        //     arcF    arcEnd  
        //        arcStart                                     //弧开始点
        public PointF O;//中心,圆心,用来拖动整个圆
        public PointF[] arcPoint;                  //
        public List<Point>[] onRadpointOut;//半径+弹性处圆弧上点集合
        public List<Point>[] onRadpointIn;//半径-弹性处圆弧上点集合
        public RoiBase2()//构造函数
        {
            m_Center = new PointF();
            m_Radius = 0;
            m_tolerance = 0;
            another = new PointF();
            arcEnd = new PointF();
            O = new PointF();
            arcPoint = new PointF[8];
            onRadpointOut = new List<Point>[8];//初始化圆弧,分为八段
            onRadpointIn = new List<Point>[8];
            for (int i = 0; i < 8; i++)//每段弧初始化
            {
                onRadpointOut[i] = new List<Point>();//半径+弹性
                onRadpointIn[i] = new List<Point>();//半径-弹性
            }
        }
        public bool Init(float x, float y, float r)//初始化函数
        {
            m_Center = new PointF(x, y);
            m_Radius = r;
            return true;
        }
        public void Draw(Graphics g, Pen p, int Dir)//画找圆工具
        {
            if (m_Radius == 0)
            {
                MessageBox.Show("please init Circle!Radius is zero!");//半径不能为零
            }
            else
            {
                //  m_Radius=m_Radius+m_tolerance;

                g.DrawRectangle(p, (int)m_Center.X - 5, (int)m_Center.Y - 5, 10, 10);//圆心小矩形,移动操作
                //base cirle
                Circle_MidPoint((int)m_Center.X, (int)m_Center.Y, (int)m_Radius, p, g);//基本圆,中点画圆算法
                //in and out circle
                DrawFollowing(g, p);//内外跟随圆,中点画圆算法
                // start line           
                g.DrawLine(p, (int)m_Center.X, (int)m_Center.Y, (int)m_Center.X, (int)(m_Center.Y + m_Radius + m_tolerance + 15));
                //arc end point and arccentrepoint;
                PointF wuyong = new PointF();
                for (int ii = 0; ii < 8; ii++)
                {
                    onRadpointIn[ii].Clear();
                    onRadpointOut[ii].Clear();

                }//内外弧间隔30,m_tolerance初始为0
                FindArcCenterAndEnd((int)m_Center.X, (int)m_Center.Y, (int)(m_Radius - m_tolerance - 15), ref wuyong, ref onRadpointIn[0]);//求出第一段内弧onRadpointIn[0],wuyong无用
                arcEnd = FindArcCenterAndEnd((int)m_Center.X, (int)m_Center.Y, (int)(m_Radius + m_tolerance + 15), ref another, ref onRadpointOut[0]);//求出第一段外弧onRadpointOut[0],求出another点
                for (int mm = 0; mm < onRadpointIn[0].Count; mm++)
                {//求出另外七段内弧
                    int yy = onRadpointIn[0][mm].Y - (int)m_Center.Y;
                    int xx = onRadpointIn[0][mm].X - (int)m_Center.X;
                    Point temppt = new Point();
                    temppt.X = yy + (int)m_Center.X;
                    temppt.Y = xx + (int)m_Center.Y;
                    onRadpointIn[1].Add(temppt);//1

                    temppt.X = yy + (int)m_Center.X;
                    temppt.Y = -xx + (int)m_Center.Y;
                    onRadpointIn[2].Add(temppt);//2


                    temppt.X = xx + (int)m_Center.X;
                    temppt.Y = -yy + (int)m_Center.Y;
                    onRadpointIn[3].Add(temppt);//3

                    temppt.X = -xx + (int)m_Center.X;
                    temppt.Y = -yy + (int)m_Center.Y;
                    onRadpointIn[4].Add(temppt);//4

                    temppt.X = -yy + (int)m_Center.X;
                    temppt.Y = -xx + (int)m_Center.Y;
                    onRadpointIn[5].Add(temppt);//5


                    temppt.X = -yy + (int)m_Center.X;
                    temppt.Y = xx + (int)m_Center.Y;
                    onRadpointIn[6].Add(temppt);//6
                    temppt.X = -xx + (int)m_Center.X;
                    temppt.Y = yy + (int)m_Center.Y;
                    onRadpointIn[7].Add(temppt);//7


                }
                for (int mm = 0; mm < onRadpointOut[0].Count; mm++)
                {//求出另外七段外弧
                    int yy = onRadpointOut[0][mm].Y - (int)m_Center.Y;
                    int xx = onRadpointOut[0][mm].X - (int)m_Center.X;
                    Point temppt = new Point();
                    temppt.X = yy + (int)m_Center.X;
                    temppt.Y = xx + (int)m_Center.Y;
                    onRadpointOut[1].Add(temppt);//1
                    temppt.X = yy + (int)m_Center.X;
                    temppt.Y = -xx + (int)m_Center.Y;
                    onRadpointOut[2].Add(temppt);//2
                    temppt.X = xx + (int)m_Center.X;
                    temppt.Y = -yy + (int)m_Center.Y;
                    onRadpointOut[3].Add(temppt);//3
                    temppt.X = -xx + (int)m_Center.X;
                    temppt.Y = -yy + (int)m_Center.Y;
                    onRadpointOut[4].Add(temppt);//4

                    temppt.X = -yy + (int)m_Center.X;
                    temppt.Y = -xx + (int)m_Center.Y;
                    onRadpointOut[5].Add(temppt);//5
                    temppt.X = -yy + (int)m_Center.X;
                    temppt.Y = xx + (int)m_Center.Y;
                    onRadpointOut[6].Add(temppt);//6
                    temppt.X = -xx + (int)m_Center.X;
                    temppt.Y = yy + (int)m_Center.Y;
                    onRadpointOut[7].Add(temppt);//7

                }
                // end line            
                g.DrawLine(p, (int)m_Center.X, (int)m_Center.Y, (int)(m_Center.X + arcEnd.X), (int)(m_Center.Y + arcEnd.Y));
                //little circle//画两个操作小圆
                Circle_MidPoint((int)(m_Center.X + another.X), (int)(m_Center.Y + another.Y), 4, p, g);
                Circle_MidPoint((int)(m_Center.X), (int)(m_Center.Y + m_Radius), 4, p, g);

                //白到黑 CentreToDown
                if (Dir == 0)
                {
                    string str1 = "白";
                    Font drawfont = new Font("Arial", 9);
                    g.DrawString(str1, drawfont, Brushes.Brown, m_Center.X - 5, m_Center.Y + 5);
                    str1 = "黑";
                    g.DrawString(str1, drawfont, Brushes.Blue, (m_Center.X) - 5,
                                       (m_Center.Y + m_Radius) + 5);
                }

                //黑到白 DownToCentre
                if (Dir == 1)
                {
                    string str1 = "黑";
                    Font drawfont = new Font("Arial", 9);
                    g.DrawString(str1, drawfont, Brushes.Blue, m_Center.X - 5, m_Center.Y + 5);
                    str1 = "白";
                    g.DrawString(str1, drawfont, Brushes.Brown, m_Center.X - 5,
                                        (m_Center.Y + m_Radius) + 5);
                }

                O = m_Center;//"o"

                arcPoint[0].X = (m_Center.X);
                arcPoint[0].Y = (m_Center.Y + m_Radius + m_tolerance + 15);//start

                arcPoint[1].X = (m_Center.X + arcEnd.X);
                arcPoint[1].Y = (m_Center.Y + arcEnd.Y);//end

                arcPoint[2].X = (m_Center.X + m_Radius + m_tolerance + 15);
                arcPoint[2].Y = m_Center.Y;//"a"

                arcPoint[3].X = m_Center.X + arcEnd.X;
                arcPoint[3].Y = m_Center.Y - arcEnd.Y;//"b"

                arcPoint[4].X = m_Center.X;//"c"
                arcPoint[4].Y = (m_Center.Y - m_Radius - m_tolerance - 15);

                arcPoint[5].X = (m_Center.X - arcEnd.X);//"d"
                arcPoint[5].Y = (m_Center.Y - arcEnd.Y);

                arcPoint[6].X = (m_Center.X - m_Radius - m_tolerance - 15);//"e"
                arcPoint[6].Y = m_Center.Y;

                arcPoint[7].X = (m_Center.X - arcEnd.X);//"f"
                arcPoint[7].Y = (m_Center.Y + arcEnd.Y);
            }
        }
        public void Circle_MidPoint(int x, int y, int r, Pen p, Graphics g)//中点画圆算法
        {
            int tx = 0, ty = r, d = (int)(1.25 - r);

            while (tx < ty)
            {
                PointF tempPt = new PointF(x + tx, y + ty);
                PointF tempPt1 = new PointF(tempPt.X + 1, tempPt.Y);
                g.DrawLine(p, tempPt, tempPt1);
                // pDC->SetPixel(x + tx, y + ty, color);//1
                tempPt = new PointF(x + tx, y - ty);
                tempPt1 = new PointF(tempPt.X + 1, tempPt.Y);
                g.DrawLine(p, tempPt, tempPt1);
                //pDC->SetPixel(x + tx, y - ty, color);   //2          
                //pDC->SetPixel(x - tx, y + ty, color); 
                tempPt = new PointF(x - tx, y + ty);
                tempPt1 = new PointF(tempPt.X + 1, tempPt.Y);
                g.DrawLine(p, tempPt, tempPt1);
                //pDC->SetPixel(x - tx, y - ty, color);//3
                tempPt = new PointF(x - tx, y - ty);
                tempPt1 = new PointF(tempPt.X + 1, tempPt.Y);
                g.DrawLine(p, tempPt, tempPt1);

                //pDC->SetPixel(x + ty, y + tx, color);//4
                tempPt = new PointF(x + ty, y + tx);
                tempPt1 = new PointF(tempPt.X + 1, tempPt.Y);
                g.DrawLine(p, tempPt, tempPt1);
                //pDC->SetPixel(x + ty, y - tx, color);//5
                tempPt = new PointF(x + ty, y - tx);
                tempPt1 = new PointF(tempPt.X + 1, tempPt.Y);
                g.DrawLine(p, tempPt, tempPt1);
                //pDC->SetPixel(x - ty, y + tx, color);//6
                tempPt = new PointF(x - ty, y + tx);
                tempPt1 = new PointF(tempPt.X + 1, tempPt.Y);
                g.DrawLine(p, tempPt, tempPt1);
                //pDC->SetPixel(x - ty, y - tx, color);//7
                tempPt = new PointF(x - ty, y - tx);
                tempPt1 = new PointF(tempPt.X + 1, tempPt.Y);
                g.DrawLine(p, tempPt, tempPt1);

                if (d < 0)
                    d += 2 * tx + 3;
                else
                {
                    d += 2 * (tx - ty) + 5;
                    ty--;
                }
                tx++;
            }

        }
        public void DrawFollowing(Graphics g, Pen p)//中点画圆算法
        {
            Circle_MidPoint((int)m_Center.X, (int)m_Center.Y, (int)(m_Radius - m_tolerance - 15), p, g);
            Circle_MidPoint((int)m_Center.X, (int)m_Center.Y, (int)(m_Radius + m_tolerance + 15), p, g);
        }
        public PointF FindArcCenterAndEnd(int x, int y, int r, ref PointF another, ref List<Point> onRadpoints)
        {//找出第一段弧,another是第一段外弧的1/2弧处点,//中点画圆算法
            // List<Point> hushangdian = new List<Point>();//1/8弧20150805
            int tx = 0, ty = r, d = (int)(1.25 - r);
            int count = 0;
            while (tx < ty)
            {
                //    pDC->SetPixel(x+tx,y+ty,color);
                Point temp = new Point(x + tx, y + ty);
                onRadpoints.Add(temp);
                if (d < 0)
                    d += 2 * tx + 3;
                else
                {
                    d += 2 * (tx - ty) + 5;
                    ty--;
                    count++;
                }
                tx++;
                count++;
            }
            Point pt = new Point(tx - 1, ty);

            tx = 0; ty = r; d = (int)(1.25 - r);
            int k = 0;
            while (tx < ty)
            {
                if (d < 0)
                    d += 2 * tx + 3;
                else
                {
                    d += 2 * (tx - ty) + 5;
                    if (k == count / 2)
                        break;///////////////////////////////////important
                    ty--;
                    k++;
                }
                if (k == count / 2)
                    break;
                tx++;
                k++;
            }
            another.X = tx;//center
            another.Y = ty;
            return pt;//end
        }
        ///////////////////////operate
        public int IsPointInRect(PointF point)
        {

            if (point.X <= (int)m_Center.X + 5 && point.X >= (int)m_Center.X - 5
        && point.Y >= (int)m_Center.Y - 5 && point.Y <= (int)m_Center.Y + 5)
            {
                return 1;  //E_HANDLE_INSIDE,//操作圆心移动
            }
            else if (point.X <= (int)(m_Center.X + another.X + 1.4) && point.X >= (int)(m_Center.X + another.X - 1.4)
        && point.Y >= (int)(m_Center.Y + another.Y - 1.4) && point.Y <= (int)(m_Center.Y + another.Y + 1.4))
            {
                return 9;//E_HANDLE_SOUTH_EAST,//操作弹性范围,改变内外圆
            }
            else if (point.X <= (int)(m_Center.X + 1.4) && point.X >= (int)(m_Center.X - 1.4)
                && point.Y >= (int)(m_Center.Y + m_Radius - 1.4) && point.Y <= (int)(m_Center.Y + m_Radius + 1.4))
            {
                return 4;//  E_HANDLE_SOUTH,//操作半径大小
            }
            else
            {
                return -1;
            }
        }
        public void Drag(PointF point)//中心改变
        {
            m_Center = (point);
        }
        public void DragTolerance(PointF point)//弹性改变
        {
            m_tolerance = (float)Math.Sqrt((point.X - m_Center.X) * (point.X - m_Center.X) + (point.Y - m_Center.Y) * (point.Y - m_Center.Y)) - m_Radius - 15;
            // m_Radius = m_Radius + m_tolerance;
        }
        public void DragRadius(PointF point)//半径改变
        {
            m_Radius = (float)Math.Sqrt((point.X - m_Center.X) * (point.X - m_Center.X) + (point.Y - m_Center.Y) * (point.Y - m_Center.Y));
        }

    }

(未完待续....................)

猜你喜欢

转载自blog.csdn.net/ganggangwawa/article/details/89173494