private void btnExport_Click(object sender, EventArgs e) { if (dlgSave.ShowDialog() == DialogResult.OK) { var colors = GetColorList(); var cube = ColorClassification.GetCube(colors); var sb = new StringBuilder("R;G;B;Name"); for (int i = 0; i < colors.Count; i++) { var color = colors[i]; sb.AppendLine(); sb.Append(color.R); sb.Append(";"); sb.Append(color.G); sb.Append(";"); sb.Append(color.B); sb.Append(";"); sb.Append(cube.colors[i].Name); } System.IO.File.WriteAllText(dlgSave.FileName, sb.ToString()); } }
private void btnInit_Click(object sender, EventArgs e) { var colors = GetColorList(); using (var state = GlobalState.GetState()) { state.InitialCube = ColorClassification.GetCube(colors); } }
private void Application_Idle(object sender, EventArgs e) { Image <Bgr, byte> inImage = null; lock (_lockVideoAccess) { if (_capture == null) { return; } Pastille[,] pastilleMatrix = null; double angle = 0; //run this until application closed (close button click on image viewer) var frame = _capture.QueryFrame(); if (frame == null) { return; } inImage = frame.ToImage <Bgr, byte>(); //draw the image obtained from camera // var contourImage = inImage.Clone(); Mat outImage = new Mat(); CvInvoke.MedianBlur(inImage, outImage, 5); ////var processsImageChannels = new Image<Bgr, byte>(inImage.Size); ////CvInvoke.CvtColor(frame, processsImageChannels, ColorConversion.Rgb2Hsv); // var processsImage = new Mat(); // CvInvoke.ExtractChannel(inImage, processsImage, 1); //processViewer.Image = processsImageChannels; Mat canny = new Mat(); CvInvoke.Canny(outImage, canny, 58, 130, 3, true); //cannyViewer.Image = canny; //CvInvoke.DrawContours(outImage, contours,-1, new MCvScalar(0,0,255)); using (VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint()) { CvInvoke.FindContours(canny, contours, null, RetrType.List, ChainApproxMethod.ChainApproxSimple); var lstParallelogram = new List <Quadrilateral>(); for (int i = 0; i < contours.Size; i++) { using (VectorOfPoint contour = contours[i]) using (VectorOfPoint approxContour = new VectorOfPoint()) { var arc = CvInvoke.ArcLength(contour, true); // éliminer les objets les plus petits if (arc / 4 < inImage.Width / 30) { continue; } CvInvoke.ApproxPolyDP(contour, approxContour, arc * 0.02, true); if (approxContour.Size == 4) { var pts = approxContour.ToArray(); // contourImage.DrawPolyline(pts, true, new Bgr(Color.Green)); var quadri = new Quadrilateral(pts, 0.1, 0.1); if (quadri.IsParallelogram) { lstParallelogram.Add(quadri); } } } } //contourViewer.Image = contourImage; // suppression des doublons var comparer = new QuadrilateralCenterComparer(0.3); lstParallelogram = lstParallelogram.Distinct(comparer).ToList(); var lstSquares = lstParallelogram.Where((x) => x.IsSquare).ToList(); // nombre minimal de cube if (lstSquares.Count > 5) { var minX = lstSquares.Min((x) => x.Center.X); var maxX = lstSquares.Max((x) => x.Center.X); var minY = lstSquares.Min((x) => x.Center.Y); var maxY = lstSquares.Max((x) => x.Center.Y); lstSquares.Min((x) => x.Center.X); // largeur moyenne d'une pastille var averageLength = lstSquares.Average((x) => x.AverageLength); // distance entre les centres des pastilles. Première approximation var centerDistance = averageLength * 1.4; var bottom = new Vector2(lstSquares.Average((x) => x.Bottom.X), lstSquares.Average((x) => x.Bottom.Y)); bottom.Normalize(); var right = new Vector2(bottom.Y, -bottom.X); var pastilles = new List <Pastille>(); var pastilleOrigine = new Pastille(); pastilleOrigine.m = 0; pastilleOrigine.n = 0; pastilleOrigine.Quadrilateral = lstSquares[0]; pastilleOrigine.Center = lstSquares[0].Center; pastilles.Add(pastilleOrigine); var origine = lstSquares[0].Center; for (int i = 1; i < lstSquares.Count; i++) { var u = lstSquares[i].Center - origine; var pastille = new Pastille(); pastille.Quadrilateral = lstSquares[i]; pastille.m = (int)Math.Round(Vector2.Dot(u, bottom) / centerDistance); pastille.n = (int)Math.Round(Vector2.Dot(u, right) / centerDistance); pastille.Center = lstSquares[i].Center; pastilles.Add(pastille); } var xMax = pastilles.Max((x) => x.n); var xMin = pastilles.Min((x) => x.n); var yMax = pastilles.Max((x) => x.m); var yMin = pastilles.Min((x) => x.m); if (xMax - xMin != 3 || yMax - yMin != 3) { return; // ce n'est pas un cube 4x4 } // x et y entre 0 et 3 pastilles.ForEach((x) => { x.m -= yMin; x.n -= xMin; }); // recalcul de centerDistance centerDistance = 0; for (int i = 0; i < pastilles.Count - 1; i++) { var dm = pastilles[i + 1].m - pastilles[i].m; var dn = pastilles[i + 1].n - pastilles[i].n; centerDistance += (pastilles[i].Center - pastilles[i + 1].Center).LengthFast / Math.Sqrt(dm * dm + dn * dn); } centerDistance /= pastilles.Count - 1; pastilleMatrix = new Pastille[4, 4]; for (int m = 0; m < 4; m++) { for (int n = 0; n < 4; n++) { var pastille = pastilles.FirstOrDefault((x) => x.m == m && x.n == n); if (pastille == null) { pastille = new Pastille(); pastille.m = m; pastille.n = n; // calcul de la position des pastilles non détéctées foreach (var p in pastilles) { pastille.Center += p.Center + (float)centerDistance * ((m - p.m) * bottom + (n - p.n) * right); } pastille.Center /= pastilles.Count; } pastilleMatrix[m, n] = pastille; var ptRect = pastille.Center - new Vector2(averageLength / 4); if (ptRect.X < 0) { ptRect.X = 0; } else if (ptRect.X + averageLength / 2 >= inImage.Width) { ptRect.X = inImage.Width - 1 - (int)averageLength / 2; } if (ptRect.Y < 0) { ptRect.Y = 0; } else if (ptRect.Y + averageLength / 2 >= inImage.Height) { ptRect.Y = inImage.Height - 1 - (int)averageLength / 2; } var rectangle = new Rectangle((int)ptRect.X, (int)ptRect.Y, (int)averageLength / 2, (int)averageLength / 2); // var rectMat = processsImageChannels.GetSubRect(rectangle); // var color = CvInvoke.Mean(rectMat); // pastille.MeanColorHSV.MCvScalar = color; var rectMat = inImage.GetSubRect(rectangle); pastille.MeanColorBGR.MCvScalar = CvInvoke.Mean(rectMat); //var minDist = float.MaxValue; //foreach (var elt in Colors) //{ // var dist = (elt.Value - new Vector2((float)color.V0, (float)color.V1)).Length; // if (dist < minDist) // { // minDist = dist; // pastille.Color = elt.Key; // } //} } } foreach (var pastille in pastilleMatrix) { if (pastille.Quadrilateral != null) { inImage.DrawPolyline(pastille.Quadrilateral.Points, true, new Bgr(Color.Blue), 3); inImage.Draw(new LineSegment2D(new Point((int)(pastille.Quadrilateral.Center.X), (int)(pastille.Quadrilateral.Center.Y)), new Point((int)(pastille.Quadrilateral.Center.X + right.X * 20), (int)(pastille.Quadrilateral.Center.Y + right.Y * 20))), new Bgr(Color.SeaGreen), 3); inImage.Draw(new LineSegment2D(new Point((int)(pastille.Quadrilateral.Center.X), (int)(pastille.Quadrilateral.Center.Y)), new Point((int)(pastille.Quadrilateral.Center.X + bottom.X * 20), (int)(pastille.Quadrilateral.Center.Y + bottom.Y * 20))), new Bgr(Color.Red), 3); inImage.Draw(pastille.m + ";" + pastille.n, new Point((int)pastille.Quadrilateral.Center.X - 10, (int)pastille.Quadrilateral.Center.Y + 10), FontFace.HersheyComplex, 0.5, new Bgr(Color.Aquamarine), 1); } else { var circle = new CircleF(new PointF(pastille.Center.X, pastille.Center.Y), averageLength / 4); inImage.Draw(circle, new Bgr(Color.Pink), (int)averageLength / 4); //inImage.Draw(circle, new Bgr(Color.Pink), 3); } //var l = 20; //var rect = new Rectangle(pastille.m * l + l, pastille.n * l + l, l / 2, l / 2); //inImage.Draw(rect, new Bgr(pastille.Color), l / 2, LineType.AntiAlias); } inImage.Draw(new CircleF(new PointF(origine.X, origine.Y), 5), new Bgr(Color.Purple), 10); angle = Math.Atan2(bottom.X, bottom.Y); } } var allFacesScanned = false; // traitement des infos de l'image, mise à jour de l'état using (var state = GlobalState.GetState()) { if (state.Scanner.Starting) { for (int f = 0; f < 6; f++) { for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { _scannedColors[f, i, j].Clear(); //_scannedCube.colors[f * 16 + i * 4 + j] = Color.Transparent; } } } } // si on est en scan mais qu'aucun cube n'est détécté if (!state.Scanner.WaitingForFace && pastilleMatrix == null) { // lancer un timer if (!_noCubeSW.IsRunning) { _noCubeSW.Restart(); } // si le temps imparti est atteint, passer à la face suivant else if (_noCubeSW.ElapsedMilliseconds > 1000) { _noCubeSW.Stop(); state.Scanner.WaitingForFace = true; MainForm.Instance.Viewer.SetCameraInclination(0); switch (state.Scanner.CurrentScannedFace) { case Faces.L: state.Scanner.CurrentScannedFace = Faces.B; MainForm.Instance.Viewer.RotateCube(Modele.Axe.Z); break; case Faces.B: state.Scanner.CurrentScannedFace = Faces.R; MainForm.Instance.Viewer.RotateCube(Modele.Axe.Z); break; case Faces.R: state.Scanner.CurrentScannedFace = Faces.F; MainForm.Instance.Viewer.RotateCube(Modele.Axe.Z); break; case Faces.F: state.Scanner.CurrentScannedFace = Faces.D; MainForm.Instance.Viewer.RotateCube(Modele.Axe.Y); break; case Faces.D: state.Scanner.CurrentScannedFace = Faces.U; MainForm.Instance.Viewer.RotateCube(Modele.Axe.Y, -2); break; case Faces.U: allFacesScanned = true; state.Scanner.CurrentScannedFace = Faces.UNKNOWN; MainForm.Instance.Viewer.RotateCube(Modele.Axe.Y); System.Threading.Thread.Sleep(1000); break; default: Logger.Log("Face inconnue lors du scan", TraceEventType.Error); break; } } } else if (pastilleMatrix != null) { _noCubeSW.Stop(); if (state.Scanner.CurrentScannedFace == Faces.UNKNOWN) { state.Scanner.Reset(); } for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { _scannedColors[(int)state.Scanner.CurrentScannedFace, i, j].Add(pastilleMatrix[i, j]); } } // raz du cube if (state.Scanner.Starting) { MainForm.Instance.Viewer.RefreshCube(null); MainForm.Instance.Viewer.RotateCube(Modele.Axe.Z); } SumAngle += angle; nbAngleSamples++; if (_refreshCubeSW.ElapsedMilliseconds > 300 && nbAngleSamples > 0) { MainForm.Instance.Viewer.setColorsAndInclination(_scannedColors.OfType <List <Pastille> >().Select((lst) => lst.Count == 0 ? Color.FromArgb(0x22, 0x22, 0x22) : Color.FromArgb((int)lst.Average((x) => x.MeanColorBGR.Red), (int)lst.Average((x) => x.MeanColorBGR.Green), (int)lst.Average((x) => x.MeanColorBGR.Blue))), SumAngle / nbAngleSamples); SumAngle = 0; nbAngleSamples = 0; _refreshCubeSW.Restart(); } state.Scanner.WaitingForFace = false; } // dessiner un carré autour de l'image si un scan est en cours if (!state.Scanner.WaitingForFace) { inImage.Draw(new Rectangle(0, 0, inImage.Width, inImage.Height), new Bgr(Color.Red), 10); } if (allFacesScanned) { state.InitialCube = ColorClassification.GetCube(_scannedColors.OfType <List <Pastille> >().Select((lst) => Color.FromArgb((int)lst.Average((x) => x.MeanColorBGR.Red), (int)lst.Average((x) => x.MeanColorBGR.Green), (int)lst.Average((x) => x.MeanColorBGR.Blue))).ToList(), state.ColorsAssociation); } } if (allFacesScanned) { FormManager.Navigate <ColorDefinitionControl>(); } } _viewer.Image = inImage; }