поиск маркеров в режиме реального времени через web-камеру

Мне нужно найти маркер на изображении с помощью веб-камеры в режиме реального времени. Как это можно сделать на C#? у меня есть web-камера от ps3 и мишень. Нужно что бы камера могла распознать мишень и найти центр. У меня есть код он вроде бы находит маркер, но он ищет не так как надо. Помогите хотя бы словесным алгоритмом введите сюда описание изображения

using AForge.Video;
using AForge.Video.DirectShow;
using System.Drawing.Imaging;

namespace Shooting
{
    public partial class Form1 : Form
    {
        private FilterInfoCollection CaptureDevices;
        private VideoCaptureDevice FinalFrame;
        private bool searchPixels = false;
        private Rectangle? foundMarker = null;

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            CaptureDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);
            foreach (FilterInfo Device in CaptureDevices)
            {
                DeviceNameToolStripMenuItem.Items.Add(Device.Name);
            }
            DeviceNameToolStripMenuItem.SelectedIndex = 0;
            StartVideoImage();
        }

        private void StartVideoImage()
        {
            FinalFrame = new VideoCaptureDevice(CaptureDevices[DeviceNameToolStripMenuItem.SelectedIndex].MonikerString);
            FinalFrame.NewFrame += new NewFrameEventHandler(FinalFrame_NewFrame);
            FinalFrame.Start();
        }

        private void FinalFrame_NewFrame(object sender, NewFrameEventArgs eventArgs)
        {
            /* Bitmap image = (Bitmap)eventArgs.Frame.Clone();
             Bitmap grayscaleImage = MakeGrayscale((Bitmap)image);
             Bitmap binaryImage = Binarize(grayscaleImage, CalculateBlackThreshold(grayscaleImage));
             ProcessImage(binaryImage);*/

            System.Drawing.Image image = (Bitmap)eventArgs.Frame.Clone();

            image = MakeGrayscale((Bitmap)image);

            using (Graphics g = Graphics.FromImage(image))
            {
                int width = image.Width;
                int height = image.Height;


                int thirdWidth = width / 3;
                int thirdHeight = height / 3;

                g.DrawLine(Pens.Red, thirdWidth, 0, thirdWidth, height);
                g.DrawLine(Pens.Red, 2 * thirdWidth, 0, 2 * thirdWidth, height);
                g.DrawLine(Pens.Red, 0, thirdHeight, width, thirdHeight);
                g.DrawLine(Pens.Red, 0, 2 * thirdHeight, width, 2 * thirdHeight);
                int centerX = width / 2;
                int centerY = height / 2;
                g.DrawLine(Pens.Blue, centerX - 10, centerY, centerX + 10, centerY);

                g.DrawLine(Pens.Blue, centerX, centerY - 10, centerX, centerY + 10);
            }

            if (searchPixels)
            {
                ProcessImage((Bitmap)image);
            }

            VideoImage.Image = image;
        }


        private void ProcessImage(Bitmap image)
        {
            Bitmap binaryImage = Binarize(image, CalculateBlackThreshold(image));

            using (Graphics g = Graphics.FromImage(image))
            {
                Rectangle? markerRect = FindMarker(binaryImage);

                if (markerRect.HasValue)
                {

                    if (IsSurroundedByWhite(binaryImage, markerRect.Value))
                    {

                        g.DrawRectangle(Pens.Yellow, markerRect.Value);
                    }
                    /*else
                    {

                        g.DrawRectangle(Pens.Red, markerRect.Value);
                    }*/
                }
            }
        }


        private Rectangle? FindMarker(Bitmap binaryImage)
        {
            int width = binaryImage.Width;
            int height = binaryImage.Height;

            // Определение границ первого квадранта
            int firstQuadrantStartX = 0;
            int firstQuadrantStartY = 0;
            int firstQuadrantEndX = width / 3;
            int firstQuadrantEndY = height / 3;

            // Определение границ девятого квадранта
            int ninthQuadrantStartX = 2 * (width / 3);
            int ninthQuadrantStartY = 2 * (height / 3);
            int ninthQuadrantEndX = width;
            int ninthQuadrantEndY = height;

            int maxDistance = 3;

            // Поиск маркера в девятом квадранте
            Rectangle? foundMarker = SearchInQuadrant(binaryImage, ninthQuadrantStartX, ninthQuadrantStartY, ninthQuadrantEndX, ninthQuadrantEndY, maxDistance);
            if (foundMarker.HasValue)
            {
                return foundMarker;
            }

            // Поиск маркера в первом квадранте
            foundMarker = SearchInQuadrant(binaryImage, firstQuadrantStartX, firstQuadrantStartY, firstQuadrantEndX, firstQuadrantEndY, maxDistance);
            if (foundMarker.HasValue)
            {
                return foundMarker;
            }

            return null;
        }


        private Rectangle? SearchInQuadrant(Bitmap binaryImage, int startX, int startY, int endX, int endY, int maxDistance)
        {
            int? minX = null, minY = null, maxX = null, maxY = null;

            // Поиск последовательностей черных и белых пикселей по строкам
            for (int y = startY; y < endY; y++)
            {
                int currentColor = -1; // -1 означает, что цвет еще не определен
                int count = 0; // Счетчик последовательности
                int lastX = -1;

                for (int x = startX; x < endX; x++)
                {
                    int pixelColor = binaryImage.GetPixel(x, y).R;

                    if (pixelColor != currentColor)
                    {
                        if (currentColor != -1)
                        {
                            // Проверка на черный и белый пиксели
                            if ((currentColor == 0 && pixelColor == 255) || (currentColor == 255 && pixelColor == 0))
                            {
                                count++;
                            }
                            else
                            {
                                count = 1; // Сброс счетчика
                            }
                        }

                        currentColor = pixelColor;
                        lastX = x;

                        // Если нашли последовательность, сохраняем координаты
                        if (count >= 2) // Измените это значение, если нужно
                        {
                            if (!minX.HasValue || x < minX) minX = x;
                            if (!maxX.HasValue || x > maxX) maxX = x;
                            if (!minY.HasValue || y < minY) minY = y;
                            if (!maxY.HasValue || y > maxY) maxY = y;
                        }
                    }
                }
            }

            // Поиск последовательностей черных и белых пикселей по столбцам
            for (int x = startX; x < endX; x++)
            {
                int currentColor = -1;
                int count = 0;
                int lastY = -1;

                for (int y = startY; y < endY; y++)
                {
                    int pixelColor = binaryImage.GetPixel(x, y).R;

                    if (pixelColor != currentColor)
                    {
                        if (currentColor != -1)
                        {
                            // Проверка на черный и белый пиксели
                            if ((currentColor == 0 && pixelColor == 255) || (currentColor == 255 && pixelColor == 0))
                            {
                                count++;
                            }
                            else
                            {
                                count = 1; // Сброс счетчика
                            }
                        }

                        currentColor = pixelColor;
                        lastY = y;

                        // Если нашли последовательность, сохраняем координаты
                        if (count >= 2) // Измените это значение, если нужно
                        {
                            if (!minX.HasValue || x < minX) minX = x;
                            if (!maxX.HasValue || x > maxX) maxX = x;
                            if (!minY.HasValue || y < minY) minY = y;
                            if (!maxY.HasValue || y > maxY) maxY = y;
                        }
                    }
                }
            }

            // Проверка на наличие найденного маркера
            if (minX.HasValue && minY.HasValue && maxX.HasValue && maxY.HasValue)
            {
                return new Rectangle(minX.Value, minY.Value, maxX.Value - minX.Value, maxY.Value - minY.Value);
            }

            return null;
        }


        private Bitmap Binarize(Bitmap original, int threshold)
        {
            Bitmap binarizedBmp = new Bitmap(original.Width, original.Height);
            Rectangle rect = new Rectangle(0, 0, original.Width, original.Height);
            BitmapData originalData = original.LockBits(rect, ImageLockMode.ReadOnly, original.PixelFormat);
            BitmapData binarizedData = binarizedBmp.LockBits(rect, ImageLockMode.WriteOnly, binarizedBmp.PixelFormat);

            unsafe
            {
                byte* originalPtr = (byte*)originalData.Scan0;
                byte* binarizedPtr = (byte*)binarizedData.Scan0;

                for (int y = 0; y < original.Height; y++)
                {
                    for (int x = 0; x < original.Width; x++)
                    {
                        int pixelIndex = y * originalData.Stride + x * 4;
                        byte blue = originalPtr[pixelIndex];
                        byte green = originalPtr[pixelIndex + 1];
                        byte red = originalPtr[pixelIndex + 2];

                        int brightness = (int)(red * 0.3 + green * 0.59 + blue * 0.11);
                        byte newColor = (byte)(brightness >= threshold ? 255 : 0);

                        binarizedPtr[pixelIndex] = newColor;
                        binarizedPtr[pixelIndex + 1] = newColor;
                        binarizedPtr[pixelIndex + 2] = newColor;
                        binarizedPtr[pixelIndex + 3] = 255;
                    }
                }
            }

            original.UnlockBits(originalData);
            binarizedBmp.UnlockBits(binarizedData);
            return binarizedBmp;
        }

        private int CalculateBlackThreshold(Bitmap image)
        {
            double averageBrightness = CalculateAverageBrightness(image);
            double standardDeviation = CalculateStandardDeviation(image, averageBrightness);
            return (int)(averageBrightness - 2 * standardDeviation);
        }
        private double CalculateAverageBrightness(Bitmap image)
        {
            int sumBrightness = 0;
            int count = 0;

            for (int y = 0; y < image.Height; y++)
            {
                for (int x = 0; x < image.Width; x++)
                {
                    Color pixelColor = image.GetPixel(x, y);
                    int brightness = (int)(pixelColor.R * 0.3 + pixelColor.G * 0.59 + pixelColor.B * 0.11);
                    sumBrightness += brightness;
                    count++;
                }
            }

            return (double)sumBrightness / count;
        }

        private double CalculateStandardDeviation(Bitmap image, double averageBrightness)
        {
            double sumSquaredDifference = 0;
            int count = 0;

            for (int y = 0; y < image.Height; y++)
            {
                for (int x = 0; x < image.Width; x++)
                {
                    Color pixelColor = image.GetPixel(x, y);
                    int brightness = (int)(pixelColor.R * 0.3 + pixelColor.G * 0.59 + pixelColor.B * 0.11);
                    double squaredDifference = Math.Pow(brightness - averageBrightness, 2);
                    sumSquaredDifference += squaredDifference;
                    count++;
                }
            }

            return Math.Sqrt(sumSquaredDifference / count);
        }

        public Bitmap MakeGrayscale(Bitmap original)
        {
            Bitmap newBmp = new Bitmap(original.Width, original.Height);
            using (Graphics g = Graphics.FromImage(newBmp))
            {
                ColorMatrix colorMatrix = new ColorMatrix(new float[][]
                {
                        new float[] {0.3f, 0.3f, 0.3f, 0, 0},
                        new float[] {0.59f, 0.59f, 0.59f, 0, 0},
                        new float[] {0.11f, 0.11f, 0.11f, 0, 0},
                        new float[] {0, 0, 0, 1, 0},
                        new float[] {0, 0, 0, 0, 1}
                });

                ImageAttributes imgAttr = new ImageAttributes();
                imgAttr.SetColorMatrix(colorMatrix);
                g.DrawImage(original, new Rectangle(0, 0, original.Width, original.Height),
                    0, 0, original.Width, original.Height, GraphicsUnit.Pixel, imgAttr);
            }

            return newBmp;
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (FinalFrame != null)
            {
                if (FinalFrame.IsRunning)
                {
                    FinalFrame.SignalToStop();
                    FinalFrame.WaitForStop();
                }
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            searchPixels = true;
        }

        private void BlackThresholdTrackBar_Scroll(object sender, EventArgs e)
        {

        }

        private bool IsSurroundedByWhite(Bitmap binaryImage, Rectangle marker)
        {
            bool isInFirstQuadrant = marker.Left < binaryImage.Width / 3 && marker.Top < binaryImage.Height / 3;
            bool isInNinthQuadrant = marker.Left >= 2 * (binaryImage.Width / 3) && marker.Top >= 2 * (binaryImage.Height / 3);

            if (isInFirstQuadrant)
            {
                // Проверка для первого квадранта
                for (int x = marker.Left; x <= marker.Right; x++)
                {
                    if (x < 0 || x >= binaryImage.Width) continue;
                    if (binaryImage.GetPixel(x, marker.Bottom + 1).R == 0) return false; // Проверка снизу
                }

                for (int y = marker.Top; y <= marker.Bottom; y++)
                {
                    if (marker.Right + 1 >= binaryImage.Width) return false;
                    if (binaryImage.GetPixel(marker.Right + 1, y).R == 0) return false; // Проверка справа
                }
            }
            else if (isInNinthQuadrant)
            {
                // Проверка для девятого квадранта
                if (marker.Top > 0)
                {
                    for (int x = marker.Left - 1; x <= marker.Right + 1; x++)
                    {
                        if (x < 0 || x >= binaryImage.Width) continue;
                        if (binaryImage.GetPixel(x, marker.Top - 1).R == 0) return false; // Проверка сверху
                    }
                }

                if (marker.Bottom + 1 < binaryImage.Height)
                {
                    for (int x = marker.Left - 1; x <= marker.Right + 1; x++)
                    {
                        if (x < 0 || x >= binaryImage.Width) continue;
                        if (binaryImage.GetPixel(x, marker.Bottom + 1).R == 0) return false; // Проверка снизу
                    }
                }

                if (marker.Left > 0)
                {
                    for (int y = marker.Top; y <= marker.Bottom; y++)
                    {
                        if (marker.Left - 1 < 0) return false;
                        if (binaryImage.GetPixel(marker.Left - 1, y).R == 0) return false; // Проверка слева
                    }
                }

                if (marker.Right + 1 < binaryImage.Width)
                {
                    for (int y = marker.Top; y <= marker.Bottom; y++)
                    {
                        if (marker.Right + 1 >= binaryImage.Width) return false;
                        if (binaryImage.GetPixel(marker.Right + 1, y).R == 0) return false; // Проверка справа
                    }
                }
            }
            else
            {
                // Проверка для других квадрантов (если необходимо)
                if (marker.Top > 0)
                {
                    for (int x = marker.Left - 1; x <= marker.Right + 1; x++)
                    {
                        if (x < 0 || x >= binaryImage.Width) continue;
                        if (binaryImage.GetPixel(x, marker.Top - 1).R == 0) return false; // Проверка сверху
                    }
                }

                if (marker.Bottom + 1 < binaryImage.Height)
                {
                    for (int x = marker.Left - 1; x <= marker.Right + 1; x++)
                    {
                        if (x < 0 || x >= binaryImage.Width) continue;
                        if (binaryImage.GetPixel(x, marker.Bottom + 1).R == 0) return false; // Проверка снизу
                    }
                }

                if (marker.Left > 0)
                {
                    for (int y = marker.Top; y <= marker.Bottom; y++)
                    {
                        if (marker.Left - 1 < 0) return false;
                        if (binaryImage.GetPixel(marker.Left - 1, y).R == 0) return false; // Проверка слева
                    }
                }

                if (marker.Right + 1 < binaryImage.Width)
                {
                    for (int y = marker.Top; y <= marker.Bottom; y++)
                    {
                        if (marker.Right + 1 >= binaryImage.Width) return false;
                        if (binaryImage.GetPixel(marker.Right + 1, y).R == 0) return false; // Проверка справа
                    }
                }
            }

            return true;
        }


    }
}

Ответы (0 шт):