一种简单视觉处理

背景

网友说他有个芯片的图,识别不出管脚的位置

俺就写了一个代码,识别管脚的位置,先看结果。

代码

识别图片,并显示结果,对于结果位置使用红色标出

            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;
            else
                return 1.0F * v_std / v;
        }
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

月巴月巴白勺合鸟月半

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值