поиск маркеров в режиме реального времени через 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;
}
}
}