public String ProcessImage_Dif(Bitmap image, Bitmap template, TemplateMatch pMatch, bool bShow1) { // lock source and template images BitmapData imageData = image.LockBits( new Rectangle(0, 0, image.Width, image.Height), ImageLockMode.ReadOnly, image.PixelFormat); BitmapData templateData = template.LockBits( new Rectangle(0, 0, template.Width, template.Height), ImageLockMode.ReadOnly, template.PixelFormat); return(ProcessImage_Dif(new UnmanagedImage(imageData), new UnmanagedImage(templateData), pMatch, bShow1)); }
/// <summary> /// Process image looking for matchings with specified template. /// </summary> /// /// <param name="image">Unmanaged source image to process.</param> /// <param name="template">Unmanaged template image to search for.</param> /// <param name="searchZone">Rectangle in source image to search template for.</param> /// /// <returns>Returns array of found template matches. The array is sorted by similarity /// of found matches in descending order.</returns> /// /// <exception cref="UnsupportedImageFormatException">The source image has incorrect pixel format.</exception> /// <exception cref="InvalidImagePropertiesException">Template image is bigger than search zone.</exception> /// public TemplateMatch[] ProcessImage(UnmanagedImage image, UnmanagedImage template, Rectangle searchZone) { // check image format if ( ((image.PixelFormat != PixelFormat.Format8bppIndexed) && (image.PixelFormat != PixelFormat.Format24bppRgb)) || (image.PixelFormat != template.PixelFormat)) { throw new UnsupportedImageFormatException("Unsupported pixel format of the source or template image."); } // clip search zone Rectangle zone = searchZone; zone.Intersect(new Rectangle(0, 0, image.Width, image.Height)); // search zone's starting point int startX = zone.X; int startY = zone.Y; // get source and template image size int sourceWidth = zone.Width; int sourceHeight = zone.Height; int templateWidth = template.Width; int templateHeight = template.Height; // check template's size if ((templateWidth > sourceWidth) || (templateHeight > sourceHeight)) { throw new InvalidImagePropertiesException("Template's size should be smaller or equal to search zone."); } int pixelSize = (image.PixelFormat == PixelFormat.Format8bppIndexed) ? 1 : 3; int sourceStride = image.Stride; // similarity map. its size is increased by 4 from each side to increase // performance of non-maximum suppresion int mapWidth = sourceWidth - templateWidth + 1; int mapHeight = sourceHeight - templateHeight + 1; int[,] map = new int[mapHeight + 4, mapWidth + 4]; // maximum possible difference with template int maxDiff = templateWidth * templateHeight * pixelSize * 255; // integer similarity threshold int threshold = (int)(similarityThreshold * maxDiff); // width of template in bytes int templateWidthInBytes = templateWidth * pixelSize; // do the job unsafe { byte *baseSrc = (byte *)image.ImageData.ToPointer(); byte *baseTpl = (byte *)template.ImageData.ToPointer(); int sourceOffset = image.Stride - templateWidth * pixelSize; int templateOffset = template.Stride - templateWidth * pixelSize; /*trl * PointF topP = new PointF(430, 70); * PointF LeftP = new PointF(67, 333); * PointF RightP = new PointF(787, 335); * PointF BottomP = new PointF(430, 605); * List<PointF> m_Points = new List<PointF>(); * m_Points.Add(topP); * m_Points.Add(RightP); * m_Points.Add(BottomP); * m_Points.Add(LeftP); * m_Points.Add(topP); * Polygon CocArea = new Polygon(m_Points.ToArray()); */ // for each row of the source image for (int y = 0; y < mapHeight; y++) { // for each pixel of the source image for (int x = 0; x < mapWidth; x++) { Point CurrPoint = new Point(x + startX, y + startY); //trl if (COCDiamond.PointInPolygon(CurrPoint.X, CurrPoint.Y)) //checks if point is in cocDiamond { byte *src = baseSrc + sourceStride * (y + startY) + pixelSize * (x + startX); byte *tpl = baseTpl; // compare template with source image starting from current X,Y int dif = 0; // for each row of the template for (int i = 0; i < templateHeight; i++) { // for each pixel of the template for (int j = 0; j < templateWidthInBytes; j++, src++, tpl++) { int d = *src - *tpl; if (d > 0) { dif += d; } else { dif -= d; } } src += sourceOffset; tpl += templateOffset; } // templates similarity int sim = maxDiff - dif; if (sim >= threshold) { map[y + 2, x + 2] = sim; } } //trl } } } // collect interesting points - only those points, which are local maximums List <TemplateMatch> matchingsList = new List <TemplateMatch>(); // for each row for (int y = 2, maxY = mapHeight + 2; y < maxY; y++) { // for each pixel for (int x = 2, maxX = mapWidth + 2; x < maxX; x++) { int currentValue = map[y, x]; // for each windows' row for (int i = -2; (currentValue != 0) && (i <= 2); i++) { // for each windows' pixel for (int j = -2; j <= 2; j++) { if (map[y + i, x + j] > currentValue) { currentValue = 0; break; } } } // check if this point is really interesting if (currentValue != 0) { matchingsList.Add(new TemplateMatch( new Rectangle(x - 2 + startX, y - 2 + startY, templateWidth, templateHeight), (float)currentValue / maxDiff)); } } } // convert list to array TemplateMatch[] matchings = new TemplateMatch[matchingsList.Count]; matchingsList.CopyTo(matchings); // sort in descending order Array.Sort(matchings, new MatchingsSorter()); return(matchings); }
/// <summary> /// Process image looking for matchings with specified template. /// </summary> /// /// <param name="image">Unmanaged source image to process.</param> /// <param name="template">Unmanaged template image to search for.</param> /// <param name="searchZone">Rectangle in source image to search template for.</param> /// /// <returns>Returns array of found template matches. The array is sorted by similarity /// of found matches in descending order.</returns> /// /// <exception cref="UnsupportedImageFormatException">The source image has incorrect pixel format.</exception> /// <exception cref="InvalidImagePropertiesException">Template image is bigger than search zone.</exception> /// public TemplateMatch[] ProcessImage( UnmanagedImage image, UnmanagedImage template, Rectangle searchZone ) { // check image format if ( ( ( image.PixelFormat != PixelFormat.Format8bppIndexed ) && ( image.PixelFormat != PixelFormat.Format24bppRgb ) ) || ( image.PixelFormat != template.PixelFormat ) ) { throw new UnsupportedImageFormatException( "Unsupported pixel format of the source or template image." ); } // clip search zone Rectangle zone = searchZone; zone.Intersect( new Rectangle( 0, 0, image.Width, image.Height ) ); // search zone's starting point int startX = zone.X; int startY = zone.Y; // get source and template image size int sourceWidth = zone.Width; int sourceHeight = zone.Height; int templateWidth = template.Width; int templateHeight = template.Height; // check template's size if ( ( templateWidth > sourceWidth ) || ( templateHeight > sourceHeight ) ) { throw new InvalidImagePropertiesException( "Template's size should be smaller or equal to search zone." ); } int pixelSize = ( image.PixelFormat == PixelFormat.Format8bppIndexed ) ? 1 : 3; int sourceStride = image.Stride; // similarity map. its size is increased by 4 from each side to increase // performance of non-maximum suppresion int mapWidth = sourceWidth - templateWidth + 1; int mapHeight = sourceHeight - templateHeight + 1; int[,] map = new int[mapHeight + 4, mapWidth + 4]; // maximum possible difference with template int maxDiff = templateWidth * templateHeight * pixelSize * 255; // integer similarity threshold int threshold = (int) ( similarityThreshold * maxDiff ); // width of template in bytes int templateWidthInBytes = templateWidth * pixelSize; // do the job unsafe { byte* baseSrc = (byte*) image.ImageData.ToPointer( ); byte* baseTpl = (byte*) template.ImageData.ToPointer( ); int sourceOffset = image.Stride - templateWidth * pixelSize; int templateOffset = template.Stride - templateWidth * pixelSize; // for each row of the source image for ( int y = 0; y < mapHeight; y++ ) { // for each pixel of the source image for ( int x = 0; x < mapWidth; x++ ) { byte* src = baseSrc + sourceStride * ( y + startY ) + pixelSize * ( x + startX ); byte* tpl = baseTpl; // compare template with source image starting from current X,Y int dif = 0; // for each row of the template for ( int i = 0; i < templateHeight; i++ ) { // for each pixel of the template for ( int j = 0; j < templateWidthInBytes; j++, src++, tpl++ ) { int d = *src - *tpl; if ( d > 0 ) { dif += d; } else { dif -= d; } } src += sourceOffset; tpl += templateOffset; } // templates similarity int sim = maxDiff - dif; if ( sim >= threshold ) map[y + 2, x + 2] = sim; } } } // collect interesting points - only those points, which are local maximums List<TemplateMatch> matchingsList = new List<TemplateMatch>( ); // for each row for ( int y = 2, maxY = mapHeight + 2; y < maxY; y++ ) { // for each pixel for ( int x = 2, maxX = mapWidth + 2; x < maxX; x++ ) { int currentValue = map[y, x]; // for each windows' row for ( int i = -2; ( currentValue != 0 ) && ( i <= 2 ); i++ ) { // for each windows' pixel for ( int j = -2; j <= 2; j++ ) { if ( map[y + i, x + j] > currentValue ) { currentValue = 0; break; } } } // check if this point is really interesting if ( currentValue != 0 ) { matchingsList.Add( new TemplateMatch( new Rectangle( x - 2 + startX, y - 2 + startY, templateWidth, templateHeight ), (float) currentValue / maxDiff ) ); } } } // convert list to array TemplateMatch[] matchings = new TemplateMatch[matchingsList.Count]; matchingsList.CopyTo( matchings ); // sort in descending order Array.Sort( matchings, new MatchingsSorter( ) ); return matchings; }
/// <summary> /// /// </summary> /// <param name="image"></param> /// <param name="template"></param> /// <param name="pItem"></param> /// <returns></returns> public String ProcessImage_Dif( UnmanagedImage image, UnmanagedImage template, TemplateMatch pItem, bool bShow1) // Rectangle searchZone) { // check image format if ( ((image.PixelFormat != PixelFormat.Format8bppIndexed) && (image.PixelFormat != PixelFormat.Format24bppRgb)) || (image.PixelFormat != template.PixelFormat)) { throw new UnsupportedImageFormatException("Unsupported pixel format of the source or template image."); } // clip search zone //Rectangle zone = searchZone; //zone.Intersect(new Rectangle(0, 0, image.Width, image.Height)); // search zone's starting point int startX = 0; //zone.X; int startY = 0; // zone.Y; // get source and template image size int sourceWidth = image.Width; // zone.Width; int sourceHeight = image.Height; // zone.Height; int templateWidth = template.Width; int templateHeight = template.Height; // check template's size if ((templateWidth > sourceWidth) || (templateHeight > sourceHeight)) { throw new InvalidImagePropertiesException("Template's size should be smaller or equal to search zone."); } int pixelSize = (image.PixelFormat == PixelFormat.Format8bppIndexed) ? 1 : 3; int sourceStride = image.Stride; // similarity map. its size is increased by 4 from each side to increase // performance of non-maximum suppresion // 后面找相似度是否是最大的,是在5*5区域里找的,所以四个方向都扩大两个像素,这样就不需要检查边界条件 int mapWidth = sourceWidth - templateWidth + 1; int mapHeight = sourceHeight - templateHeight + 1; int[,] map = new int[mapHeight + 4, mapWidth + 4]; // maximum possible difference with template int maxDiff = templateWidth * templateHeight * pixelSize * 255; // integer similarity threshold int threshold = (int)(similarityThreshold * maxDiff); //iStep是步长,iStep个点里找一个点做比较,减少运算量 // width of template in bytes int templateWidthInBytes = templateWidth * pixelSize; StringBuilder pStr = new StringBuilder(); // do the job unsafe { byte *baseSrc = (byte *)image.ImageData.ToPointer(); byte *baseTpl = (byte *)template.ImageData.ToPointer(); int sourceOffset = image.Stride - templateWidth * pixelSize; int templateOffset = template.Stride - templateWidth * pixelSize; int y = pItem.Rectangle.Y; // y < pItem.Rectangle.Y+pItem.Rectangle.Height; y++) // for each pixel of the source image int x = pItem.Rectangle.X; // x < pItem.Rectangle.X+pItem.Rectangle.Width; x++) byte *src = baseSrc + sourceStride * (y + startY) + pixelSize * (x + startX); byte *tpl = baseTpl; // for each row of the template for (int i = 0; i < templateHeight; i++) { // for each pixel of the template int j = 0; for (j = 0; j < templateWidthInBytes; j += pixelSize, src += pixelSize, tpl += pixelSize) // j++, src++, tpl++) { //int d = *src - *tpl; //d= Math.Abs(d); int d = Math.Abs(*src - *tpl) + Math.Abs(*(src + 1) - *(tpl + 1)) + Math.Abs(*(src + 2) - *(tpl + 2)); if (bShow1) { if (d > 0) { pStr.Append("X"); } else { pStr.Append(" "); } } else { pStr.Append(d).Append(" "); } } pStr.Append("\n"); src += sourceOffset; tpl += templateOffset; } } return(pStr.ToString()); }
/// <summary> /// Process image looking for matchings with specified template. /// </summary> /// /// <param name="image">Unmanaged source image to process.</param> /// <param name="template">Unmanaged template image to search for.</param> /// <param name="iStep">步长</param> /// /// <returns>Returns array of found template matches. The array is sorted by similarity /// of found matches in descending order.</returns> /// /// <exception cref="UnsupportedImageFormatException">The source image has incorrect pixel format.</exception> /// <exception cref="InvalidImagePropertiesException">Template image is bigger than search zone.</exception> /// public List <TemplateMatch> ProcessImage3(UnmanagedImage image, UnmanagedImage template, List <TemplateMatch> pList) // Rectangle searchZone) { // check image format if ( ((image.PixelFormat != PixelFormat.Format8bppIndexed) && (image.PixelFormat != PixelFormat.Format24bppRgb)) || (image.PixelFormat != template.PixelFormat)) { throw new UnsupportedImageFormatException("Unsupported pixel format of the source or template image."); } // clip search zone //Rectangle zone = searchZone; //zone.Intersect(new Rectangle(0, 0, image.Width, image.Height)); // search zone's starting point int startX = 0; //zone.X; int startY = 0; // zone.Y; // get source and template image size int sourceWidth = image.Width; // zone.Width; int sourceHeight = image.Height; // zone.Height; int templateWidth = template.Width; int templateHeight = template.Height; // check template's size if ((templateWidth > sourceWidth) || (templateHeight > sourceHeight)) { throw new InvalidImagePropertiesException("Template's size should be smaller or equal to search zone."); } int pixelSize = (image.PixelFormat == PixelFormat.Format8bppIndexed) ? 1 : 3; int sourceStride = image.Stride; // similarity map. its size is increased by 4 from each side to increase // performance of non-maximum suppresion // 后面找相似度是否是最大的,是在5*5区域里找的,所以四个方向都扩大两个像素,这样就不需要检查边界条件 int mapWidth = sourceWidth - templateWidth + 1; int mapHeight = sourceHeight - templateHeight + 1; int[,] map = new int[mapHeight + 4, mapWidth + 4]; // maximum possible difference with template int maxDiff = templateWidth * templateHeight * pixelSize * 255; // integer similarity threshold int threshold = (int)(similarityThreshold * maxDiff); //iStep是步长,iStep个点里找一个点做比较,减少运算量 // width of template in bytes int templateWidthInBytes = templateWidth * pixelSize; // do the job unsafe { byte *baseSrc = (byte *)image.ImageData.ToPointer(); byte *baseTpl = (byte *)template.ImageData.ToPointer(); int sourceOffset = image.Stride - templateWidth * pixelSize; int templateOffset = template.Stride - templateWidth * pixelSize; for (int k = 0; k < pList.Count; k++) { TemplateMatch pItem = pList[k]; // for each row of the source image int y = pItem.Rectangle.Y; // y < pItem.Rectangle.Y+pItem.Rectangle.Height; y++) // for each pixel of the source image int x = pItem.Rectangle.X; // x < pItem.Rectangle.X+pItem.Rectangle.Width; x++) byte *src = baseSrc + sourceStride * (y + startY) + pixelSize * (x + startX); byte *tpl = baseTpl; // compare template with source image starting from current X,Y int dif = 0; // for each row of the template for (int i = 0; i < templateHeight; i++) { // for each pixel of the template int j = 0; for (j = 0; j < templateWidthInBytes; j++, src++, tpl++) { int d = *src - *tpl; dif += Math.Abs(d); } src += sourceOffset; tpl += templateOffset; } // templates similarity int sim = maxDiff - dif; if (sim >= threshold) { map[y + 2, x + 2] = sim; //相似度实际存储的位置比实际位置增加2,2,后面要减去2,2 } } } // collect interesting points - only those points, which are local maximums List <TemplateMatch> matchingsList = new List <TemplateMatch>(); // for each row for (int y = 2, maxY = mapHeight + 2; y < maxY; y++) { // for each pixel for (int x = 2, maxX = mapWidth + 2; x < maxX; x++) { int currentValue = map[y, x]; // for each windows' row for (int i = -2; (currentValue != 0) && (i <= 2); i++) { // for each windows' pixel for (int j = -2; j <= 2; j++) { if (map[y + i, x + j] > currentValue) { currentValue = 0;//如果周围有一个相似度比它大,就没找到 break; } } } // check if this point is really interesting if (currentValue != 0) {//如果找到了 matchingsList.Add(new TemplateMatch( new Rectangle(x - 2 + startX, y - 2 + startY, templateWidth, templateHeight), (float)currentValue / maxDiff)); } } } return(matchingsList); }
private bool checkSteadiness(TemplateMatch match) { if (match.Similarity < threshold) { if (--steady < -10) steady = -10; } else { if (++steady > 0) steady = 0; } return (steady != -10); }
public unsafe TemplateMatch[] ProcessImage(UnmanagedImage image, UnmanagedImage template, Rectangle searchZone) { if (((image.PixelFormat != PixelFormat.Format8bppIndexed) && (image.PixelFormat != PixelFormat.Format24bppRgb)) || (image.PixelFormat != template.PixelFormat)) { throw new UnsupportedImageFormatException("Unsupported pixel format of the source or template image."); } Rectangle rectangle = searchZone; rectangle.Intersect(new Rectangle(0, 0, image.Width, image.Height)); int x = rectangle.X; int y = rectangle.Y; int width = rectangle.Width; int height = rectangle.Height; int num5 = template.Width; int num6 = template.Height; if ((num5 > width) || (num6 > height)) { throw new InvalidImagePropertiesException("Template's size should be smaller or equal to search zone."); } int num7 = (image.PixelFormat == PixelFormat.Format8bppIndexed) ? 1 : 3; int stride = image.Stride; int num9 = (width - num5) + 1; int num10 = (height - num6) + 1; int[,] numArray = new int[num10 + 4, num9 + 4]; int num11 = ((num5 * num6) * num7) * 0xff; int num12 = (int)(this.similarityThreshold * num11); int num13 = num5 * num7; byte *numPtr = (byte *)image.ImageData.ToPointer(); byte *numPtr2 = (byte *)template.ImageData.ToPointer(); int num14 = image.Stride - (num5 * num7); int num15 = template.Stride - (num5 * num7); for (int i = 0; i < num10; i++) { for (int j = 0; j < num9; j++) { byte *numPtr3 = (numPtr + (stride * (i + y))) + (num7 * (j + x)); byte *numPtr4 = numPtr2; int num18 = 0; for (int k = 0; k < num6; k++) { int num20 = 0; while (num20 < num13) { int num21 = numPtr3[0] - numPtr4[0]; if (num21 > 0) { num18 += num21; } else { num18 -= num21; } num20++; numPtr3++; numPtr4++; } numPtr3 += num14; numPtr4 += num15; } int num22 = num11 - num18; if (num22 >= num12) { numArray[i + 2, j + 2] = num22; } } } List <TemplateMatch> list = new List <TemplateMatch>(); int num23 = 2; int num24 = num10 + 2; while (num23 < num24) { int num25 = 2; int num26 = num9 + 2; while (num25 < num26) { int num27 = numArray[num23, num25]; for (int m = -2; (num27 != 0) && (m <= 2); m++) { for (int n = -2; n <= 2; n++) { if (numArray[num23 + m, num25 + n] > num27) { num27 = 0; break; } } } if (num27 != 0) { list.Add(new TemplateMatch(new Rectangle((num25 - 2) + x, (num23 - 2) + y, num5, num6), ((float)num27) / ((float)num11))); } num25++; } num23++; } TemplateMatch[] array = new TemplateMatch[list.Count]; list.CopyTo(array); Array.Sort(array, new MatchingsSorter()); return(array); }
/// <summary> /// Process image looking for matchings with specified template. /// </summary> /// /// <param name="image">Unmanaged source image to process.</param> /// <param name="template">Unmanaged template image to search for.</param> /// <param name="searchZone">Rectangle in source image to search template for.</param> /// /// <returns>Returns array of found template matches. The array is sorted by similarity /// of found matches in descending order.</returns> /// /// <exception cref="UnsupportedImageFormatException">The source image has incorrect pixel format.</exception> /// <exception cref="InvalidImagePropertiesException">Template image is bigger than search zone.</exception> /// public TemplateMatch[] ProcessImage(UnmanagedImage image, UnmanagedImage template, Rectangle searchZone) { // check image format if ( ((image.PixelFormat != PixelFormat.Format8bppIndexed) && (image.PixelFormat != PixelFormat.Format24bppRgb)) || (image.PixelFormat != template.PixelFormat)) { throw new UnsupportedImageFormatException("Unsupported pixel format of the source or template image."); } // clip search zone var zone = searchZone; zone.Intersect(new Rectangle(0, 0, image.Width, image.Height)); // search zone's starting point var startX = zone.X; var startY = zone.Y; // get source and template image size var sourceWidth = zone.Width; var sourceHeight = zone.Height; var templateWidth = template.Width; var templateHeight = template.Height; // check template's size if ((templateWidth > sourceWidth) || (templateHeight > sourceHeight)) { throw new InvalidImagePropertiesException("Template's size should be smaller or equal to search zone."); } var pixelSize = (image.PixelFormat == PixelFormat.Format8bppIndexed) ? 1 : 3; var sourceStride = image.Stride; // similarity map. its size is increased by 4 from each side to increase // performance of non-maximum suppresion var mapWidth = sourceWidth - templateWidth + 1; var mapHeight = sourceHeight - templateHeight + 1; var map = new int[mapHeight + 4, mapWidth + 4]; // maximum possible difference with template var maxDiff = templateWidth * templateHeight * pixelSize * 255; // integer similarity threshold var threshold = (int)(similarityThreshold * maxDiff); // width of template in bytes var templateWidthInBytes = templateWidth * pixelSize; // do the job unsafe { var baseSrc = (byte *)image.ImageData.ToPointer(); var baseTpl = (byte *)template.ImageData.ToPointer(); var sourceOffset = image.Stride - templateWidth * pixelSize; var templateOffset = template.Stride - templateWidth * pixelSize; // for each row of the source image for (var y = 0; y < mapHeight; y++) { // for each pixel of the source image for (var x = 0; x < mapWidth; x++) { var src = baseSrc + sourceStride * (y + startY) + pixelSize * (x + startX); var tpl = baseTpl; // compare template with source image starting from current X,Y var dif = 0; // for each row of the template for (var i = 0; i < templateHeight; i++) { // for each pixel of the template for (var j = 0; j < templateWidthInBytes; j++, src++, tpl++) { var d = *src - *tpl; if (d > 0) { dif += d; } else { dif -= d; } } src += sourceOffset; tpl += templateOffset; } // templates similarity var sim = maxDiff - dif; if (sim >= threshold) { map[y + 2, x + 2] = sim; } } } } // collect interesting points - only those points, which are local maximums var matchingsList = new List <TemplateMatch>(); // for each row for (int y = 2, maxY = mapHeight + 2; y < maxY; y++) { // for each pixel for (int x = 2, maxX = mapWidth + 2; x < maxX; x++) { var currentValue = map[y, x]; // for each windows' row for (var i = -2; (currentValue != 0) && (i <= 2); i++) { // for each windows' pixel for (var j = -2; j <= 2; j++) { if (map[y + i, x + j] > currentValue) { currentValue = 0; break; } } } // check if this point is really interesting if (currentValue != 0) { matchingsList.Add(new TemplateMatch( new Rectangle(x - 2 + startX, y - 2 + startY, templateWidth, templateHeight), (float)currentValue / maxDiff)); } } } // convert list to array var matchings = new TemplateMatch[matchingsList.Count]; matchingsList.CopyTo(matchings); // sort in descending order Array.Sort(matchings, new MatchingsSorter()); return(matchings); }
public unsafe TemplateMatch[] ProcessImage(UnmanagedImage image, UnmanagedImage template, Rectangle searchZone) { if ((image.PixelFormat != PixelFormat.Format8bppIndexed && image.PixelFormat != PixelFormat.Format24bppRgb) || image.PixelFormat != template.PixelFormat) { throw new UnsupportedImageFormatException("Unsupported pixel format of the source or template image."); } Rectangle rectangle = searchZone; rectangle.Intersect(new Rectangle(0, 0, image.Width, image.Height)); int x = rectangle.X; int y = rectangle.Y; int width = rectangle.Width; int height = rectangle.Height; int width2 = template.Width; int height2 = template.Height; if (width2 > width || height2 > height) { throw new InvalidImagePropertiesException("Template's size should be smaller or equal to search zone."); } int num = (image.PixelFormat == PixelFormat.Format8bppIndexed) ? 1 : 3; int stride = image.Stride; int num2 = width - width2 + 1; int num3 = height - height2 + 1; int[,] array = new int[num3 + 4, num2 + 4]; int num4 = width2 * height2 * num * 255; int num5 = (int)(similarityThreshold * (float)num4); int num6 = width2 * num; byte *ptr = (byte *)image.ImageData.ToPointer(); byte *ptr2 = (byte *)template.ImageData.ToPointer(); int num7 = image.Stride - width2 * num; int num8 = template.Stride - width2 * num; for (int i = 0; i < num3; i++) { for (int j = 0; j < num2; j++) { byte *ptr3 = ptr + (long)stride * (long)(i + y) + (long)num * (long)(j + x); byte *ptr4 = ptr2; int num9 = 0; for (int k = 0; k < height2; k++) { int num10 = 0; while (num10 < num6) { int num11 = *ptr3 - *ptr4; num9 = ((num11 <= 0) ? (num9 - num11) : (num9 + num11)); num10++; ptr3++; ptr4++; } ptr3 += num7; ptr4 += num8; } int num12 = num4 - num9; if (num12 >= num5) { array[i + 2, j + 2] = num12; } } } List <TemplateMatch> list = new List <TemplateMatch>(); int l = 2; for (int num13 = num3 + 2; l < num13; l++) { int m = 2; for (int num14 = num2 + 2; m < num14; m++) { int num15 = array[l, m]; int num16 = -2; while (num15 != 0 && num16 <= 2) { for (int n = -2; n <= 2; n++) { if (array[l + num16, m + n] > num15) { num15 = 0; break; } } num16++; } if (num15 != 0) { list.Add(new TemplateMatch(new Rectangle(m - 2 + x, l - 2 + y, width2, height2), (float)num15 / (float)num4)); } } } TemplateMatch[] array2 = new TemplateMatch[list.Count]; list.CopyTo(array2); Array.Sort(array2, new MatchingsSorter()); return(array2); }
public TemplateMatch[] ProcessImage(UnmanagedImage image, UnmanagedImage template, Rectangle searchZone) { // Normalized Cross Correlation. // check image format if ( ((image.PixelFormat != PixelFormat.Format8bppIndexed) && (image.PixelFormat != PixelFormat.Format24bppRgb)) || (image.PixelFormat != template.PixelFormat)) { throw new UnsupportedImageFormatException("Unsupported pixel format of the source or template image."); } // clip search zone Rectangle zone = searchZone; zone.Intersect(new Rectangle(0, 0, image.Width, image.Height)); // search zone's starting point int startX = zone.X; int startY = zone.Y; // get source and template image size int sourceWidth = zone.Width; int sourceHeight = zone.Height; int templateWidth = template.Width; int templateHeight = template.Height; // check template's size if ((templateWidth > sourceWidth) || (templateHeight > sourceHeight)) { throw new InvalidImagePropertiesException("Template's size should be smaller or equal to search zone."); } int pixelSize = (image.PixelFormat == PixelFormat.Format8bppIndexed) ? 1 : 3; int sourceStride = image.Stride; // Similarity map. // Its size is increased by 4 in both dimensions to increase performance of non-maximum suppresion. int mapWidth = sourceWidth - templateWidth + 1; int mapHeight = sourceHeight - templateHeight + 1; float[,] map = new float[mapHeight + 4, mapWidth + 4]; // width of template in bytes int templateWidthInBytes = templateWidth * pixelSize; // Algorithm: // 1. compute mean of template. // 2. for each candidate in the search zone: // 2.a. Compute mean of candidate. // 2.b. Compute correlation coefficient. // 3. Suppress non-maxima and sort by correlation coeff. unsafe { // 1. compute mean of template. byte *baseTpl = (byte *)template.ImageData.ToPointer( ); byte *tpl = baseTpl; int templateOffset = template.Stride - templateWidthInBytes; int iTemplateTotal = 0; // for each row of the template for (int i = 0; i < templateHeight; i++) { // for each pixel of the template for (int j = 0; j < templateWidthInBytes; j++, tpl++) { iTemplateTotal += *tpl; } tpl += templateOffset; } double fMeanTemplate = (double)iTemplateTotal / (double)(templateHeight * templateWidthInBytes); // 2. Compute correlation coeff for each candidate in the search zone byte *baseSrc = (byte *)image.ImageData.ToPointer( ); int sourceOffset = image.Stride - templateWidth * pixelSize; // for each row of the search zone for (int y = 0; y < mapHeight; y++) { // for each pixel of the search zone for (int x = 0; x < mapWidth; x++) { byte *src = baseSrc + sourceStride * (y + startY) + pixelSize * (x + startX); // 2.a. Compute mean of candidate. int iCandidateTotal = 0; // for each row of the candidate for (int i = 0; i < templateHeight; i++) { // for each pixel of the candidate for (int j = 0; j < templateWidthInBytes; j++, src++) { iCandidateTotal += *src; } src += sourceOffset; } double fMeanCandidate = (double)iCandidateTotal / (double)(templateHeight * templateWidthInBytes); // 2.b Denominator. tpl = baseTpl; src = baseSrc + sourceStride * (y + startY) + pixelSize * (x + startX); double sit = 0; double sisq = 0; double stsq = 0; // for each row of the candidate for (int i = 0; i < templateHeight; i++) { // for each pixel of the candidate for (int j = 0; j < templateWidthInBytes; j++, tpl++, src++) { sit += ((*src - fMeanCandidate) * (*tpl - fMeanTemplate)); sisq += ((*src - fMeanCandidate) * (*src - fMeanCandidate)); stsq += ((*tpl - fMeanTemplate) * (*tpl - fMeanTemplate)); } src += sourceOffset; tpl += templateOffset; } // Correlation coeff for candidate x,y. // Map has a 2-pixel black border for non local-maxima suppression. map[y + 2, x + 2] = 0; if (sisq != 0 && stsq != 0) { // Add to map, filter out lower-than-threshold results. float fCorrCoeff = (float)(sit / System.Math.Sqrt(sisq * stsq)); if (fCorrCoeff >= similarityThreshold) { map[y + 2, x + 2] = fCorrCoeff; } } } } } // Reparse all results to suppress those that are not local maxima. List <TemplateMatch> matchingsList = new List <TemplateMatch>( ); // for each row of the result map. for (int y = 2, maxY = mapHeight + 2; y < maxY; y++) { // for each pixel of the result map. for (int x = 2, maxX = mapWidth + 2; x < maxX; x++) { float currentValue = map[y, x]; // Look for a better match in the 5² surrounding window. for (int i = -2; (currentValue != 0) && (i <= 2); i++) { for (int j = -2; j <= 2; j++) { if (map[y + i, x + j] > currentValue) { currentValue = 0; break; } } } // Save if really interesting. if (currentValue != 0) { matchingsList.Add(new TemplateMatch( new Rectangle(x - 2 + startX, y - 2 + startY, templateWidth, templateHeight), currentValue)); } } } // convert list to array TemplateMatch[] matchings = new TemplateMatch[matchingsList.Count]; matchingsList.CopyTo(matchings); // sort in descending order Array.Sort(matchings, new MatchingsSorter( )); return(matchings); }