背景
网友说他有个芯片的图,识别不出管脚的位置
俺就写了一个代码,识别管脚的位置,先看结果。
代码
识别图片,并显示结果,对于结果位置使用红色标出
PT pt = new PT();pt.Find(bmp);Bitmap bmp_tmp = new Bitmap(bmp);Graphics g = Graphics.FromImage(bmp_tmp);StringBuilder sb = new StringBuilder();foreach (PtRec r in pt.Result){g.DrawRectangle(Pens.Red, new Rectangle(r.x1, r.y1, r.x2- r.x1+1, r.y2 - r.y1+1));sb.AppendLine(((r.x1 + r.x2) / 2).ToString() + "," + ((r.y1 + r.y2) / 2).ToString() + " Score:" + (r.v * 100).ToString("0.0"));} g.Dispose(); pictureBox1.Image = bmp_tmp;textBox1.Text = sb.ToString();
识别的处理在class PT中
public void Find(Bitmap bmp)
{
Result.Clear();
Bmp2Array(bmp);
Proc();
}
Bmp2Array 将图片转化为灰度二维数组
Proc 计算管脚的位置
private void Proc()
{
x_a = new int[Width * Height];
y_a = new int[Width * Height];
for (int y = step_len + 1; y < Height - step_len - 1; y++)
for (int x = step_len + 1; x < Width - step_len - 1; x++)
{
if (array[y, x] < max_gv)
{
PtRec r = new PtRec() { x1 = x, y1 = y, x2 = x, y2 = y, cnt = 0 };
Fill(x, y, r);
r.Check();
if (r.v>0.6)
Result.Add(r);
}
}
}
使用Fill计出所有的区域,然后计算区域的符合度,v>0.6 添加到结果中。
r.Check 是计算符合度的函数
public void Check()
{
int w = x2 - x1+1;
int h = y2 - y1 + 1;
int v1 = cnt * 100 / (w * h);
int v2 = w * h;
int v1_std = 80;
int v2_std = 288;
v = get_v(v1, v1_std) * get_v(v2, v2_std);
}
public float get_v(int v, int v_std)
{
if (v * v_std == 0)
return 0;
if (v < v_std)
return 1.0F *v / v_std;
else
return 1.0F * v_std / v;
}
这里有2个参数 ,v1_std = 80 和 v2_std = 288 对于不同大小的图像可以修改这里。
或者只用v1_std = 80 这个参数,就和图像大小无关了。不过另外需要加一个过滤,把特别小的和特别大的区域过滤掉,例如过滤掉
- 宽度 小于 图片宽度 1%的区域
- 高度 小于 图片宽度 1%的区域
- 宽度 大于 图片宽度 15%的区域
- 高度 大于 图片宽度 15%的区域
主要的计算在private void Fill(int x, int y, PtRec r) 中
private void Fill(int x, int y, PtRec r)
{
c_a_last = 0;
c_a = 1;
x_a[0] = x;
y_a[0] = y;
int xi, yi;
while (c_a > c_a_last)
{
int c = c_a;
for (int i = c_a_last; i < c_a; i++)
{
foreach (Point pt in step)
{
xi = x_a[i] + pt.X;
yi = y_a[i] + pt.Y;
if (xi < 0)
continue;
if (yi < 0)
continue;
if (xi >= Width)
continue;
if (yi >= Height)
continue;
if (array[yi, xi] < max_gv)
{
if (yi < r.y1)
r.y1 = yi;
if (yi > r.y2)
r.y2 = yi;
if (xi < r.x1)
r.x1 = xi;
if (xi > r.x2)
r.x2 = xi;
array[yi, xi] = 255;
r.cnt = r.cnt + 1;
x_a[c] = xi;
y_a[c] = yi;
c++;
}
}
}
c_a_last = c_a;
c_a = c;
}
}
全部代码如下:
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Text;
using System.Threading.Tasks;namespace ImgPT
{public class PT{public void Find(Bitmap bmp){Result.Clear();Bmp2Array(bmp);Proc();}private void Proc(){x_a = new int[Width * Height];y_a = new int[Width * Height];for (int y = step_len + 1; y < Height - step_len - 1; y++)for (int x = step_len + 1; x < Width - step_len - 1; x++){if (array[y, x] < max_gv){PtRec r = new PtRec() { x1 = x, y1 = y, x2 = x, y2 = y, cnt = 0 };Fill(x, y, r);r.Check();if (r.v>0.6)Result.Add(r); }}}public int[] x_a;public int[] y_a;public int c_a_last;public int c_a;private void Fill(int x, int y, PtRec r){c_a_last = 0;c_a = 1;x_a[0] = x;y_a[0] = y;int xi, yi;while (c_a > c_a_last){int c = c_a;for (int i = c_a_last; i < c_a; i++){foreach (Point pt in step){xi = x_a[i] + pt.X;yi = y_a[i] + pt.Y;if (xi < 0)continue;if (yi < 0)continue;if (xi >= Width)continue;if (yi >= Height)continue;if (array[yi, xi] < max_gv){if (yi < r.y1)r.y1 = yi;if (yi > r.y2)r.y2 = yi;if (xi < r.x1)r.x1 = xi;if (xi > r.x2)r.x2 = xi;array[yi, xi] = 255;r.cnt = r.cnt + 1;x_a[c] = xi;y_a[c] = yi;c++;}}}c_a_last = c_a;c_a = c;}}private static int max_gv = 128;private static int step_len =2;private static List<Point> step = make_step();private static List<Point> make_step(){List<Point> list = new List<Point>();for (int y = -step_len; y <= step_len; y++)for (int x = -step_len; x <= step_len; x++){if ((y == 0) && (x == 0))continue;list.Add(new Point(x, y));}return list;}private void Bmp2Array(Bitmap v){Width = v.Width;Height = v.Height;array = new int[Height, Width];Bitmap bmp = new Bitmap(v.Width, v.Height, PixelFormat.Format24bppRgb);Graphics g = Graphics.FromImage(bmp);g.DrawImage(v, 0, 0);g.Dispose();BitmapData bmpdata = bmp.LockBits(new Rectangle(0, 0, Width, Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);int len = bmpdata.Stride;byte[] buff = new byte[len];int idx = 0;byte blue, green, red, gv;for (int y = 0; y < Height; y++){IntPtr p = bmpdata.Scan0 + len * y;System.Runtime.InteropServices.Marshal.Copy(p, buff, 0, len);for (int x = 0; x < Width; x++){idx = x * 3;blue = buff[idx];green = buff[idx + 1];red = buff[idx + 2];gv = (byte)(0.229 * red + 0.587 * green + 0.144 * blue);array[y, x] = gv;}}bmp.UnlockBits(bmpdata);bmp.Dispose();}private int Width;private int Height;private int[,] array;public List<PtRec> Result = new List<PtRec>();}public class PtRec{public int x1;public int y1;public int x2;public int y2;public int cnt = 0;public float v = 0;public void Check(){int w = x2 - x1+1;int h = y2 - y1 + 1;int v1 = cnt * 100 / (w * h);int v2 = w * h;int v1_std = 80;int v2_std = 288;v = get_v(v1, v1_std) * get_v(v2, v2_std);}public float get_v(int v, int v_std){if (v * v_std == 0)return 0;if (v < v_std)return 1.0F *v / v_std;elsereturn 1.0F * v_std / v;}}
}