Question about emgu library

payam1363

Member
Joined
Jun 23, 2021
Messages
7
Programming Experience
Beginner
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)

and can see main lines of Form1.cs
form1:
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();
                }
            }
        }
    }
}


and these are codes of lineutil.cs
lineutil:
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);
    }
}
 

Skydiver

Staff member
Joined
Apr 6, 2019
Messages
4,445
Location
Chesapeake, VA
Programming Experience
10+
Do some image pre-processing beyond your current pre-processing of just converting to gray-scale. If you absolutely know that you are targeting only white lines, perhaps run the image through a high band pass filter that only lets white and other very light colors through. Alternatively you can try increasing the contrast on the image first. Personally, I would go with the filtering.
 

payam1363

Member
Joined
Jun 23, 2021
Messages
7
Programming Experience
Beginner
Do some image pre-processing beyond your current pre-processing of just converting to gray-scale. If you absolutely know that you are targeting only white lines, perhaps run the image through a high band pass filter that only lets white and other very light colors through. Alternatively you can try increasing the contrast on the image first. Personally, I would go with the filtering.
thanks for your reply
i will increase the contrast
what is the next step?
what is your idea about targeting only white lines ?
 

Skydiver

Staff member
Joined
Apr 6, 2019
Messages
4,445
Location
Chesapeake, VA
Programming Experience
10+
Re-read post #2. You even quoted it, but it seems like you did not really read it.
 
Top Bottom