private static Gray <byte>[,] SpreadOrientations(Gray <byte>[,] quantizedOrientationImage, int neghborhood) { var destImg = quantizedOrientationImage.CopyBlank(); using (var uQuantizedOrientationImage = quantizedOrientationImage.Lock()) using (var uDestImg = destImg.Lock()) { byte *srcImgPtr = (byte *)uQuantizedOrientationImage.ImageData; int imgStride = uQuantizedOrientationImage.Stride; byte *destImgPtr = (byte *)uDestImg.ImageData; int imgHeight = uDestImg.Height; int imgWidth = uDestImg.Width; for (int row = 0; row < neghborhood; row++) { int subImageHeight = imgHeight - row; for (int col = 0; col < neghborhood; col++) { OrImageBits(&srcImgPtr[col], destImgPtr, imgStride, imgWidth - col, subImageHeight); } srcImgPtr += imgStride; } } return(destImg); }
/// <summary> /// Computes gradient orientations from the color image. Orientation from the channel which has the maximum gradient magnitude is taken as the orientation for a location. /// </summary> /// <param name="frame">Image.</param> /// <param name="magnitudeSqrImage">Squared magnitude image.</param> /// <param name="minValidMagnitude">Minimal valid magnitude.</param> /// <returns>Orientation image (angles are in degrees).</returns> public unsafe static Gray <int>[,] Compute(Bgr <byte>[,] frame, out Gray <int>[,] magnitudeSqrImage, int minValidMagnitude) { var minSqrMagnitude = minValidMagnitude * minValidMagnitude; var orientationImage = new Gray <int> [frame.Height(), frame.Width()]; var _magnitudeSqrImage = orientationImage.CopyBlank(); using (var uFrame = frame.Lock()) { ParallelLauncher.Launch(thread => { computeColor(thread, (byte *)uFrame.ImageData, uFrame.Stride, orientationImage, _magnitudeSqrImage, minSqrMagnitude); }, frame.Width() - 2 * kernelRadius, frame.Height() - 2 * kernelRadius); } magnitudeSqrImage = _magnitudeSqrImage; return(orientationImage); }
/// <summary> /// Take only those orientations that have MINIMAL_NUM_OF_SAME_ORIENTED_PIXELS in 3x3 negborhood. /// Performs angle transformation into binary form ([0..7] -> [1, 2, 4, 8, ..., 128]) as well. /// </summary> /// <param name="qunatizedOrientionImg">Quantized orientation image where angles are represented by lables [0..GlobalParameters.NUM_OF_QUNATIZED_ORIENTATIONS] (invalid orientation label included).</param> /// <param name="minSameOrientations">Minimal number of same orientations for 3x3 neigborhood. The range is: [0..9] (3x3 neigborhood).</param> private static Gray <byte>[,] RetainImportantQuantizedOrientations(Gray <byte>[,] qunatizedOrientionImg, int minSameOrientations) { if (minSameOrientations < 0 || minSameOrientations > 9 /*3x3 neigborhood*/) { throw new Exception("Minimal number of same orientations should be in: [0..9]."); } var quantizedFilteredOrient = qunatizedOrientionImg.CopyBlank(); using (var uQunatizedOrientionImg = qunatizedOrientionImg.Lock()) using (var uQuantizedFilteredOrient = quantizedFilteredOrient.Lock()) { //debugImg = new Image<Hsv, byte>(orientDegImg.Width, orientDegImg.Height); //debugImg = null; int qOrinetStride = uQunatizedOrientionImg.Stride; int qOrinetAllign = uQunatizedOrientionImg.Stride - uQunatizedOrientionImg.Width; byte *qOrinetUnfilteredPtr = (byte *)uQunatizedOrientionImg.ImageData + qOrinetStride + 1; byte *qOrinetFilteredPtr = (byte *)uQuantizedFilteredOrient.ImageData + qOrinetStride + 1; //Debug.Assert(qunatizedOrientionImg.Stride == quantizedFilteredOrient.Stride); int imgWidth = uQunatizedOrientionImg.Width; int imgHeight = uQunatizedOrientionImg.Height; for (int j = 1; j < imgHeight - 1; j++) { for (int i = 1; i < imgWidth - 1; i++) { if (*qOrinetUnfilteredPtr != INVALID_QUANTIZED_ORIENTATION) { byte[] histogram = new byte[INVALID_QUANTIZED_ORIENTATION + 1]; //gleda se susjedstvo 3x3 histogram[qOrinetUnfilteredPtr[-qOrinetStride - 1]]++; histogram[qOrinetUnfilteredPtr[-qOrinetStride + 0]]++; histogram[qOrinetUnfilteredPtr[-qOrinetStride + 1]]++; histogram[qOrinetUnfilteredPtr[-1]]++; histogram[qOrinetUnfilteredPtr[0]]++; histogram[qOrinetUnfilteredPtr[+1]]++; histogram[qOrinetUnfilteredPtr[+qOrinetStride - 1]]++; histogram[qOrinetUnfilteredPtr[+qOrinetStride + 0]]++; histogram[qOrinetUnfilteredPtr[+qOrinetStride + 1]]++; int maxBinVotes = 0; byte quantizedAngle = 0; // find the max direction in the 3x3 box for (byte histBinIdx = 0; histBinIdx < GlobalParameters.NUM_OF_QUNATIZED_ORIENTATIONS /*discard invalid orientation*/; histBinIdx++) { if (histogram[histBinIdx] > maxBinVotes) { maxBinVotes = histogram[histBinIdx]; quantizedAngle = histBinIdx; } } if (maxBinVotes >= minSameOrientations) { *qOrinetFilteredPtr = (byte)(1 << quantizedAngle); //[1,2,4,8...128] (8 orientations) } //*qOrinetFilteredPtr = (byte)(1 << *qOrinetUnfilteredPtr); //[1,2,4,8...128] (8 orientations) //debugImg[j, i] = new Hsv((*qOrinetFilteredPtr-1) * 35, 100, 100); } qOrinetUnfilteredPtr++; qOrinetFilteredPtr++; } qOrinetUnfilteredPtr += 1 + qOrinetAllign + 1; qOrinetFilteredPtr += 1 + qOrinetAllign + 1; //preskoči zadnji piksel, poravnanje, i početni piksel } } //magnitudeImg.Save("magnitude.bmp"); //quantizedFilteredOrient.Save("quantizedImg.bmp"); return(quantizedFilteredOrient); }