判断图形里是否存在另外一个图形 并返回所在位置
作者:互联网
public class FindSmallImgInBig
{ /// <summary>
/// 判断图形里是否存在另外一个图形 并返回所在位置
/// </summary>
/// <param name="p_SourceBitmap">原始图形</param>
/// <param name="p_PartBitmap">小图形</param>
/// <param name="p_Float">溶差0~120数值越大,容许相差越大(0为完全相同,一般50到100可以称:相似)</param>
/// <returns>坐标</returns>
public Point GetImageContains(Bitmap p_SourceBitmap, Bitmap p_PartBitmap, int p_Float)
{
int _SourceWidth = p_SourceBitmap.Width;
int _SourceHeight = p_SourceBitmap.Height;
int _PartWidth = p_PartBitmap.Width;
int _PartHeight = p_PartBitmap.Height;
Bitmap _SourceBitmap = new Bitmap(_SourceWidth, _SourceHeight);
Graphics _Graphics = Graphics.FromImage(_SourceBitmap);
_Graphics.DrawImage(p_SourceBitmap, new Rectangle(0, 0, _SourceWidth, _SourceHeight));
_Graphics.Dispose();
BitmapData _SourceData = _SourceBitmap.LockBits(new Rectangle(0, 0, _SourceWidth, _SourceHeight), System.Drawing.Imaging.ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
byte[] _SourceByte = new byte[_SourceData.Stride * _SourceHeight];
Marshal.Copy(_SourceData.Scan0, _SourceByte, 0, _SourceByte.Length); //复制出p_SourceBitmap的相素信息
Bitmap _PartBitmap = new Bitmap(_PartWidth, _PartHeight);
_Graphics = Graphics.FromImage(_PartBitmap);
_Graphics.DrawImage(p_PartBitmap, new Rectangle(0, 0, _PartWidth, _PartHeight));
_Graphics.Dispose();
BitmapData _PartData = _PartBitmap.LockBits(new Rectangle(0, 0, _PartWidth, _PartHeight), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
byte[] _PartByte = new byte[_PartData.Stride * _PartHeight];
Marshal.Copy(_PartData.Scan0, _PartByte, 0, _PartByte.Length); //复制出p_PartBitmap的相素信息
for (int i = 0; i != _SourceHeight; i++)
{
if (_SourceHeight - i < _PartHeight) return new Point(-1, -1); //如果 剩余的高 比需要比较的高 还要小 就直接返回
int _PointX = -1; //临时存放坐标 需要包正找到的是在一个X点上
bool _SacnOver = true; //是否都比配的上
for (int z = 0; z != _PartHeight - 1; z++) //循环目标进行比较
{
int _TrueX = GetImageContains(_SourceByte, _PartByte, i * _SourceData.Stride, _SourceWidth, _PartWidth, p_Float);
if (_TrueX == -1) //如果没找到
{
_PointX = -1; //设置坐标为没找到
_SacnOver = false; //设置不进行返回
break;
}
else
{
if (z == 0) _PointX = _TrueX;
if (_PointX != _TrueX) //如果找到了 也的保证坐标和上一行的坐标一样 否则也返回
{
_PointX = -1;//设置坐标为没找到
_SacnOver = false; //设置不进行返回
break;
}
}
}
if (_SacnOver) return new Point(_PointX, i);
}
return new Point(-1, -1);
}
/// <summary>
/// 判断图形里是否存在另外一个图形 所在行的索引
/// </summary>
/// <param name="p_Source">原始图形数据</param>
/// <param name="p_Part">小图形数据</param>
/// <param name="p_SourceIndex">开始位置</param>
/// <param name="p_SourceWidth">原始图形宽</param>
/// <param name="p_PartWidth">小图宽</param>
/// <param name="p_Float">溶差</param>
/// <returns>所在行的索引 如果找不到返回-1</returns>
private static int GetImageContains(byte[] p_Source, byte[] p_Part, int p_SourceIndex, int p_SourceWidth, int p_PartWidth, int p_Float)
{
int _PartIndex = 0;
int _SourceIndex = p_SourceIndex;
for (int i = 0; i < p_SourceWidth; i++)
{
if (p_SourceWidth - i < p_PartWidth) return -1;
Color _CurrentlyColor = Color.FromArgb((int)p_Source[_SourceIndex + 3], (int)p_Source[_SourceIndex + 2], (int)p_Source[_SourceIndex + 1], (int)p_Source[_SourceIndex]);
Color _CompareColoe = Color.FromArgb((int)p_Part[3], (int)p_Part[2], (int)p_Part[1], (int)p_Part[0]);
_SourceIndex += 4;
bool _ScanColor = ScanColor(_CurrentlyColor, _CompareColoe, p_Float);
if (_ScanColor)
{
_PartIndex += 4;
int _SourceRVA = _SourceIndex;
bool _Equals = true;
for (int z = 0; z != p_PartWidth - 1; z++)
{
_CurrentlyColor = Color.FromArgb((int)p_Source[_SourceRVA + 3], (int)p_Source[_SourceRVA + 2], (int)p_Source[_SourceRVA + 1], (int)p_Source[_SourceRVA]);
_CompareColoe = Color.FromArgb((int)p_Part[_PartIndex + 3], (int)p_Part[_PartIndex + 2], (int)p_Part[_PartIndex + 1], (int)p_Part[_PartIndex]);
if (!ScanColor(_CurrentlyColor, _CompareColoe, p_Float))
{
_PartIndex = 0;
_Equals = false;
break;
}
_PartIndex += 4;
_SourceRVA += 4;
}
if (_Equals) return i;
}
else
{
_PartIndex = 0;
}
}
return -1;
}
/// <summary>
/// 检查色彩(可以根据这个更改比较方式
/// </summary>
/// <param name="p_CurrentlyColor">当前色彩</param>
/// <param name="p_CompareColor">比较色彩</param>
/// <param name="p_Float">溶差</param>
/// <returns></returns>
private static bool ScanColor(Color p_CurrentlyColor, Color p_CompareColor, int p_Float)
{
int _R = p_CurrentlyColor.R;
int _G = p_CurrentlyColor.G;
int _B = p_CurrentlyColor.B;
return (_R <= p_CompareColor.R + p_Float && _R >= p_CompareColor.R - p_Float) && (_G <= p_CompareColor.G + p_Float && _G >= p_CompareColor.G - p_Float) && (_B <= p_CompareColor.B + p_Float && _B >= p_CompareColor.B - p_Float);
}
#region 找图
/// <summary>
/// 查找图片,不能镂空
/// </summary>
/// <param name="subPic">要查找坐标的小图</param>
/// <param name="parPic">在哪个大图里查找</param>
/// <param name="errorRange">容错,单个色值范围内视为正确0~255</param>
/// <param name="searchRect">如果为empty,则默认查找整个图像</param>
/// <param name="matchRate">图片匹配度,默认90%</param>
/// <param name="isFindAll">是否查找所有相似的图片</param>
/// <returns>返回查找到的图片的中心点坐标</returns>
public List<System.Drawing.Point> FindPicture(string subPic, string parPic, byte errorRange = 0, Rectangle searchRect = new System.Drawing.Rectangle(), double matchRate = 0.9, bool isFindAll = false)
{
List<System.Drawing.Point> ListPoint = new List<System.Drawing.Point>();
var subBitmap = new Bitmap(subPic);
//var parBitmap = new Bitmap(parPic);
var parBitmap = new Bitmap(parPic);
int subWidth = subBitmap.Width;
int subHeight = subBitmap.Height;
int parWidth = parBitmap.Width;
int parHeight = parBitmap.Height;
if (searchRect.IsEmpty)
{
searchRect = new Rectangle(0, 0, parBitmap.Width, parBitmap.Height);
}
var searchLeftTop = searchRect.Location;
var searchSize = searchRect.Size;
System.Drawing.Color startPixelColor = subBitmap.GetPixel(0, 0);
var subData = subBitmap.LockBits(new Rectangle(0, 0, subBitmap.Width, subBitmap.Height), ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
var parData = parBitmap.LockBits(new Rectangle(0, 0, parBitmap.Width, parBitmap.Height), ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
var byteArrarySub = new byte[subData.Stride * subData.Height];
var byteArraryPar = new byte[parData.Stride * parData.Height];
Marshal.Copy(subData.Scan0, byteArrarySub, 0, subData.Stride * subData.Height);
Marshal.Copy(parData.Scan0, byteArraryPar, 0, parData.Stride * parData.Height);
var iMax = searchLeftTop.Y + searchSize.Height - subData.Height;//行
var jMax = searchLeftTop.X + searchSize.Width - subData.Width;//列
int smallOffsetX = 0, smallOffsetY = 0;
int smallStartX = 0, smallStartY = 0;
int pointX = -1; int pointY = -1;
for (int i = searchLeftTop.Y; i < iMax; i++)
{
for (int j = searchLeftTop.X; j < jMax; j++)
{
//大图x,y坐标处的颜色值
int x = j, y = i;
int parIndex = i * parWidth * 4 + j * 4;
var colorBig = System.Drawing.Color.FromArgb(byteArraryPar[parIndex + 3], byteArraryPar[parIndex + 2], byteArraryPar[parIndex + 1], byteArraryPar[parIndex]);
;
if (ColorAEqualColorB(colorBig, startPixelColor, errorRange))
{
smallStartX = x - smallOffsetX;//待找的图X坐标
smallStartY = y - smallOffsetY;//待找的图Y坐标
int sum = 0;//所有需要比对的有效点
int matchNum = 0;//成功匹配的点
for (int m = 0; m < subHeight; m++)
{
for (int n = 0; n < subWidth; n++)
{
int x1 = n, y1 = m;
int subIndex = m * subWidth * 4 + n * 4;
var color = System.Drawing.Color.FromArgb(byteArrarySub[subIndex + 3], byteArrarySub[subIndex + 2], byteArrarySub[subIndex + 1], byteArrarySub[subIndex]);
sum++;
int x2 = smallStartX + x1, y2 = smallStartY + y1;
int parReleativeIndex = y2 * parWidth * 4 + x2 * 4;//比对大图对应的像素点的颜色
var colorPixel = System.Drawing.Color.FromArgb(byteArraryPar[parReleativeIndex + 3], byteArraryPar[parReleativeIndex + 2], byteArraryPar[parReleativeIndex + 1], byteArraryPar[parReleativeIndex]);
if (ColorAEqualColorB(colorPixel, color, errorRange))
{
matchNum++;
}
}
}
if ((double)matchNum / sum >= matchRate)
{
Console.WriteLine((double)matchNum / sum);
pointX = smallStartX + (int)(subWidth / 2.0);
pointY = smallStartY + (int)(subHeight / 2.0);
var point = new System.Drawing.Point(pointX, pointY);
if (!ListContainsPoint(ListPoint, point, 10))
{
ListPoint.Add(point);
}
if (!isFindAll)
{
goto FIND_END;
}
}
}
//小图x1,y1坐标处的颜色值
}
}
FIND_END:
subBitmap.UnlockBits(subData);
parBitmap.UnlockBits(parData);
subBitmap.Dispose();
parBitmap.Dispose();
GC.Collect();
return ListPoint;
}
public List<System.Drawing.Point> FindPicture(Bitmap subPic, Bitmap parPic, byte errorRange = 0, Rectangle searchRect = new System.Drawing.Rectangle(), double matchRate = 0.9, bool isFindAll = false)
{
List<System.Drawing.Point> ListPoint = new List<System.Drawing.Point>();
var subBitmap = new Bitmap(subPic);
//var parBitmap = new Bitmap(parPic);
var parBitmap = new Bitmap(parPic);
int subWidth = subBitmap.Width;
int subHeight = subBitmap.Height;
int parWidth = parBitmap.Width;
int parHeight = parBitmap.Height;
if (searchRect.IsEmpty)
{
searchRect = new Rectangle(0, 0, parBitmap.Width, parBitmap.Height);
}
var searchLeftTop = searchRect.Location;
var searchSize = searchRect.Size;
System.Drawing.Color startPixelColor = subBitmap.GetPixel(0, 0);
var subData = subBitmap.LockBits(new Rectangle(0, 0, subBitmap.Width, subBitmap.Height), ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
var parData = parBitmap.LockBits(new Rectangle(0, 0, parBitmap.Width, parBitmap.Height), ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
var byteArrarySub = new byte[subData.Stride * subData.Height];
var byteArraryPar = new byte[parData.Stride * parData.Height];
Marshal.Copy(subData.Scan0, byteArrarySub, 0, subData.Stride * subData.Height);
Marshal.Copy(parData.Scan0, byteArraryPar, 0, parData.Stride * parData.Height);
var iMax = searchLeftTop.Y + searchSize.Height - subData.Height;//行
var jMax = searchLeftTop.X + searchSize.Width - subData.Width;//列
int smallOffsetX = 0, smallOffsetY = 0;
int smallStartX = 0, smallStartY = 0;
int pointX = -1; int pointY = -1;
for (int i = searchLeftTop.Y; i < iMax; i++)
{
for (int j = searchLeftTop.X; j < jMax; j++)
{
//大图x,y坐标处的颜色值
int x = j, y = i;
int parIndex = i * parWidth * 4 + j * 4;
var colorBig = System.Drawing.Color.FromArgb(byteArraryPar[parIndex + 3], byteArraryPar[parIndex + 2], byteArraryPar[parIndex + 1], byteArraryPar[parIndex]);
;
if (ColorAEqualColorB(colorBig, startPixelColor, errorRange))
{
smallStartX = x - smallOffsetX;//待找的图X坐标
smallStartY = y - smallOffsetY;//待找的图Y坐标
int sum = 0;//所有需要比对的有效点
int matchNum = 0;//成功匹配的点
for (int m = 0; m < subHeight; m++)
{
for (int n = 0; n < subWidth; n++)
{
int x1 = n, y1 = m;
int subIndex = m * subWidth * 4 + n * 4;
var color = System.Drawing.Color.FromArgb(byteArrarySub[subIndex + 3], byteArrarySub[subIndex + 2], byteArrarySub[subIndex + 1], byteArrarySub[subIndex]);
sum++;
int x2 = smallStartX + x1, y2 = smallStartY + y1;
int parReleativeIndex = y2 * parWidth * 4 + x2 * 4;//比对大图对应的像素点的颜色
var colorPixel = System.Drawing.Color.FromArgb(byteArraryPar[parReleativeIndex + 3], byteArraryPar[parReleativeIndex + 2], byteArraryPar[parReleativeIndex + 1], byteArraryPar[parReleativeIndex]);
if (ColorAEqualColorB(colorPixel, color, errorRange))
{
matchNum++;
}
}
}
if ((double)matchNum / sum >= matchRate)
{
Console.WriteLine((double)matchNum / sum);
pointX = smallStartX + (int)(subWidth / 2.0);
pointY = smallStartY + (int)(subHeight / 2.0);
var point = new System.Drawing.Point(pointX, pointY);
if (!ListContainsPoint(ListPoint, point, 10))
{
ListPoint.Add(point);
}
if (!isFindAll)
{
goto FIND_END;
}
}
}
//小图x1,y1坐标处的颜色值
}
}
FIND_END:
subBitmap.UnlockBits(subData);
parBitmap.UnlockBits(parData);
subBitmap.Dispose();
parBitmap.Dispose();
GC.Collect();
return ListPoint;
}
#endregion
public bool ColorAEqualColorB(System.Drawing.Color colorA, System.Drawing.Color colorB, byte errorRange = 10)
{
return colorA.A <= colorB.A + errorRange && colorA.A >= colorB.A - errorRange &&
colorA.R <= colorB.R + errorRange && colorA.R >= colorB.R - errorRange &&
colorA.G <= colorB.G + errorRange && colorA.G >= colorB.G - errorRange &&
colorA.B <= colorB.B + errorRange && colorA.B >= colorB.B - errorRange;
}
public bool ListContainsPoint(List<System.Drawing.Point> listPoint, System.Drawing.Point point, double errorRange = 10)
{
bool isExist = false;
foreach (var item in listPoint)
{
if (item.X <= point.X + errorRange && item.X >= point.X - errorRange && item.Y <= point.Y + errorRange && item.Y >= point.Y - errorRange)
{
isExist = true;
}
}
return isExist;
}
}
标签:返回,int,System,Height,parBitmap,所在位置,var,new,图形 来源: https://www.cnblogs.com/liao-long/p/15261867.html