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;
}
}
}