我已经完成了代码,但我认为我的代码仍然有所改进 .
This is what I want to find:
每个象限有4种颜色的正方形 . 背景是灰色的 .
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:
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?