/// <summary> /// 梯度给Hog单元投票 /// </summary> /// <param name="ge">梯度</param> public void VoteHogCell(GradientElement ge, int partnum) { for (int i = 0; i < partnum; i++) { if (ge.theta >= HistElements[i].theta && ge.theta < HistElements[i].theta + Math.PI / partnum) { HistElements[i].rho += ge.rho; break; } } }
/// <summary> /// 给Hog图投票 /// </summary> /// <param name="bmpX">投票像素点X坐标</param> /// <param name="bmpY">投票像素点Y坐标</param> /// <param name="ge">投票像素点梯度向量(rho, theta)</param> private void VoteHog(int bmpX, int bmpY, GradientElement ge) { if (bmpX >= StartX && bmpX < StartX + HogSize.Width * CellSize.Width && bmpY >= StartY && bmpY < StartY + HogSize.Height * CellSize.Height) { int hogCellX = (bmpX - StartX) / CellSize.Width; int hogCellY = (bmpY - StartY) / CellSize.Height; int hogCellIndex = hogCellX + hogCellY * HogSize.Width; HogCells[hogCellIndex].VoteHogCell(ge, PartNumber); } }
/// <summary> /// 从位图(灰度图)中获取Hog图,位图像素是以从左到右、从下到上的顺序在内存中从低地址排列到高地址 /// 但是C#的Bitmap对象好像把这顺序颠倒过来了,根据实际经验发现,在BitmapData中,位图数据以从左到 /// 右、从上到下的顺序排列,和图像坐标的顺序一致 /// </summary> /// <param name="bitmapSource">源位图</param> /// <param name="cellHeight">单元的高度</param> /// <param name="cellWidth">单元的宽度</param> /// <param name="partNumber">PI弧度等分数</param> /// <returns>Hog图</returns> public static HogGram GetHogFromBitmap(Bitmap bitmapSource, int cellWidth, int cellHeight, int partNumber) { HogGram hogGram = null; if (bitmapSource != null && bitmapSource.PixelFormat == PixelFormat.Format8bppIndexed) { int width = bitmapSource.Width; int height = bitmapSource.Height; hogGram = new HogGram(width, height, cellWidth, cellHeight, partNumber); if (hogGram == null) { return(hogGram); } Rectangle rect = new Rectangle(0, 0, width, height); // 获得位图内容数据 BitmapData dataSource = bitmapSource.LockBits(rect, ImageLockMode.ReadOnly, bitmapSource.PixelFormat); // Stride为位图中每一行以4字节对齐的行宽 int strideSource = dataSource.Stride; unsafe { byte *ptrSource = (byte *)dataSource.Scan0.ToPointer(); byte *ptr1 = null; for (int row = 0; row < height; row++) { ptr1 = ptrSource + strideSource * row; for (int col = 0; col < width; col++) { GradientElement ge = new GradientElement(); if (row == 0 || row == height - 1 || col == 0 || col == width - 1) { ge.rho = 0; ge.theta = 0; } else { // 位图的在内存中的排列是从左到右,从下到上的,但BitmapData貌似做了优化,把位图数据在内存中的排列 // 顺序改为与坐标系一致,即从左到右、从上到下 double gradX = *(ptr1 + 1) - *(ptr1 - 1); double gradY = *(ptr1 + strideSource) - *(ptr1 - strideSource); ge.rho = Math.Sqrt(gradX * gradX + gradY * gradY); ge.theta = Math.Atan2(gradY, gradX); // 注意坐标系是垂直翻转的 } int bmpX = col; int bmpY = row; //int bmpY = height - 1 - row; // 由于BitmapData自动颠倒了位图存储序,所以这个写法是错的。 hogGram.VoteHog(bmpX, bmpY, ge); ptr1++; } } } bitmapSource.UnlockBits(dataSource); } return(hogGram); }