Click here to Skip to main content
15,881,852 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
hi guys
i wrote this code in c# (winform) . my app use from Emgu-cv library for image processing in c#
you can see codes of main file (lineutil.cs) as below
with this code app can draw lines with (Houghline)
and app can find intersection points between lines and show them with a TiltedCross sign
my app can find intersection points in lines of field in image no.1 (1.jpg)
but my app can not determine it well on image no.2 (2.jpg)
i have a question
how can change my code that app find only White Lines in image (Lines of football field) in image no.2 ????
or . have a better idea?
thanks in advance
you can see complete files of my project here: (such as images no.1 and no.2 and (Form1.cs) and all other files)
Upload files for free - Project.zip - ufile.io[^]

and can see main lines of Form1.cs
public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void loadButton_Click(object sender, EventArgs e)
    {
        using (var openFileDialog = new OpenFileDialog())
        {
            openFileDialog.InitialDirectory = "c:\\";
            openFileDialog.Filter = @"Image files (*.jpg, *.jpeg, *.jpe, *.jfif, *.png)|*.jpg;*.jpeg;*.jpe;*.jfif;*.png";
            openFileDialog.RestoreDirectory = true;
            if (openFileDialog.ShowDialog() == DialogResult.OK)
            {
                var filePath = openFileDialog.FileName;
                using (var img = new Image<Bgr, Byte>(filePath))
                using (var grayImg = img.Convert<Gray, Byte>())
                {
                    var points = LineUtil.FindIntersectionsByHoughLines(grayImg, out var lines);
                    LineUtil.DrawLines(img, lines, img.Size, Color.Yellow);
                    LineUtil.DrawPoints(img, points, Color.Red);
                    pictureBox.Image = img.AsBitmap();
                }
            }
        }
    }
}


What I have tried:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Numerics;
using System.Runtime.InteropServices;
using Emgu.CV;
using Emgu.CV.CvEnum;
using Emgu.CV.Features2D;
using Emgu.CV.LineDescriptor;
using Emgu.CV.Structure;
using Emgu.CV.Util;
using Emgu.CV.ML;
#if !__IOS__
using Emgu.CV.Cuda;
#endif
using Emgu.CV.XFeatures2D;

namespace FormEmgu
{
    public static class LineUtil
    {

        public static void DrawPoints(IInputOutputArray image, IEnumerable<Point> points, Color color,
            MarkerTypes marker = MarkerTypes.TiltedCross)
        {
            var c = new MCvScalar(color.B, color.G, color.R);
            foreach (var p in points)
            {
                CvInvoke.DrawMarker(image, p, c, marker, 10, 1);
            }
        }

        public static void DrawLines(IInputOutputArray image, IEnumerable<PointF> lines, Size size, Color color,
            int thickness = 1)
        {
            var c = new MCvScalar(color.R, color.G, color.B);
            foreach (var p in lines)
            {
                (Point p0, Point p1) = LineToPoints(p, size.Width, size.Height);
                CvInvoke.Line(image, p0, p1, c, thickness);
            }
        }

        public static Point[] FindIntersectionsByHoughLines(Image<Gray, Byte> image, out PointF[] lines, int k = 2)
        {
            using (var img = image.Clone())
            {
                CvInvoke.MedianBlur(img, img, 5);
                CvInvoke.AdaptiveThreshold(
                    img, img, 255, AdaptiveThresholdType.GaussianC, ThresholdType.BinaryInv, 11, 2);
                //PointF[] lines;
                using (var vectorOfPointF = new VectorOfPointF())
                {
                    CvInvoke.HoughLines(img, vectorOfPointF, 2, Math.PI / 300, 350);
                    lines = vectorOfPointF.ToArray();
                }

                var segmented = SegmentLines(lines, k);
                var pairs = BinaryPair(segmented);
                float w = img.Width, h = img.Height;
                var intersections = new List<Point>();
                foreach ((PointF line0, PointF line1) in pairs)
                {
                    var p = FindLineIntersection(line0, line1);
                    if (p.HasValue)
                    {
                        float x = p.Value.X, y = p.Value.Y;
                        if (x >= 0 && x < w && y >= 0 && y < h)
                            intersections.Add(p.Value);
                    }
                }

                return intersections.ToArray();
            }
        }

        public static (Point, Point) LineToPoints(PointF line, int width, int height)
        {
            var rho = line.X;
            var theta = line.Y;
            var pt1 = new Point();
            var pt2 = new Point();
            var a = Math.Cos(theta);
            var b = Math.Sin(theta);
            var x0 = a * rho;
            var y0 = b * rho;
            pt1.X = (int) Math.Round(x0 + width * (-b));
            pt1.Y = (int) Math.Round(y0 + height * (a));
            pt2.X = (int) Math.Round(x0 - width * (-b));
            pt2.Y = (int) Math.Round(y0 - height * (a));
            return (pt1, pt2);
        }

        public static List<PointF>[] SegmentLines(IList<PointF> lines, int k = 2)
        {
            var segments = new List<PointF>[k];
            for (int i = 0; i < k; i++)
            {
                segments[i] = new List<PointF>();
            }

            var points = lines.Select(p => new PointF((float) Math.Cos(p.Y * 2.0f), (float) Math.Sin(p.Y * 2.0f)))
                .ToArray();
            using (var vectorOfPoints = new VectorOfPointF(points))
            using (var vectorOfLabels = new VectorOfInt())
            {
                var termCriteria = new MCvTermCriteria(10, 1.0)
                {
                    Type = TermCritType.Iter | TermCritType.Eps
                };
                CvInvoke.Kmeans(vectorOfPoints, k, vectorOfLabels, termCriteria, 10, KMeansInitType.RandomCenters);
                for (int i = 0; i < vectorOfLabels.Size; i++)
                {
                    segments[vectorOfLabels[i]].Add(lines[i]);
                }
            }

            return segments;
        }

        public static IEnumerable<ValueTuple<T, T>> BinaryPair<T>(params IEnumerable<T>[] list)
        {
            if (list.Length < 2)
                throw new Exception("Less than 2 arguments is given.");
            var pairList = new List<ValueTuple<T, T>>();
            for (int i = 0; i < list.Length; i++)
            {
                for (int j = i + 1; j < list.Length; j++)
                {
                    foreach (var item0 in list[i])
                    foreach (var item1 in list[j])
                        yield return (item0, item1);
                }
            }
        }

        public static Point? FindLineIntersection(float r0, float t0, float r1, float t1)
        {
            double a = Math.Cos(t0), b = Math.Sin(t0);
            double c = Math.Cos(t1), d = Math.Sin(t1);
            double e = r0, f = r1;
            var determinant = a * d - b * c;
            if (determinant == 0.0f) return null;
            var x = (e * d - b * f) / determinant;
            var y = (a * f - e * c) / determinant;
            return new Point((int) Math.Round(x), (int) Math.Round(y));
        }

        public static Point? FindLineIntersection(PointF line0, PointF line1) =>
            FindLineIntersection(line0.X, line0.Y, line1.X, line1.Y);
    }
}
Posted
Updated 13-Aug-21 5:00am
v2
Comments
[no name] 13-Aug-21 13:33pm    
If you're the one drawing the lines, then you should maintain a reference to what you draw. Otherwise, I use the BitmapDecoder and PixelDataProvider classes to examine pixels / color in images.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900