支付寶首頁搜“510992378”檢視留言?
原文地址:
http://www.cnblogs.com/JimmyBright/p/4355862.html
找色:
1 /// <summary> 2 /// 找顏色 3 /// </summary> 4 /// <param name="parPic">查詢的圖片的絕對路徑</param> 5 /// <param name="searchColor">查詢的16進位制顏色值,如#0C5FAB</param> 6 /// <param name="searchRect">查詢的矩形區域範圍內</param> 7 /// <param name="errorRange">容錯</param> 8 /// <returns></returns> 9 System.Drawing.Point FindColor(string parPic, string searchColor, System.Drawing.Rectangle searchRect, byte errorRange = 10) 10 { 11 var colorX = System.Drawing.ColorTranslator.FromHtml(searchColor); 12 var parBitmap = new Bitmap(parPic); 13 var parData = parBitmap.LockBits(new System.Drawing.Rectangle(0, 0, parBitmap.Width, parBitmap.Height), ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); 14 var byteArraryPar = new byte[parData.Stride * parData.Height]; 15 Marshal.Copy(parData.Scan0, byteArraryPar, 0, parData.Stride * parData.Height); 16 if (searchRect.IsEmpty) 17 { 18 searchRect = new System.Drawing.Rectangle(0, 0, parBitmap.Width, parBitmap.Height); 19 } 20 var searchLeftTop = searchRect.Location; 21 var searchSize = searchRect.Size; 22 var iMax = searchLeftTop.Y + searchSize.Height;//行 23 var jMax = searchLeftTop.X + searchSize.Width;//列 24 int pointX = -1; int pointY = -1; 25 for (int m = searchRect.Y; m < iMax; m++) 26 { 27 for (int n = searchRect.X; n < jMax; n++) 28 { 29 int index = m * parBitmap.Width * 4 + n * 4; 30 var color = System.Drawing.Color.FromArgb(byteArraryPar[index + 3], byteArraryPar[index + 2], byteArraryPar[index + 1], byteArraryPar[index]); 31 if (ColorAEqualColorB(color, colorX, errorRange)) 32 { 33 pointX = n; 34 pointY = m; 35 goto END; 36 } 37 } 38 } 39 END: 40 parBitmap.UnlockBits(parData); 41 return new System.Drawing.Point(pointX, pointY); 42 } 43 #endregion
方法中的容錯範圍,預設設定為10。R、G、B三者的範圍都是0~255,容錯為10,就表示每個範圍都可以在10上下波動,下面還會有容錯的概念
找圖:
在一張大圖中擷取一個矩形小圖,然後在任意包含該小圖的圖片中找到該小圖的座標位置
1 #region 找圖 2 3 /// <summary> 4 /// 查詢圖片,不能鏤空 5 /// </summary> 6 /// <param name="subPic"></param> 7 /// <param name="parPic"></param> 8 /// <param name="searchRect">如果為empty,則預設查詢整個影象</param> 9 /// <param name="errorRange">容錯,單個色值範圍內視為正確0~255</param> 10 /// <param name="matchRate">圖片匹配度,預設90%</param> 11 /// <param name="isFindAll">是否查詢所有相似的圖片</param> 12 /// <returns>返回查詢到的圖片的中心點座標</returns> 13 List<System.Drawing.Point> FindPicture(string subPic, string parPic, System.Drawing.Rectangle searchRect, byte errorRange, double matchRate = 0.9, bool isFindAll = false) 14 { 15 List<System.Drawing.Point> ListPoint = new List<System.Drawing.Point>(); 16 var subBitmap = new Bitmap(subPic); 17 var parBitmap = new Bitmap(parPic); 18 int subWidth = subBitmap.Width; 19 int subHeight = subBitmap.Height; 20 int parWidth = parBitmap.Width; 21 int parHeight = parBitmap.Height; 22 if (searchRect.IsEmpty) 23 { 24 searchRect = new System.Drawing.Rectangle(0, 0, parBitmap.Width, parBitmap.Height); 25 } 26 27 var searchLeftTop = searchRect.Location; 28 var searchSize = searchRect.Size; 29 System.Drawing.Color startPixelColor = subBitmap.GetPixel(0, 0); 30 var subData = subBitmap.LockBits(new System.Drawing.Rectangle(0, 0, subBitmap.Width, subBitmap.Height), ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); 31 var parData = parBitmap.LockBits(new System.Drawing.Rectangle(0, 0, parBitmap.Width, parBitmap.Height), ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); 32 var byteArrarySub = new byte[subData.Stride * subData.Height]; 33 var byteArraryPar = new byte[parData.Stride * parData.Height]; 34 Marshal.Copy(subData.Scan0, byteArrarySub, 0, subData.Stride * subData.Height); 35 Marshal.Copy(parData.Scan0, byteArraryPar, 0, parData.Stride * parData.Height); 36 37 var iMax = searchLeftTop.Y + searchSize.Height - subData.Height;//行 38 var jMax = searchLeftTop.X + searchSize.Width - subData.Width;//列 39 40 int smallOffsetX = 0, smallOffsetY = 0; 41 int smallStartX = 0, smallStartY = 0; 42 int pointX = -1; int pointY = -1; 43 for (int i = searchLeftTop.Y; i < iMax; i++) 44 { 45 for (int j = searchLeftTop.X; j < jMax; j++) 46 { 47 //大圖x,y座標處的顏色值 48 int x = j, y = i; 49 int parIndex = i * parWidth * 4 + j * 4; 50 var colorBig = System.Drawing.Color.FromArgb(byteArraryPar[parIndex + 3], byteArraryPar[parIndex + 2], byteArraryPar[parIndex + 1], byteArraryPar[parIndex]); 51 ; 52 if (ColorAEqualColorB(colorBig, startPixelColor, errorRange)) 53 { 54 smallStartX = x - smallOffsetX;//待找的圖X座標 55 smallStartY = y - smallOffsetY;//待找的圖Y座標 56 int sum = 0;//所有需要比對的有效點 57 int matchNum = 0;//成功匹配的點 58 for (int m = 0; m < subHeight; m++) 59 { 60 for (int n = 0; n < subWidth; n++) 61 { 62 int x1 = n, y1 = m; 63 int subIndex = m * subWidth * 4 + n * 4; 64 var color = System.Drawing.Color.FromArgb(byteArrarySub[subIndex + 3], byteArrarySub[subIndex + 2], byteArrarySub[subIndex + 1], byteArrarySub[subIndex]); 65 66 sum++; 67 int x2 = smallStartX + x1, y2 = smallStartY + y1; 68 int parReleativeIndex = y2 * parWidth * 4 + x2 * 4;//比對大圖對應的畫素點的顏色 69 var colorPixel = System.Drawing.Color.FromArgb(byteArraryPar[parReleativeIndex + 3], byteArraryPar[parReleativeIndex + 2], byteArraryPar[parReleativeIndex + 1], byteArraryPar[parReleativeIndex]); 70 if (ColorAEqualColorB(colorPixel, color, errorRange)) 71 { 72 matchNum++; 73 } 74 } 75 } 76 if ((double)matchNum / sum >= matchRate) 77 { 78 Console.WriteLine((double)matchNum / sum); 79 pointX = smallStartX + (int)(subWidth / 2.0); 80 pointY = smallStartY + (int)(subHeight / 2.0); 81 var point = new System.Drawing.Point(pointX, pointY); 82 if (!ListContainsPoint(ListPoint, point, 10)) 83 { 84 ListPoint.Add(point); 85 } 86 if (!isFindAll) 87 { 88 goto FIND_END; 89 } 90 } 91 } 92 //小圖x1,y1座標處的顏色值 93 } 94 } 95 FIND_END: 96 subBitmap.UnlockBits(subData); 97 parBitmap.UnlockBits(parData); 98 subBitmap.Dispose(); 99 parBitmap.Dispose(); 100 GC.Collect(); 101 return ListPoint; 102 } 103 #endregion
找字:
找字比較困難了呢,因為文字是一種鏤空的影象,不像上述找的是非鏤空影象,程式碼:
定義結構體:
1 struct NumBody 2 { 3 public int num;//數字 4 public int matchNum;//匹配的個數 5 public int matchSum; 6 public double matchRate;//匹配度 7 public System.Drawing.Point point; 8 public List<System.Drawing.Point> bodyCollectionPoint;//該數字所有畫素在大圖中的座標 9 }
1 #region 找字 2 3 /// <summary> 4 /// 找文字,鏤空的圖片文字 5 /// </summary> 6 /// <param name="subPic"></param> 7 /// <param name="parPic"></param> 8 /// <param name="searchRect"></param> 9 /// <param name="errorRange"></param> 10 /// <param name="matchRate"></param> 11 /// <param name="isFindAll"></param> 12 /// <returns></returns> 13 List<NumBody> FindText(string subPic, string parPic, System.Drawing.Rectangle searchRect, byte errorRange, double matchRate = 0.9, bool isFindAll = false) 14 { 15 16 List<NumBody> ListPoint = new List<NumBody>(); 17 var subBitmap = new Bitmap(subPic); 18 var parBitmap = new Bitmap(parPic); 19 int subWidth = subBitmap.Width; 20 int subHeight = subBitmap.Height; 21 int parWidth = parBitmap.Width; 22 int parHeight = parBitmap.Height; 23 var bgColor = subBitmap.GetPixel(0, 0);//背景紅色 24 if (searchRect.IsEmpty) 25 { 26 searchRect = new System.Drawing.Rectangle(0, 0, parBitmap.Width, parBitmap.Height); 27 } 28 var searchLeftTop = searchRect.Location; 29 var searchSize = searchRect.Size; 30 var subData = subBitmap.LockBits(new System.Drawing.Rectangle(0, 0, subBitmap.Width, subBitmap.Height), ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); 31 var parData = parBitmap.LockBits(new System.Drawing.Rectangle(0, 0, parBitmap.Width, parBitmap.Height), ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); 32 var byteArrarySub = new byte[subData.Stride * subData.Height]; 33 var byteArraryPar = new byte[parData.Stride * parData.Height]; 34 Marshal.Copy(subData.Scan0, byteArrarySub, 0, subData.Stride * subData.Height); 35 Marshal.Copy(parData.Scan0, byteArraryPar, 0, parData.Stride * parData.Height); 36 var iMax = searchLeftTop.Y + searchSize.Height - subData.Height;//行 37 var jMax = searchLeftTop.X + searchSize.Width - subData.Width;//列 38 System.Drawing.Color startPixelColor = System.Drawing.Color.FromArgb(0, 0, 0); 39 int smallOffsetX = 0, smallOffsetY = 0; 40 int smallStartX = 0, smallStartY = 0; 41 int pointX = -1; int pointY = -1; 42 43 44 for (int m = 0; m < subHeight; m++) 45 { 46 for (int n = 0; n < subWidth; n++) 47 { 48 smallOffsetX = n; 49 smallOffsetY = m; 50 int subIndex = m * subWidth * 4 + n * 4; 51 var color = System.Drawing.Color.FromArgb(byteArrarySub[subIndex + 3], byteArrarySub[subIndex + 2], byteArrarySub[subIndex + 1], byteArrarySub[subIndex]); 52 if (!ColorAEqualColorB(color, bgColor, errorRange)) 53 { 54 startPixelColor = color; 55 goto END; 56 } 57 } 58 } 59 60 END: 61 for (int i = searchLeftTop.Y; i < iMax; i++) 62 { 63 for (int j = searchLeftTop.X; j < jMax; j++) 64 { 65 //大圖x,y座標處的顏色值 66 int x = j, y = i; 67 int parIndex = i * parWidth * 4 + j * 4; 68 var colorBig = System.Drawing.Color.FromArgb(byteArraryPar[parIndex + 3], byteArraryPar[parIndex + 2], byteArraryPar[parIndex + 1], byteArraryPar[parIndex]); 69 ; 70 71 List<System.Drawing.Point> myListPoint = new List<System.Drawing.Point>(); 72 if (ColorAEqualColorB(colorBig, startPixelColor, errorRange)) 73 { 74 smallStartX = x - smallOffsetX;//待找的圖X座標 75 smallStartY = y - smallOffsetY;//待找的圖Y座標 76 int sum = 0;//所有需要比對的有效點 77 int matchNum = 0;//成功匹配的點 78 for (int m = 0; m < subHeight; m++) 79 { 80 for (int n = 0; n < subWidth; n++) 81 { 82 int x1 = n, y1 = m; 83 int subIndex = m * subWidth * 4 + n * 4; 84 var color = System.Drawing.Color.FromArgb(byteArrarySub[subIndex + 3], byteArrarySub[subIndex + 2], byteArrarySub[subIndex + 1], byteArrarySub[subIndex]); 85 if (color != bgColor) 86 { 87 sum++; 88 int x2 = smallStartX + x1, y2 = smallStartY + y1; 89 int parReleativeIndex = y2 * parWidth * 4 + x2 * 4;//比對大圖對應的畫素點的顏色 90 var colorPixel = System.Drawing.Color.FromArgb(byteArraryPar[parReleativeIndex + 3], byteArraryPar[parReleativeIndex + 2], byteArraryPar[parReleativeIndex + 1], byteArraryPar[parReleativeIndex]); 91 if (ColorAEqualColorB(colorPixel, color, errorRange)) 92 { 93 matchNum++; 94 } 95 myListPoint.Add(new System.Drawing.Point(x2, y2)); 96 } 97 } 98 } 99 100 double rate = (double)matchNum / sum; 101 if (rate>= matchRate) 102 { 103 Console.WriteLine((double)matchNum / sum); 104 pointX = smallStartX + (int)(subWidth / 2.0); 105 pointY = smallStartY + (int)(subHeight / 2.0); 106 var point = new System.Drawing.Point(pointX, pointY); 107 if (!ListTextBodyContainsPoint(ListPoint, point, 1)) 108 { 109 ListPoint.Add(new NumBody() { point = point, matchNum = matchNum,matchSum=sum, matchRate = rate, bodyCollectionPoint = myListPoint }); 110 } 111 SearchNumbersByMatchNum(ref ListPoint); 112 if (!isFindAll) 113 { 114 goto FIND_END; 115 } 116 } 117 } 118 //小圖x1,y1座標處的顏色值 119 } 120 } 121 FIND_END: 122 subBitmap.UnlockBits(subData); 123 parBitmap.UnlockBits(parData); 124 subBitmap.Dispose(); 125 parBitmap.Dispose(); 126 GC.Collect(); 127 return ListPoint; 128 }
特別注意:有了這個方法還是不能找到你要的文字的。要先處理文字,下面舉例:
例如在這張圖片上找到朋友的朋字的座標位置:
1:開啟你的PS,先將圖片放大,看到畫素方塊為止,然後將朋字的範圍圈選住,注意稍微比字圈選的大一點,像這樣:
2:按住CTRL+C,然後CTRL+N,出現對話方塊:(教教大家使用PS^_^)
3:將背景內容選擇透明,按確定,再按CTRL+V複製影象
4:將這個圖片放大到看到畫素為止,將所有非字型的位置全部用鉛筆工具塗上同一種顏色,
5:塗完了之後將這張圖片儲存下來,這張圖片就是我們要查詢的“朋”字,圖片是這樣的
6:我們需要的就是第五步的圖片和第一張底圖,下面見證奇蹟的時刻到了。
1 string str1 = @"C:\Users\JimmyBright\Desktop\1.png"; 2 string str2 = @"C:\Users\JimmyBright\Desktop\2.png"; 3 var xx = FindText(str2,str1,new System.Drawing.Rectangle(0, 0, 400, 600),10);
str1是我們的底圖,str2是第五步的那張處理後的文字圖片,xx就是我們最後需要的文字的位置座標,我們執行看看。下面截圖執行結果:
顯然最後我們查詢的文字在圖片中的座標為(224,286),大家可以下載那張圖片驗證
找數:
你以為找到文字就算完了嗎?No,找數字才是最困難的,為什麼呢?有人會問,數字難道不也是文字嗎,不也可以通過PS處理數字達到查詢其位置的目的嗎?對的,數字也是文字,我們將需要查詢的數字0~9全部PS處理,就能查到它們的位置了。但是有一個問題啊,遊戲中用數字表示的地方通常是一連串的數字,這些數字裡麵包含0~9的任意組合。所以我們需要這樣處理:
我們從0~9依次查詢指定區域,記錄每次查詢的結果,沒查到的數字不必記錄,對查到結果的數字再按照X座標排序,因為在X座標越小,數字越靠左邊。
還有一個嚴重的問題,例如38,14,這樣的數字會很討厭,為什麼呢,我們會再8當中查詢3,在4當中查詢到1,這會對我們的數字識別產生重大誤差,所以下面我也寫了一個方法對這個問題做了處理,程式碼:
1 #region 查詢數字 2 3 /// <summary> 4 /// 在指定區域裡面查詢數字 5 /// </summary> 6 /// <param name="numDic"></param> 7 /// <param name="parPic"></param> 8 /// <param name="searchRect"></param> 9 /// <param name="errorRange"></param> 10 /// <returns></returns> 11 int FindNumbers(Dictionary<int, string> numDic, string parPic, System.Drawing.Rectangle searchRect, byte errorRange=8, double matchRate = 0.9) 12 { 13 //同一個區域找到多個相同的圖片 14 List<NumBody> ListBody = new List<NumBody>(); 15 foreach (var item in numDic) 16 { 17 var listPoint = FindText(item.Value, parPic, searchRect, errorRange, matchRate, true); 18 foreach (var point in listPoint) 19 { 20 ListBody.Add(new NumBody() { num = item.Key,matchNum=point.matchNum,matchSum=point.matchSum, matchRate=point.matchRate, point = point.point, bodyCollectionPoint = point.bodyCollectionPoint }); 21 } 22 } 23 24 SearchNumbersByMatchNum(ref ListBody); 25 var myList = from body in ListBody orderby body.point.X ascending select body; 26 string number = "0"; 27 foreach (var item in myList) 28 { 29 number += item.num; 30 } 31 int num = Int32.Parse(number); 32 return num; 33 } 34 /// <summary> 35 /// 搜尋同一個數字的時候,出現重疊的地方,用匹配度去過濾掉匹配度低的 36 /// 比如同樣是1,在控制匹配度允許下,一個(83,95)和(84,95)這兩個點明顯是同一個數字 37 /// 此時誰的匹配度低過濾掉誰 38 /// </summary> 39 /// <param name="ListBody"></param> 40 void SearchNumbersByMatchNum(ref List<NumBody> ListBody) 41 { 42 bool isValid = true; 43 for (int i = 0; i < ListBody.Count; i++) 44 { 45 var body = ListBody[i]; 46 47 for (int j = i; j < ListBody.Count; j++) 48 { 49 50 var bodyX = ListBody[j]; 51 if (!bodyX.Equals(body)) 52 { 53 int sameNum = 0; 54 foreach (var item in body.bodyCollectionPoint) 55 { 56 if (bodyX.bodyCollectionPoint.Contains(item)) 57 { 58 sameNum++; 59 } 60 } 61 if (sameNum >= 1)//有1個以上點重合,表面影象重疊,刪除畫素點數少的影象 62 { 63 isValid = false; 64 65 //如果某個數字100%匹配,那就不用比較了,這個數字肯定是對的 66 double maxRate = 1; 67 if (bodyX.matchRate >= maxRate) 68 { 69 ListBody.Remove(body); 70 } 71 else if (body.matchRate>=maxRate) 72 { 73 ListBody.Remove(bodyX); 74 } 75 else 76 { 77 if (bodyX.matchNum >= body.matchNum)//影象包含的所有畫素個數 78 { 79 ListBody.Remove(body); 80 } 81 else 82 { 83 ListBody.Remove(bodyX); 84 } 85 } 86 SearchNumbersByMatchNum(ref ListBody); 87 } 88 } 89 } 90 } 91 if (isValid) 92 { 93 return; 94 } 95 } 96 97 #endregion
其他方法:
1 bool ColorAEqualColorB(System.Drawing.Color colorA, System.Drawing.Color colorB, byte errorRange = 10) 2 { 3 return colorA.A <= colorB.A + errorRange && colorA.A >= colorB.A - errorRange && 4 colorA.R <= colorB.R + errorRange && colorA.R >= colorB.R - errorRange && 5 colorA.G <= colorB.G + errorRange && colorA.G >= colorB.G - errorRange && 6 colorA.B <= colorB.B + errorRange && colorA.B >= colorB.B - errorRange; 7 8 } 9 bool ListContainsPoint(List<System.Drawing.Point> listPoint, System.Drawing.Point point, double errorRange = 10) 10 { 11 bool isExist = false; 12 foreach (var item in listPoint) 13 { 14 if (item.X <= point.X + errorRange && item.X >= point.X - errorRange && item.Y <= point.Y + errorRange && item.Y >= point.Y - errorRange) 15 { 16 isExist = true; 17 } 18 } 19 return isExist; 20 } 21 bool ListTextBodyContainsPoint(List<NumBody> listPoint, System.Drawing.Point point, double errorRange = 10) 22 { 23 bool isExist = false; 24 foreach (var item in listPoint) 25 { 26 27 if (item.point.X <= point.X + errorRange && item.point.X >= point.X - errorRange && item.point.Y <= point.Y + errorRange && item.point.Y >= point.Y - errorRange) 28 { 29 isExist = true; 30 } 31 } 32 return isExist; 33 }
結束語:以上程式碼本人實現了找顏色,找圖片,找文字,找數字的所有功能,希望對朋友們能有所幫助。
最近找到了以前的程式碼:
想看原始碼的去這裡