我已经完成了代码,但我认为我的代码仍然有所改进 .

This is what I want to find:

每个象限有4种颜色的正方形 . 背景是灰色的 .

What I want to find

This is my implementation:

frame_drone是图像帧 .

我的实施:

  • PyrDown,PyrUp

  • SmoothGaussian(3)

  • 转换

  • 阈值Hsv - > Hsv.InRange(H,S,V)

  • 阈值HSV扩张3

  • 阈值HSV侵蚀1

  • 门槛HSV.Canny(50,150)

  • Canny.SmoothGaussian(5)

  • 找到Canny的轮廓

  • 如果CurrentContour.Area> 2500

  • 如果CurrentContour.Total = 4 // square

  • 找到边缘的角度 .

  • 如果角度介于75和105之间,则为正方形

  • 获取每个象限的颜色 .

  • 使用Hue确定它是红色,蓝色,绿色还是黄色 //is this right or wrong??

This is my Code (Dont look at the commented code):

public void quadrado()
    {
        #region Encontrar Quadrados        



        //int erosao = 4;
        // int dilatacao = 1;
        increamenta_listagem_quadrados = 0;
        tamanho_imagem.X = frame_drone.Width;
        tamanho_imagem.Y = frame_drone.Height;

        // elemento_erosao = new StructuringElementEx(erosao, erosao, 1, 1, Emgu.CV.CvEnum.CV_ELEMENT_SHAPE.CV_SHAPE_RECT); //elemento kernelx,kernely,anchorx,anchory
        //elemento_dilatacao = new StructuringElementEx(dilatacao, dilatacao, 1, 1, Emgu.CV.CvEnum.CV_ELEMENT_SHAPE.CV_SHAPE_RECT); //elemento kernelx,kernely,anchorx,anchory            

        frame_drone = frame_drone.PyrDown().PyrUp();
        frame_drone = frame_drone.SmoothGaussian(3); //Filtro mediana antes da passagem para HSV
        frame_drone_hsv = frame_drone.Convert<Hsv, Byte>(); //Converte a imagem da camera RGB para HSV
        // CvInvoke.cvCvtColor(frame_drone_hsv, frame_drone_hsv, COLOR_CONVERSION.BGR2HSV);
        //frame_drone_hsv = frame_drone.Convert<Hsv, Byte>();
        frame_drone_threshold_hsv = frame_drone_hsv.InRange(new Hsv(hl.Value, sl.Value, vl.Value), new Hsv(hh.Value, sh.Value, vh.Value)); //utiliza as trackbars HSV para ver a cor pretendida 
        //frame_drone_hsv.Split();


        //frame_drone_gray = frame_drone.Convert<Gray, Byte>().PyrDown().PyrUp(); //Bgr para Gray
        //frame_drone_threshold_gray = frame_drone_gray.ThresholdBinary(new Gray(150), new Gray(255)); //Threshold para mostrar apenas partes escuras (quadrados)
        //frame_drone_threshold_gray = frame_drone_threshold_gray.Dilate(2);
        //Dilatacao seguida de erosao para fechar o ruido (Origina o Fecho de Buracos nas Regiões e a Eliminação de Baías nos limites da regiões)
        //CvInvoke.cvDilate(frame_drone_threshold_hsv, frame_drone_threshold_hsv, elemento_dilatacao, 1);
        //CvInvoke.cvErode(frame_drone_threshold_hsv, frame_drone_threshold_hsv, elemento_erosao, 1);

        frame_drone_threshold_hsv = frame_drone_threshold_hsv.Dilate(3);
        frame_drone_threshold_hsv =  frame_drone_threshold_hsv.Erode(1);

        //Erosao seguida de dilatacao (Retira pequenas porções ou regiões que saem dos limites)
        //CvInvoke.cvErode(frame_drone_processado, frame_drone_processado, elemento_erosao, 1);
        // CvInvoke.cvDilate(frame_drone_processado, frame_drone_processado, elemento_dilatacao, 1);

        frame_drone_gray = frame_drone.Convert<Gray, Byte>();
        //frame_drone_gray = frame_drone_gray.SmoothGaussian(9); //Filtro gaussiano na imagem binaria        

        frame_drone_canny = frame_drone_threshold_hsv.Canny(50,150); //Canny
        frame_drone_canny = frame_drone_canny.SmoothGaussian(5);
        // CvInvoke.cvDilate(frame_drone_canny, frame_drone_canny, elemento_dilatacao, 1); //Dilatação ao canny
        //frame_drone_threshold_hsv_circulo = frame_drone_gray.ThresholdBinaryInv(new Gray(trackBar1.Value), new Gray(255));          
        frame_drone_threshold_hsv_circulo = frame_drone_hsv.InRange(new Hsv(0, 80, 40), new Hsv(22, 248, 251)); //laranja
        //frame_drone_threshold_hsv_circulo = frame_drone_hsv.InRange(new Hsv(0, 0, 0), new Hsv(0, 0, 0));
        frame_drone_threshold_hsv_circulo = frame_drone_threshold_hsv_circulo.Dilate(6);
        frame_drone_threshold_hsv_circulo = frame_drone_threshold_hsv_circulo.Erode(6);
        frame_drone_threshold_hsv_circulo = frame_drone_threshold_hsv_circulo.SmoothGaussian(15);

        frame_drone_copia = frame_drone.Copy(); //copia a imagem original para evitar pixeis escritos na imagem

        #region Extração de contornos
        using (MemStorage storage = new MemStorage()) //aloca espaço na memoria
        {


            //detecao_circulo_em_quadrado(); //procura por circulos no quadrado

            //Procura contornos 
            for (Contour<System.Drawing.Point> contours = frame_drone_canny.FindContours(Emgu.CV.CvEnum.CHAIN_APPROX_METHOD.CV_CHAIN_APPROX_SIMPLE, Emgu.CV.CvEnum.RETR_TYPE.CV_RETR_TREE, storage); contours != null; contours = contours.HNext)
            {

                Contour<System.Drawing.Point> currentContour = contours.ApproxPoly(contours.Perimeter * 0.05, storage); //AproxContour                       
                // MCvMoments moments; //inicializacao
                 // moments = currentContour.GetMoments(); // momentos

                //Cria letra
                MCvFont f = new MCvFont(FONT.CV_FONT_HERSHEY_COMPLEX, 0.8, 0.8);

                // centroid = new System.Drawing.Point((int)(moments.m10 / moments.m00), (int)(moments.m01 / moments.m00)); //calculo do centroid

                if (currentContour.Area > 2500/*currentContour.Area >= area_contornos_min.Value && currentContour.Area <= area_contornos_max.Value*/) //se a area estiver dentro dos valores das trackbars
                {

                    if (currentContour.Total == 4) //se for retangulo/quadrado
                    {
                        // string area_contornos = contours.Area.ToString();
                        //string perimetro_contornos = contours.Perimeter.ToString();

                        bool retangular = true;

                        //frame_drone.Draw("" + area_contornos.Substring(0,5),ref f, new Point(centroid.X, centroid.Y),new Bgr(Color.Black));
                        //frame_drone.Draw("" + perimetro_contornos.Substring(0,5), ref f, new Point(centroid.X, centroid.Y), new Bgr(Color.Black));



                        Point[] pontos = currentContour.ToArray(); //pontos para array
                        LineSegment2D[] edges = PointCollection.PolyLine(pontos, true);

                        for (int i = 0; i < edges.Length; i++)
                        {
                            double angulo = Math.Abs(edges[(i + 1) % edges.Length].GetExteriorAngleDegree(edges[i]));
                            if (angulo < 75 || angulo > 105) //Limitação do angulo para determinar se é quadrado ou nao
                            {
                               retangular = false; //não é quadrado
                               quadrado_detetado = 0;
                               lv_lista_quadrados.Items.Clear();
                               //increamenta_listagem_quadrados = 0;
                               posicao_atual = new PointF(0, 0);

                            }
                            if (retangular)
                            {
                                increamenta_listagem_quadrados++;                                  
                                centroid.X = (int)currentContour.GetMoments().GravityCenter.x;
                                centroid.Y = (int)currentContour.GetMoments().GravityCenter.y;


                                List<Point> pontos_quadrado = new List<Point>()
                                    {
                                        pontos[0],
                                        pontos[1],
                                        pontos[2],
                                        pontos[3]
                                    };

                                pontos_quadrado = pontos_quadrado.OrderBy(x => Math.Pow(x.X, 2) + Math.Pow(x.Y, 2)).ToList(); //reorganiza a lista de pontos por distancia a um canto da imagem


                                if (centroid.X > tamanho_imagem.X || centroid.X < 0 || centroid.Y > tamanho_imagem.Y || centroid.Y < 0)
                                {
                                    centroid.X = 0;
                                    centroid.Y = 0;
                                }


                                for (int vertices = 0; vertices <= 3; vertices++) //Numero de vertices da forma (quadrado)
                                {
                                    frame_drone.Draw(new CircleF(pontos_quadrado[vertices], 1), new Bgr(Color.Yellow), 10); //Mostra os vertices a amarelo
                                    //frame_drone.Draw("" + pontos[vertices].X + "," + pontos[vertices].Y, ref f, pontos[vertices], new Bgr(Color.Black)); //Escrever na imagem as coordenadas dos vertices  
                                    frame_drone.Draw("V" +vertices, ref f, pontos_quadrado[vertices], new Bgr(Color.Black));
                                    //treeview_contornos.Nodes[0].Nodes[0].Nodes.Add("" + vertices + ":" + "" + pontos[vertices].X + "," + pontos[vertices].Y); //Adiciona os vertices à treeview


                                    //Calcular os pontos médios
                                    int ponto_medio_x;
                                    int ponto_medio_y;

                                    PointF ponto_medio_circulo = new PointF(0,0);
                                    ponto_medio_circulo.X = (pontos_quadrado[vertices].X + centroid.X) / 2;
                                    ponto_medio_circulo.Y = (pontos_quadrado[vertices].Y + centroid.Y) / 2;

                                    //utiliza pontos perto do centroide do quadrado para ver as cores
                                    ponto_medio_x = ((pontos_quadrado[vertices].X - centroid.X) / 4) +centroid.X;
                                    ponto_medio_y = ((pontos_quadrado[vertices].Y - centroid.Y) / 4) + centroid.Y;

                                    array_pontos_medios[vertices] = new PointF(ponto_medio_x, ponto_medio_y);


                                    frame_drone.Draw(new CircleF(new Point(ponto_medio_x, ponto_medio_y), 1), new Bgr(Color.LightYellow), 7); //Desenha os pontos (quadrantes)
                                    frame_drone.Draw(new CircleF(new Point((int)ponto_medio_circulo.X, (int)ponto_medio_circulo.Y), 1), new Bgr(Color.Pink), 7); //Desenha os pontos médios (quadrantes)



                                    Color obter_cor_pixel = frame_drone_copia.Bitmap.GetPixel(ponto_medio_x, ponto_medio_y); //obtem cor do pixel no ponto médio
                                                                                                                             //RGB para HSV

                                    Color obter_cor_circulo = frame_drone_copia.Bitmap.GetPixel((int)ponto_medio_circulo.X, (int)ponto_medio_circulo.Y); //obtem cor do pixel no ponto médio
                                                                                                                                                         //RGB para HSV



                                    if(obter_cor_circulo.G < 5 && obter_cor_circulo.R < 5 && obter_cor_circulo.B <5 )
                                    {
                                        frame_drone.Draw("Circulo", ref f, new System.Drawing.Point((int)ponto_medio_circulo.X, (int)ponto_medio_circulo.Y), new Bgr(Color.White));
                                        //utiliza o centroid onde encontrou o ponto preto para o centroid do circulo
                                        centroide_circulo.X = (int)ponto_medio_circulo.X;
                                        centroide_circulo.Y = (int)ponto_medio_circulo.Y;
                                    }

                                    //float huecirculo = obter_cor_circulo.GetHue();
                                    //float saturacaocirculo = obter_cor_circulo.GetSaturation();
                                    //float luminusidadecirculo = obter_cor_circulo.GetBrightness();

                                    float hue = obter_cor_pixel.GetHue();
                                    float saturacao = obter_cor_pixel.GetSaturation();
                                    float luminusidade = obter_cor_pixel.GetBrightness();


                                    //if(huecirculo > 300 && huecirculo < 350)
                                    //{
                                    //    frame_drone.Draw("Circulo", ref f, new System.Drawing.Point((int)ponto_medio_circulo.X, (int)ponto_medio_circulo.Y), new Bgr(Color.White)); //Escrever na imagem a cor no ponto medio    
                                    //}

                                    if (hue > 160 && hue < 250)
                                    {
                                        frame_drone.Draw("Azul", ref f, new System.Drawing.Point(ponto_medio_x, ponto_medio_y), new Bgr(Color.White)); //Escrever na imagem a cor no ponto medio                                                                                    
                                        cores_dos_pontos_medios[incrementa_ponto_medio] = "Azul";
                                    }
                                    else if (hue > 60 && hue <= 160)
                                    {
                                        frame_drone.Draw("Verde", ref f, new System.Drawing.Point(ponto_medio_x, ponto_medio_y), new Bgr(Color.White)); //Escrever na imagem a cor no ponto medio           
                                        cores_dos_pontos_medios[incrementa_ponto_medio] = "Verde";
                                    }
                                    else if (hue >= 0 && hue <= 65)
                                    {
                                        frame_drone.Draw("Amarelo", ref f, new System.Drawing.Point(ponto_medio_x, ponto_medio_y), new Bgr(Color.White)); //Escrever na imagem a cor no ponto medio           
                                        cores_dos_pontos_medios[incrementa_ponto_medio] = "Amarelo";
                                    }
                                    else if ((hue >= 0 && hue <= 30) || (hue > 330 && hue <= 360))
                                    {
                                        frame_drone.Draw("Vermelho", ref f, new System.Drawing.Point(ponto_medio_x, ponto_medio_y), new Bgr(Color.White)); //Escrever na imagem a cor no ponto medio           
                                        cores_dos_pontos_medios[incrementa_ponto_medio] = "Vermelho";
                                    }

                                    incrementa_ponto_medio++;
                                    if (incrementa_ponto_medio == 4)
                                    {
                                        incrementa_ponto_medio = 0;
                                    }

                                }

This is the result:

Result

My conclusion:

The threshold and the square finding is not ideal . 它的工作原理如果完美的话 . If it's not the best but still good ,它只能在正方形的门槛 .

What can I do to improve my square finding? Is there another kind of implementation?