1. 程式人生 > >PCB Polar SI9000阻抗模型圖片文字識別方法

PCB Polar SI9000阻抗模型圖片文字識別方法

build lin ray 最大 return http range rpo view

用過Polar SI9000的都知道,阻抗模型圖片可以進行用戶鼠標交互,那麽它的是如何實現的呢,下面就講一下如何實現此功能的方法

一.看看Polar SI9000阻抗模型圖片交互效果

鼠標點擊阻抗模型圖片某個像素點, 它可以實現找到離它最近的阻抗參數的文字並用紅色框選出來, 並且可以識別文字是哪一個阻抗參數.

技術分享圖片

二.解決方法思路

解決方法一:

1.將每一種阻抗模型圖片中的所有參數在圖片中的位置區域信息與參數值記錄到數據庫中

2.鼠標點擊阻抗模型的坐標位置後,再進與數據庫中的參數坐標位置匹配

這樣就可以實現與Polar阻抗軟件相同的效果,但是Polar SI9000有阻抗計算模型93種,要實現的話工作量可不小,所以這種方法排除了。

解決方法二(采用此方法實現):

1.找最近鄰----點擊像素點位置,找出離它最近的一個黑色像素點位置

2.聚類----通過一個像素點查找周邊相鄰的黑色像素點進行聚類

3.識別---截取指定區域文字圖片與圖像Ocr識別

三.找最近鄰----點擊像素點位置,找出離它最近的一個黑色像素點位置

1.【圈】的遍歷方式按下圖方式進行

以鼠標點擊像素的位置,向像素四周搜索黑色像素點,依次遍歷第1圈,第2圈,第3圈.....直到找到黑色像素則終止

技術分享圖片

2.【段】的遍歷方式按下圖方式進行

技術分享圖片

3.C#代碼實現,鼠標點擊像素點位置,找出離它最近的黑色像素點

        /// <summary>
        /// 通過鼠標點擊像素點位置,找出離它最近的一個黑色像素點位置
        /// </summary>
        /// <param name="MousePoint"></param>
        /// <param name="ArrayBitmap"></param>
        /// <returns></returns>
        private
Point ArrayLoop(Point MousePoint, Bitmap ArrayBitmap) { Point ClacBlackPoint = new Point(); Color pixel = ArrayBitmap.GetPixel(MousePoint.X, MousePoint.Y); if (pixel.R <= 25 && pixel.G <= 40 && pixel.B <= 60) { return MousePoint; } Point ArraySum = new Point(ArrayBitmap.Size); int[,] ArrayLoopType = new int[,] { { 1, 1 }, { -1, 1 }, { -1, -1 }, { 1, -1 } }; //偏移位移矩陣數組 int LoopLength = getArrayLoopMax(MousePoint, ArraySum);//遍歷的圈數計算 int ArayLength = ArrayLoopType.GetLength(0);//計算值為4 for (int k = 1; k <= LoopLength; k++) //按圈遍歷 { Point LoopPoint = MousePoint; LoopPoint.Offset(0, -k);//更新圈的起點像素坐標 for (int i = 0; i < ArayLength; i++)//每圈分為4段遍歷 { for (int j = 0; j < k; j++) { LoopPoint.X += ArrayLoopType[i, 0]; LoopPoint.Y += ArrayLoopType[i, 1]; if (LoopPoint.X > 0 && LoopPoint.Y > 0 && LoopPoint.X <= ArraySum.X && LoopPoint.Y <= ArraySum.Y)// { pixel = ArrayBitmap.GetPixel(LoopPoint.X - 1, LoopPoint.Y - 1); if (pixel.R <= 25 && pixel.G <= 40 && pixel.B <= 60) { ClacBlackPoint = LoopPoint; goto L1; } } } } } L1: return ClacBlackPoint; } /// <summary> /// 獲取遍歷圈數最大值 /// </summary> /// <param name="MousePoint"></param> /// <param name="ArraySum"></param> /// <param name="LoopType"></param> /// <returns></returns> private int getArrayLoopMax(Point MousePoint, Point ArraySum, int LoopType = 1) { int LoopLength = 0; if (LoopType == 1) { int TopLeft = (MousePoint.X - 1 + MousePoint.Y - 1); int TopRight = (ArraySum.X - MousePoint.X + MousePoint.Y - 1); int TopMax = Math.Max(TopLeft, TopRight); int BootomLeft = (MousePoint.X - 1 + ArraySum.Y - MousePoint.Y); int BottomRight = (ArraySum.X - MousePoint.X + ArraySum.Y - MousePoint.Y); int BottomMax = Math.Max(BootomLeft, BottomRight); LoopLength = Math.Max(TopMax, BottomMax); } else { int MaxX = Math.Max(MousePoint.X - 1, ArraySum.X - MousePoint.X); int MaxY = Math.Max(MousePoint.Y - 1, ArraySum.Y - MousePoint.Y); LoopLength = Math.Max(MaxX, MaxY); } return LoopLength; }

.聚類----通過一個像素點查找周邊相鄰的黑色像素點進行聚類

1.聚類實現方法按下圖進行

技術分享圖片

2.C#代碼實現,通過一個像素點查找周邊相鄰的黑色像素點進行聚類為一個矩形區域

        /// <summary>
        /// 通過一個像素點查找周邊相鄰的黑色像素點進行聚類為一個矩形區域
        /// </summary>
        /// <param name="CalcPoint"></param>
        /// <param name="ArrayBitmap"></param>
        /// <returns></returns>
        private RangePoint RangeArea(Point CalcPoint, Bitmap ArrayBitmap)
        {
            int LoopLength = 10; //搜索周邊相鄰像素個數
            int[,] ArrayLoopType = new int[,] { { 1, 1 }, { -1, 1 }, { -1, -1 }, { 1, -1 } };
            Point ArraySum = new Point(ArrayBitmap.Size);
            RangePoint RangePointArea = new RangePoint(CalcPoint, CalcPoint);
            HashSet<Point> PointSet = new HashSet<Point>();
            HashSet<Point> LoopPointSet = new HashSet<Point>();
            Queue<Point> PointQueue = new Queue<Point>();
            PointQueue.Enqueue(CalcPoint);
            while (PointQueue.Count > 0)
            {
                var TopPoint = PointQueue.Dequeue();  //TopPoint 以這個點周邊範圍進行搜索像素
                for (int k = 1; k <= LoopLength; k++)
                {
                    Point LoopPoint = TopPoint;
                    LoopPoint.Offset(0, -k);
                    for (int i = 0; i < 4; i++)
                    {
                        for (int j = 0; j < k; j++)
                        {
                            LoopPoint.X += ArrayLoopType[i, 0];
                            LoopPoint.Y += ArrayLoopType[i, 1];
                            if (!LoopPointSet.Contains(LoopPoint))
                            {
                                LoopPointSet.Add(LoopPoint);
                                if (LoopPoint.X > 0 && LoopPoint.Y > 0 && LoopPoint.X <= ArraySum.X && LoopPoint.Y <= ArraySum.Y)
                                {
                                    Color pixel = ArrayBitmap.GetPixel(LoopPoint.X - 1, LoopPoint.Y - 1);
                                    if (pixel.R <= 25 && pixel.G <= 40 && pixel.B <= 60)
                                    {
                                        if (!PointSet.Contains(LoopPoint))
                                        {
                                            //找到相似的黑色像素加入隊列
                                            PointQueue.Enqueue(LoopPoint);
                                            //將周邊相似相素 進行擴大合並區域
                                            RangePointArea = RangePointArea.Union(LoopPoint);
                                            //加入字典
                                            PointSet.Add(TopPoint);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
            return RangePointArea;
        }

RangePoint Mod類

技術分享圖片
    /// <summary>
    /// 範圍區域點
    /// </summary>
    public class RangePoint
    {
        public RangePoint(Point MinPoint, Point MaxPoint)
        {
            RangeMinPoint = MinPoint;
            RangeMaxPoint = MaxPoint;
        }
        /// <summary>
        /// 最小點
        /// </summary>
        public Point RangeMinPoint { get; set; }
        /// <summary>
        /// 最大點
        /// </summary>
        public Point RangeMaxPoint { get; set; }
        /// <summary>
        /// 範圍寬
        /// </summary>
        public int Width
        {
            get {  return this.RangeMaxPoint.X - this.RangeMinPoint.X + 1; }
        }
        /// <summary>
        /// 範圍高
        /// </summary>
        public int Height
        {
            get { return this.RangeMaxPoint.Y - this.RangeMinPoint.Y + 1; }
        }
        /// <summary>
        /// 合拼區域
        /// </summary>
        /// <param name="point"></param>
        /// <returns></returns>
        public RangePoint Union(Point point)
        {
            Point minP = RangeMinPoint;
            Point MaxP = RangeMaxPoint;
            if (point.X < minP.X)
                minP.X = point.X;
            if (point.Y < minP.Y)
                minP.Y = point.Y;
            if (point.X > MaxP.X)
                MaxP.X = point.X;
            if (point.Y > MaxP.Y)
                MaxP.Y = point.Y;
            RangeMinPoint = minP;
            RangeMaxPoint = MaxP;
            return this;
        }
        /// <summary>
        /// 檢測點是否在區域內
        /// </summary>
        /// <param name="point"></param>
        /// <returns></returns>
        public bool IsRangeInner(Point point)
        {
            return (RangeMinPoint.X <= point.X && RangeMinPoint.Y <= point.Y && RangeMaxPoint.X >= point.X && RangeMaxPoint.Y >= point.Y);
        }
        /// <summary>
        /// 獲得區域中心點
        /// </summary>
        /// <param name="point"></param>
        /// <returns></returns>
        public Point getRangeCenterPoint()
        {
            return new Point((int)((this.RangeMinPoint.X + this.RangeMaxPoint.X) * 0.5), (int)((this.RangeMinPoint.Y + this.RangeMaxPoint.Y) * 0.5));
        }
        /// <summary>
        /// 區域偏移 擴大縮小
        /// </summary>
        /// <param name="point"></param>
        /// <returns></returns>
        public RangePoint RangeOffset(int OffsetVal)
        {
            this.RangeMinPoint = new Point(this.RangeMinPoint.X - OffsetVal, this.RangeMinPoint.Y - OffsetVal);
            this.RangeMaxPoint = new Point(this.RangeMaxPoint.X + OffsetVal, this.RangeMaxPoint.Y + OffsetVal);
            return this;
        }
    }
View Code

五.識別---截取指定區域文字圖片與圖像識別

1.通過聚類識別出文本區域坐標進行圖像截取,並將截取出來的圖像進行圖像識別轉文字.

技術分享圖片

2.C#代碼實現,截取指定區域文字圖片與圖像識別

此圖像識別用Baidu它們家的Ocr API自己註冊一下就能用了,另外一個Tesseract也不錯的,可以自行對Ocr字體模型訓練,最主要是可以實現本地不聯網的情況下也可以Ocr識別

        /// <summary>
        /// 獲取圖片指定部分
        /// </summary>
        /// <param name="pPath">圖片路徑</param>
        /// <param name="pOrigStartPointX">原始圖片開始截取處的坐標X值</param>
        /// <param name="pOrigStartPointY">原始圖片開始截取處的坐標Y值</param>
        /// <param name="pPartWidth">目標圖片的寬度</param>
        /// <param name="pPartHeight">目標圖片的高度</param>
        static System.Drawing.Bitmap GetPart(Image originalImg, int pOrigStartPointX, int pOrigStartPointY, int pPartWidth, int pPartHeight)
        {
            System.Drawing.Bitmap partImg = new System.Drawing.Bitmap(pPartWidth, pPartHeight);
            System.Drawing.Graphics graphics = System.Drawing.Graphics.FromImage(partImg);
            System.Drawing.Rectangle destRect = new System.Drawing.Rectangle(new System.Drawing.Point(0, 0), new System.Drawing.Size(pPartWidth, pPartHeight));//目標位置
            System.Drawing.Rectangle origRect = new System.Drawing.Rectangle(new System.Drawing.Point(pOrigStartPointX, pOrigStartPointY), new System.Drawing.Size(pPartWidth, pPartHeight));//原圖位置(默認從原圖中截取的圖片大小等於目標圖片的大小)
            graphics.DrawImage(originalImg, destRect, origRect, System.Drawing.GraphicsUnit.Pixel);
            return partImg;
        }
       /// <summary>
        /// Baidu Ocr識別
        /// </summary>
        /// <param name="img"></param>
        /// <returns></returns>
        private string OcrGeneralBasic(Image img)
        {
            StringBuilder OcrTxt = new StringBuilder();
            string baiduAPI_ID = "baiduAPI_ID";
            string baiduAPI_key = "baiduAPI_key";
            Baidu.Aip.Ocr.Ocr OcrClient = new Baidu.Aip.Ocr.Ocr(baiduAPI_ID, baiduAPI_key);
            var byteImg = Img2Byte(img);
            var OcrResult = OcrClient.GeneralBasic(byteImg);
            var words_result = OcrResult["words_result"];
            if (words_result == null) return "";
            foreach (var item in words_result)
            {
                OcrTxt.AppendLine(item["words"].ToString());
            }
            return OcrTxt.ToString();
        }
        /// <summary>
        /// 將Image轉換成為byte[] 
        /// </summary>
        /// <param name="img"></param>
        /// <returns></returns>
        public byte[] Img2Byte(System.Drawing.Image img)
        {
            MemoryStream mstream = new MemoryStream();
            img.Save(mstream, System.Drawing.Imaging.ImageFormat.Bmp);
            byte[] byData = new Byte[mstream.Length];
            mstream.Position = 0;
            mstream.Read(byData, 0, byData.Length); mstream.Close();
            return byData;
        }

六.實現效果圖

技術分享圖片

七.其它問題解決方法

1.PictureBox控件顯示圖片尺寸與實際圖片尺寸不一致,會造成PictureBox控件上的鼠標點擊像素點位置,並不是實際圖片像素點位置,這裏給出2種解決方法

方法一.在讀入Bitmap圖片前提前轉換(縮放)圖片尺寸和PictureBox控件尺寸一致

技術分享圖片
        /// <summary>
        /// 圖片縮放
        /// </summary>
        /// <param name="bmp"></param>
        /// <param name="newW"></param>
        /// <param name="newH"></param>
        /// <returns></returns>
        public static Bitmap KiResizeImage(Bitmap bmp, int newW, int newH)
        {
            try
            {
                Bitmap newBitmap = new Bitmap(newW, newH);
                Graphics g = Graphics.FromImage(newBitmap);
                g.InterpolationMode = InterpolationMode.HighQualityBicubic;
                g.DrawImage(bmp, new Rectangle(0, 0, newW, newH), new Rectangle(0, 0, bmp.Width, bmp.Height), GraphicsUnit.Pixel);
                g.Dispose();
                return newBitmap;
            }
            catch
            {
                return null;
            }
        }
View Code

方法二.計算PictureBox圖像大小與真實圖像大小的比值關系,通過鼠標點擊像素位置與屏幕位置的關系,計算得鼠標真實點擊的圖像像素位置

技術分享圖片
        /// <summary>
        /// 鼠標移動  查看鼠標位置與實際圖片和顯示圖片關系
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void picBox_MouseMove(object sender, MouseEventArgs e)
        {
            PictureBox  picBox = (PictureBox)sender;
            int originalWidth = picBox.Image.Width;
            int originalHeight = picBox.Image.Height;
            PropertyInfo rectangleProperty = picBox.GetType().GetProperty("ImageRectangle", BindingFlags.Instance | BindingFlags.NonPublic);
            Rectangle rectangle = (Rectangle)rectangleProperty.GetValue(picBox, null);
            int currentWidth = rectangle.Width;
            int currentHeight = rectangle.Height;
            double rate = (double)currentHeight / (double)originalHeight;
            int black_left_width = (currentWidth == picBox.Width) ? 0 : (picBox.Width - currentWidth) / 2;
            int black_top_height = (currentHeight == picBox.Height) ? 0 : (picBox.Height - currentHeight) / 2;
            int zoom_x = e.X - black_left_width;
            int zoom_y = e.Y - black_top_height;
            double original_x = (double)zoom_x / rate;
            double original_y = (double)zoom_y / rate;
            StringBuilder sb = new StringBuilder();
            sb.AppendFormat("原始尺寸{0}/{1}(寬/高)\r\n", originalWidth, originalHeight);
            sb.AppendFormat("縮放狀態圖片尺寸{0}/{1}(寬/高)\r\n", currentWidth, currentHeight);
            sb.AppendFormat("縮放比率{0}\r\n", rate);
            sb.AppendFormat("左留白寬度{0}\r\n", black_left_width);
            sb.AppendFormat("上留白高度{0}\r\n", black_top_height);
            sb.AppendFormat("當前鼠標坐標{0}/{1}(X/Y)\r\n", e.X, e.Y);
            sb.AppendFormat("縮放圖中鼠標坐標{0}/{1}(X/Y)\r\n", zoom_x, zoom_y);
            sb.AppendFormat("原始圖中鼠標坐標{0}/{1}(X/Y)\r\n", original_x, original_y);
            string InfoTxt = sb.ToString();
        }
View Code

PCB Polar SI9000阻抗模型圖片文字識別方法