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

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

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

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

 

 

 二.解決方法思路

    解決方法一:  ide

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

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

    這樣就能夠實現與Polar阻抗軟件相同的效果,可是Polar SI9000有阻抗計算模型93種,要實現的話工做量可不小,因此這種方法排除了。ui

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

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

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

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

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

      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
相關文章
相關標籤/搜索