128x32.png?
?
/*
工业视觉_79:猫眼识别演示[先异或再求和]
未来20~50年里,机器换人,强化视觉功能的机器人,改造传统工厂成智慧工厂,将成为最火的行业之一.
工业视觉,目标很明确:"快,准,稳"三个字. 快:开发快,运行速度快;准:高精度;稳:稳健可靠
使用高级语言做工程主要优势在:已经有丰富的数据结构和成熟的类型库,如List,Dictionary,Lambda,Accord,...
所以,目前"机器换人"项目大多采用工控电脑,搭建 Windows7+VS2019+Emgu(或AForge+Accord),这一方案见效最快.
Halcon,Emgu的视觉库都很强大,而AForge+Accord库也很全面,内容更丰富(如:数学,人工智能,机器学习).
识别与匹配,在大多情况下用AI训练,生成概率云.也可通过特征向量与最小二乘法的进行匹配的.
在诸多场合,要识别特有对象,如敌人的眼睛\双手,或工业中的零部件.作为原理的理解,可参考本文.
要实现高速地匹配与识别,或运用GPU,FPGA,或制作特定的芯片.速度与精度是永恒的目标!
所有相机,均要做好纠偏与标定等工作,以便与机器人进行精确匹配.
本文系作者在"安吉八塔机器人公司"产品线研发中的拓展与随笔.
[已经发布,链接:...]
--------- 编撰: 项道德(微信:daode1212),2021-07-27
*/
//一,基本图片与工具准备:###########################################################
pictureBox1.Image = Image.FromFile("2D_727.jpg");
MSG("猫眼识别演示[先异或再求和]");
Bitmap bmp = (Bitmap)(pictureBox1.Image);
int ww = bmp.Width, hh = bmp.Height;
string txtAll = "找到的匹配坐标:\r\n";
Graphics g = Graphics.FromImage(bmp);
SolidBrush bh0 = new SolidBrush(Color.FromArgb(0, 0, 0));
SolidBrush bh1 = new SolidBrush(Color.FromArgb(161, 0, 161));
SolidBrush bh2 = new SolidBrush(Color.FromArgb(255, 255, 0));
SolidBrush bh3 = new SolidBrush(Color.FromArgb(255, 255, 255));
Pen pen0 = new Pen(Color.FromArgb(182, 122, 182), 1);
Pen pen1 = new Pen(Color.FromArgb(255, 122, 0), 1);
Pen pen2 = new Pen(Color.FromArgb(0, 110, 255), 1);
Pen pen3 = new Pen(Color.FromArgb(0, 55, 180), 4);
var Gry = new Accord.Imaging.Filters.Grayscale(0.2, 0.5, 0.1).Apply(bmp);//灰度化
Bitmap bmp2 = new Accord.Imaging.Filters.Threshold(40).Apply(Gry);//位图处理呈现:二值化
var Eros = new Accord.Imaging.Filters.Erosion3x3().Apply(bmp2);//腐蚀:黑色点扩大
pictureBox1.Image = Eros;
MSG("位图已经处理:灰度化 --> 二值化 --> 腐蚀");
//二,读取猫眼模板,每一种眼睛大小:32x32,有四只眼睛:128x32:
Bitmap eye4 = (Bitmap)Bitmap.FromFile("128x32.png");
bool[,] MX = new bool[128, 32];
unsafe
{
BitmapData data = eye4.LockBits(new System.Drawing.Rectangle(0, 0, eye4.Width, eye4.Height),
ImageLockMode.ReadOnly,
System.Drawing.Imaging.PixelFormat.Format8bppIndexed);
var ptr = (byte*)data.Scan0.ToPointer();
int wBit = data.Stride;
for (int j = 0; j < data.Width; j++)
{
for (int i = 0; i < data.Height; i++)
{
byte rr = ptr[i * wBit + j];
MX[j, i] = rr == 0 ? false : true;
}
}
eye4.UnlockBits(data);
}
//三,在位图中搜索猫眼的存在性与位置:
List<Point> LP1 = new List<Point>();
unsafe
{
BitmapData data = Eros.LockBits(new System.Drawing.Rectangle(0, 0, Eros.Width, Eros.Height),
ImageLockMode.ReadOnly,
System.Drawing.Imaging.PixelFormat.Format8bppIndexed);
var ptr = (byte*)data.Scan0.ToPointer();
int wBit = data.Stride;
int xx, yy, x3, y3;
bool rBmp, rMx;
// Parallel.For(16, data.Height - 16, y =>{...}0;
for (int y = 16; y < data.Height - 16; y++)
{
for (int x = 16; x < data.Width - 16; x++)
{
//针对横向四个猫眼:
for (int k = 0; k < 4; k++)
{
int M = 0;//每一次求和.
for (int y2 = -16; y2 < 16; y2++)
{
for (int x2 = -16; x2 < 16; x2++)
{
//在源位图中取出相应的点:
xx = x + x2;
yy = y + y2;
rBmp = ptr[yy * wBit + xx] == 0 ? false : true;
//在矩阵中取出相应的元素:
x3 = 32 * k + x2 + 16;
y3 = y2 + 16;
rMx = MX[x3, y3];
//异或运算后求和:
M += (rBmp ^ rMx == true ? 1 : 0);
if (M >= 50) break;
}
if (M >= 50) break;
}
if (M < 50)//不相同的点在60以内
{
LP1.Add(new Point(x, y));
}
}
}
}
Eros.UnlockBits(data);
}
MSG("OK, LP1.Count=" + LP1.Count());
//四,显示结果,在猫眼处绘制:
foreach (var p in LP1)
{
g.FillEllipse(bh2, p.X - 4, p.Y - 4, 8, 8);
g.DrawEllipse(pen3, p.X - 14, p.Y - 14, 28, 28);
}
textBox1.Text = txtAll + string.Join("\r\n", LP1.ToArray());
pictureBox1.Image = bmp;
?
|