C#判断一张图片是否包含另一张图片并返回坐标

今天做一个程序其中有一个要求是这样的:从一个大图片里找这个图片的某部分并返回小图片相对于大图片的坐标点,心想这也不是太难就去问百度,结果半天没找到答案,于是问谷歌,结果还是一样,看来要自己搞了。最后在CSDN上找到了一段代码,不过Copy下来却不能用,确定自己研究,就在这段代码的基础上把它改成可以用的代码了,现在发出来给大家分享一下咯。

直接调用 GetImageContains,有三个参数,大图片,小图片,溶差,如果找到了就返回小图片在大图片中的坐标点,找不到返回一个(-1,-1)的point对象。  

/// <summary>        
/// 判断图形里是否存在另外一个图形 并返回所在位置 
/// </summary>
/// <param name="p_SourceBitmap">原始图形</param> 
/// <param name="p_PartBitmap">小图形</param>
/// <param name="p_Float">溶差</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), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb); byte[] _SourceByte = new byte[_SourceData.Stride * _SourceHeight]; Marshal.Copy(_SourceData.Scan0, _SourceByte, 0, _SourceByte.Length);  //复制出p_SourceBitmap的相素信息           
    _SourceBitmap.UnlockBits(_SourceData);
    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的相素信息           
    _PartBitmap.UnlockBits(_PartData); 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 + z) * _SourceData.Stride, z * _PartData.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 int GetImageContains(byte[] p_Source, byte[] p_Part, int p_SourceIndex, int p_PartIndex, int p_SourceWidth, int p_PartWidth, int p_Float)
{
    int _PartIndex = p_PartIndex;//           
    int _PartRVA = _PartIndex;//p_PartX轴起点         
    int _SourceIndex = p_SourceIndex;//p_SourceX轴起点        
    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[_PartRVA + 3], (int)p_Part[_PartRVA + 2], (int)p_Part[_PartRVA + 1], (int)p_Part[_PartRVA]); _SourceIndex += 4;//成功,p_SourceX轴加4
        bool _ScanColor = ScanColor(_CurrentlyColor, _CompareColoe, p_Float); if (_ScanColor)
        {
            _PartRVA += 4;//成功,p_PartX轴加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[_PartRVA + 3], (int)p_Part[_PartRVA + 2], (int)p_Part[_PartRVA + 1], (int)p_Part[_PartRVA]);
                if (!ScanColor(_CurrentlyColor, _CompareColoe, p_Float))
                {
                    _PartRVA = _PartIndex;//失败,重置p_PartX轴开始                
                    _Equals = false; break;
                }
                _PartRVA += 4;//成功,p_PartX轴加4             
                _SourceRVA += 4;//成功,p_SourceX轴加4              
            }
            if (_Equals) return i;
        }
        else
        {
            _PartRVA = _PartIndex;//失败,重置p_PartX轴开始        
        }
    }
    return -1;
}
/// <summary>        
/// 检查色彩(可以根据这个更改比较方式   
/// </summary>       
/// <param name="p_CurrentlyColor">当前色彩</param>        
/// <param name="p_CompareColor">比较色彩</param>      
/// <param name="p_Float">溶差</param>        
/// <returns></returns>         
private 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);
}

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注