using RichCreator.Utility.Structs; using Emgu.CV; using Emgu.CV.CvEnum; using Emgu.CV.Structure; using Emgu.CV.Util; using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using Orientation = RichCreator.Utility.Structs.Orientation; using RichCreator.Utility.Captures; namespace RichCreator.Utility.CV { /// /// 图像识别类 /// public static class CVHelper { #region 找线 /// /// 查找线 /// /// /// /// /// /// /// /// public static bool FindLine(out ZTLine line, Image image, Int32 minSize, Orientation orientation, ZTHsvFloatColor minColor, ZTHsvFloatColor maxColor) { ZTRectangle limitRect = new ZTRectangle(0, 0, image.Width - 1, image.Height - 1); return FindLine(out line, image, minSize, limitRect, orientation, minColor, maxColor); } /// /// 查找线 /// /// /// /// /// /// /// /// /// public static bool FindLine(out ZTLine line, Image image, Int32 minSize, ZTRectangle limitRectangle, Orientation orientation, ZTHsvFloatColor minColor, ZTHsvFloatColor maxColor) { line = ZTLine.Empty; Int32 start, size; Int32 xStep = 1; Int32 yStep = 1; if (minSize > 0) { if (orientation == Orientation.Horizontal) { xStep = minSize - 1; } if (orientation == Orientation.Vertical) { yStep = minSize - 1; } } for (int y = limitRectangle.Start.Y; y <= limitRectangle.End.Y; y += yStep) { for (int x = limitRectangle.Start.X; x <= limitRectangle.End.X; x += xStep) { if (InRange(image.Data, x, y, minColor,maxColor)) { if (GetLineInfo(out start, out size, image, new ZTPoint(x, y), minSize,orientation, minColor, maxColor)) { if (orientation == Orientation.Horizontal) { line = new ZTLine(start, y, size); } else { line = new ZTLine(x, start, size); } return true; } } } } return false; } /// /// 查找线 /// /// /// /// /// /// /// /// public static List FindLines( Image image, Int32 minSize, ZTRectangle limitRectangle, Orientation orientation, ZTHsvFloatColor minColor, ZTHsvFloatColor maxColor) { List lines = new List(); Func existsPoint = (x, y) => { for (Int32 i = 0; i < lines.Count; i++) { if (lines[0].Contain(x, y, orientation)) { return true; } } return false; }; ZTLine line = ZTLine.Empty; Int32 start, size; Int32 xStep = 1; Int32 yStep = 1; if (minSize > 0) { if (orientation == Orientation.Horizontal) { xStep = minSize - 1; } if (orientation == Orientation.Vertical) { yStep = minSize - 1; } } for (int y = limitRectangle.Start.Y; y <= limitRectangle.End.Y; y += yStep) { for (int x = limitRectangle.Start.X; x <= limitRectangle.End.X; x += xStep) { if (InRange(image.Data, x, y, minColor, maxColor)) { //存在,即跳过 if (existsPoint(x, y)) { continue; } if (GetLineInfo(out start, out size, image, new ZTPoint(x, y), minSize, orientation, minColor, maxColor)) { if (orientation == Orientation.Horizontal) { line = new ZTLine(start, y, size); } else { line = new ZTLine(x, start, size); } lines.Add(line); } } } } return lines; } /// /// 线信息 /// /// 图片 /// 参考点 /// /// 线的最小长度,如果找到的线比这个小就舍弃 /// 要找的线的颜色 /// 起点X /// 长度 /// private static bool GetLineInfo(out Int32 start, out Int32 size, Image image, ZTPoint point, Int32 minSize, Orientation orientation, ZTHsvFloatColor minColor,ZTHsvFloatColor maxColor) { start = orientation == Orientation.Horizontal ? point.X : point.Y; Int32 end = start; Int32 current = start; bool result = true; //往前捯,找起点 for (int i = current; i >= 0; i--) { if (orientation == Orientation.Horizontal) { result = InRange(image.Data, i, point.Y,minColor,maxColor); } else { result = InRange(image.Data, point.X, i,minColor,maxColor); } if (!result) { break; } start = i; } //往后捯,找终点 current = (orientation == Orientation.Horizontal ? point.X : point.Y) + 1; for (int i = current; i < image.Width; i++) { if (orientation == Orientation.Horizontal) { result = InRange(image.Data, i, point.Y, minColor, maxColor); } else { result = InRange(image.Data, point.X, i, minColor, maxColor); } if (!result) { break; } end = i; } size = end - start + 1; if (size >= minSize) { return true; } return false; } /// /// 查找线 /// /// /// /// /// /// public static bool FindLine(out ZTLine line,Image image, Int32 minSize,Orientation orientation, params ZTColor[] colors) { ZTRectangle limitRect = new ZTRectangle(0, 0, image.Width - 1, image.Height - 1); return FindLine(out line, image, minSize, limitRect,orientation, colors); } /// /// 查找线 /// /// /// /// /// /// /// public static bool FindLine(out ZTLine line, Image image, Int32 minSize, ZTRectangle limitRectangle,Orientation orientation,params ZTColor[] colors) { line = ZTLine.Empty; Int32 start, size; Int32 xStep = 1; Int32 yStep = 1; if (minSize > 0) { if (orientation == Orientation.Horizontal) { xStep = minSize - 1; } if (orientation == Orientation.Vertical) { yStep = minSize - 1; } } for (int y = limitRectangle.Start.Y; y <= limitRectangle.End.Y; y+=yStep) { for (int x = limitRectangle.Start.X; x <= limitRectangle.End.X; x += xStep) { if (CompareColors(image.Data, x, y, orientation, colors)) { if (GetLineInfo(out start, out size,image, new ZTPoint(x, y), minSize,orientation, colors)) { if (orientation == Orientation.Horizontal) { line = new ZTLine(start, y, size); } else { line = new ZTLine(x, start, size); } return true; } } } } return false; } /// /// 线信息 /// /// 图片 /// 参考点 /// /// 线的最小长度,如果找到的线比这个小就舍弃 /// 要找的线的颜色 /// 起点X /// 长度 /// private static bool GetLineInfo(out Int32 start, out Int32 size,Image image, ZTPoint point, Int32 minSize,Orientation orientation, ZTColor[] colors) { start =orientation==Orientation.Horizontal? point.X:point.Y; Int32 end = start; Int32 current = start; bool result = true; for (int i = current; i >= 0; i--) { if (orientation == Orientation.Horizontal) { result = CompareColors(image.Data, i, point.Y, orientation, colors); } else { result = CompareColors(image.Data, point.X, i, orientation, colors); } if (!result) { break; } start = i; } current = (orientation == Orientation.Horizontal ? point.X : point.Y) + 1; for (int i = current; i < image.Width; i++) { if (orientation == Orientation.Horizontal) { result = CompareColors(image.Data, i, point.Y, orientation, colors); } else { result = CompareColors(image.Data, point.X, i, orientation, colors); } if (!result) { break; } end = i; } size = end - start + 1; if (size >= minSize) { return true; } return false; } #endregion #region 查找方框 /// /// 查找方框 /// /// /// /// /// /// /// /// public static bool FindRectangle(out ZTRectangle rectangle, Image image, ZTSize minSize, Int32 maxRadius, ZTHsvFloatColor minColor,ZTHsvFloatColor maxColor) { ZTRectangle limitRect = new ZTRectangle(0, 0, image.Width - 1, image.Height - 1); return FindRectangle(out rectangle, image, minSize, maxRadius, limitRect, minColor,maxColor); } /// /// 查找方框 /// /// /// /// /// /// /// /// /// public static bool FindRectangle(out ZTRectangle rectangle, Image image, ZTSize minSize, Int32 maxRadius, ZTRectangle limitRect, ZTHsvFloatColor minColor, ZTHsvFloatColor maxColor) { rectangle = default(ZTRectangle); ZTLine topLine = ZTLine.Empty; ZTLine top = default(ZTLine); //查找顶部线 ZTRectangle limit = limitRect; if (!FindLine(out top, image, minSize.Width, limit, Orientation.Horizontal, minColor,maxColor)) { return false; } //查找左边线 ZTLine left = default(ZTLine); limit = new ZTRectangle( Math.Max(limitRect.Start.X, top.X - maxRadius), top.Y, top.X + top.Length - minSize.Width, limitRect.End.Y ); if (!FindLine(out left, image, minSize.Height, limit, Orientation.Vertical, minColor, maxColor)) { return false; } //查找右边线 ZTLine right = default(ZTLine); limit = new ZTRectangle( top.X + minSize.Width, top.Y, Math.Min(limitRect.End.X, top.X + top.Length + maxRadius), limitRect.End.Y ); if (!FindLine(out right, image, minSize.Height, limit, Orientation.Vertical, minColor, maxColor)) { return false; } if (Math.Abs(left.Length- right.Length)> maxRadius) { return false; } //查找下边线 ZTLine down = default(ZTLine); limit = new ZTRectangle( left.X, top.Y + minSize.Height, right.X, Math.Min(limitRect.End.Y, right.Y + right.Length + maxRadius) ); if (!FindLine(out down, image, minSize.Width, limit, Orientation.Horizontal, minColor, maxColor)) { return false; } if (top.Length != down.Length) { return false; } rectangle = new ZTRectangle(left.X, top.Y, right.X, down.Y); return true; } /// /// 查找矩形 /// /// /// /// /// /// /// public static bool FindRectangle(out ZTRectangle rectangle,Image image, ZTSize minSize, Int32 maxRadius, ZTColor color) { ZTRectangle limitRect = new ZTRectangle(0, 0, image.Width - 1, image.Height - 1); return FindRectangle(out rectangle, image, minSize, maxRadius, limitRect, color); } /// /// 查找矩形 /// /// 图像 /// 颜色 /// 最小的宽高 /// 转角最大半径 /// 返回找到的矩形 /// 在限制的区域里查找 /// public static bool FindRectangle(out ZTRectangle rectangle, Image image, ZTSize minSize, Int32 maxRadius, ZTRectangle limitRect, ZTColor color) { rectangle = default(ZTRectangle); ZTLine topLine = ZTLine.Empty; ZTLine top = default(ZTLine); //查找顶部线 ZTRectangle limit = limitRect; if (!FindLine(out top, image, minSize.Width, limit,Orientation.Horizontal, color)) { return false; } //查找左边线 ZTLine left = default(ZTLine); limit = new ZTRectangle( Math.Max(limitRect.Start.X, top.X - maxRadius), top.Y, top.X+top.Length-minSize.Width, limitRect.End.Y ); if (!FindLine(out left, image, minSize.Height, limit,Orientation.Vertical, color)) { return false; } //查找右边线 ZTLine right = default(ZTLine); limit = new ZTRectangle( top.X +minSize.Width, top.Y, Math.Min(limitRect.End.X, top.X + top.Length + maxRadius), limitRect.End.Y ); if (!FindLine(out right, image, minSize.Height, limit,Orientation.Vertical, color)) { return false; } if (left.Length != right.Length) { return false; } //查找下边线 ZTLine down = default(ZTLine); limit = new ZTRectangle( left.X, top.Y+minSize.Height, right.X, Math.Min(limitRect.End.Y, right.Y + right.Length + maxRadius) ); if (!FindLine(out down, image, minSize.Width, limit,Orientation.Horizontal, color)) { return false; } if (top.Length != down.Length) { return false; } rectangle = new ZTRectangle(left.X, top.Y, right.X, down.Y); return true; } #endregion #region 查找方块 /// /// 查找方块 /// /// /// /// /// /// /// public static List FindBlocks(Image image, Hsv minColor, Hsv maxColor, ZTSize size) { List rects = new List(); Image main = image.InRange(minColor, maxColor); //腐蚀 //Mat element1 = CvInvoke.GetStructuringElement(ElementShape.Rectangle, new System.Drawing.Size(3, 3), new System.Drawing.Point(0, 0)); //CvInvoke.Erode(main, main, element1, new System.Drawing.Point(-1, -1), 1, BorderType.Default, new MCvScalar(100)); //查找边框 VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint(); Image hierarchy = new Image(main.Size); CvInvoke.FindContours(main, contours, hierarchy, RetrType.External, ChainApproxMethod.ChainApproxSimple); for (int i = 0; i < contours.Size; i++) { System.Drawing.Rectangle rect = CvInvoke.BoundingRectangle(contours[i]); if (rect.Width < size.Width || rect.Height < size.Height) { continue; } ZTRectangle zrect = new ZTRectangle(rect.X, rect.Y, rect.X + rect.Width - 1, rect.Y + rect.Height - 1); rects.Add(zrect); } return rects; } #endregion #region 查找数组 /// /// 查找图像的二值化颜色数组 /// /// /// /// /// /// /// /// public static bool FindColorArrayForThreshold(out ZTRectangle position, Image source, ColorArray colorArray, ZTRectangle limitRectangle, Int32 xSkip = 1, Int32 ySkip = 1) { Image image = source; using (var temp = source.Convert()) { image = temp.ThresholdBinary(new Gray(colorArray.ThresholdValue), new Gray(255)).Convert(); } return FindColorArray(out position, image, colorArray, limitRectangle, xSkip, ySkip); } /// /// 查找图像的灰度化颜色数组 /// /// /// /// /// /// /// /// public static bool FindColorArrayForGray(out ZTRectangle position, Image source, ColorArray colorArray, ZTRectangle limitRectangle, Int32 xSkip = 1, Int32 ySkip = 1) { Image image = source.Convert().Convert(); return FindColorArray(out position, image, colorArray, limitRectangle, xSkip, ySkip); } /// /// 查找颜色数组 /// /// /// /// /// /// /// /// public static bool FindColorArray(out ZTRectangle position, Image image, ColorArray colorArray, ZTRectangle limitRectangle, Int32 xSkip = 1, Int32 ySkip = 1) { position = ZTRectangle.Empty; if (xSkip < 1 || ySkip < 1) { throw new ArgumentOutOfRangeException("skip不能小于1"); } for (int y = limitRectangle.Start.Y; y <= limitRectangle.End.Y; y += ySkip) { //超出高度 if ((limitRectangle.End.Y - y + 1) < colorArray.Size.Height) { return false; } for (int x = limitRectangle.Start.X; x <= limitRectangle.End.X; x += xSkip) { //超出宽度 if ((limitRectangle.End.X - x + 1) < colorArray.Size.Width) { break; } if (colorArray.Compare(image.Data, x, y)) { position = new ZTRectangle(x, y, x + colorArray.Size.Width - 1, y + colorArray.Size.Height - 1); return true; } } } return false; } /// /// 查找颜色数组 /// /// /// /// /// /// /// /// /// public static bool FindColorArray(out ZTRectangle position, Image image, ColorArray colorArray, ZTRectangle limitRectangle, Func filter, Int32 xSkip = 1, Int32 ySkip = 1) { position = ZTRectangle.Empty; if (xSkip < 1 || ySkip < 1) { throw new ArgumentOutOfRangeException("skip不能小于1"); } for (int y = limitRectangle.Start.Y; y <= limitRectangle.End.Y; y += ySkip) { //超出高度 if ((limitRectangle.End.Y - y + 1) < colorArray.Size.Height) { return false; } for (int x = limitRectangle.Start.X; x <= limitRectangle.End.X; x += xSkip) { //超出宽度 if ((limitRectangle.End.X - x + 1) < colorArray.Size.Width) { break; } if (colorArray.Compare(image.Data, x, y)) { position = new ZTRectangle(x, y, x + colorArray.Size.Width - 1, y + colorArray.Size.Height - 1); if (filter(position)) { return true; } } } } return false; } /// /// 查找所有数组方框 /// /// /// /// /// /// /// public static List FindColorArray(Image image, ColorArray colorArray, ZTRectangle limitRectangle, Int32 xSkip = 1, Int32 ySkip = 1) { List rects = new List(); if (xSkip < 1 || ySkip < 1) { throw new ArgumentOutOfRangeException("skip不能小于1"); } for (int y = limitRectangle.Start.Y; y <= limitRectangle.End.Y; y += ySkip) { //超出高度 if ((limitRectangle.End.Y - y + 1) < colorArray.Size.Height) { break; } for (int x = limitRectangle.Start.X; x <= limitRectangle.End.X; x += xSkip) { //超出宽度 if ((limitRectangle.End.X - x + 1) < colorArray.Size.Width) { break; } if (colorArray.Compare(image.Data, x, y)) { rects.Add(new ZTRectangle(x, y, x + colorArray.Size.Width - 1, y + colorArray.Size.Height - 1)); } } } return rects; } /// /// 查找数组 /// /// /// /// /// /// /// 相对于要查找点的偏移 /// public static bool FindColorBlock(out ZTPoint position, Image image, ZTRectangle limitRectangle, ZTHsvFloatColor minColor,ZTHsvFloatColor maxColor,ZTPoint[] pointOfBlock) { position = ZTPoint.Empty; byte[,,] data = image.Data; for (int y = limitRectangle.Start.Y; y <= limitRectangle.End.Y; y += 1) { for (int x = limitRectangle.Start.X; x <= limitRectangle.End.X; x += 1) { if (InRange(data, x, y, minColor, maxColor, pointOfBlock)) { position = new ZTPoint(x, y); return true; } } } return false; } #endregion #region 颜色比对 /// /// 颜色对比 /// /// /// /// /// /// /// public static bool IsColor(byte[,,] colorData, Int32 x, Int32 y, ZTColor color) { if (colorData[y, x, 0] == color.Red && colorData[y, x, 1] == color.Green && colorData[y, x, 2] == color.Blue) { return true; } return false; } /// /// 颜色比对,不包含x,y,仅比较indexs中的位置 /// /// /// /// /// /// 基于x,y的偏移量 /// public static bool IsColor(byte[,,] colorData, Int32 x, Int32 y, ZTColor color, ZTPoint[] indexs) { ZTPoint point = ZTPoint.Empty; for (int i = 0; i < indexs.Length; i++) { point = indexs[i]; if (!IsColor(colorData, x + point.X, y + point.Y, color)) { return false; } } return true; } /// /// 颜色比对 /// /// /// /// /// /// /// public static bool InRange(byte[,,] colorData, Int32 x, Int32 y, ZTHsvFloatColor minColor, ZTHsvFloatColor maxColor) { byte r = colorData[y, x, 0]; byte g = colorData[y, x, 1]; byte b = colorData[y, x, 2]; float h, s, v; ColorUtils.RGBtoHSV(r, g, b, out h, out s, out v); if (h >= minColor.H && s >= minColor.S && v >= minColor.V && h <= maxColor.H && s <= maxColor.S && v <= maxColor.V) { return true; } return false; } /// /// 颜色比对,不包含x,y,仅比较indexs中的位置 /// /// /// /// /// /// /// 相对于x,y的便宜量 /// public static bool InRange(byte[,,] colorData, Int32 x, Int32 y, ZTHsvFloatColor minColor, ZTHsvFloatColor maxColor,ZTPoint[] indexs) { ZTPoint point = ZTPoint.Empty; for (int i = 0; i < indexs.Length; i++) { point = indexs[i]; if (!InRange(colorData, x + point.X, y + point.Y, minColor,maxColor)) { return false; } } return true; } /// /// 对比位置的颜色 /// /// /// /// /// /// private static bool CompareColors(byte[,,] colorData, Int32 x, Int32 y, Orientation compareOriginal, ZTColor[] colors) { if (colors.Length <= 0) { return false; } if (colors.Length == 1) { return IsColor(colorData, x, y, colors[0]); } Int32 tx = x; Int32 ty = y; for (int i = 0; i < colors.Length; i++) { if (compareOriginal == Orientation.Horizontal) { tx = x + i; } else { ty = y + i; } if (!IsColor(colorData, tx, ty, colors[i])) { return false; } } return true; } #endregion /// /// 是否在指定颜色在区域内 /// /// public static bool RectExistsArray(ZTRectangle rect,ColorArray colorArray) { ZTRectangle colorRect = ZTRectangle.Empty; return RectExistsArray(out colorRect, rect, colorArray); } /// /// 是否在指定颜色在区域内 /// /// public static bool RectExistsArray(out ZTRectangle arrayRect,ZTRectangle rect, ColorArray colorArray) { //截图 System.Drawing.Bitmap bitmap = ScreenCapture.Instance.CaptureScreen(); Image image = new Image(bitmap); //查找地图右上边是否存在时空之门文字 if (CVHelper.FindColorArray(out arrayRect, image, colorArray, rect)) { return true; } return false; } } }