public void ShlTest() { const int RepeatCount = 5; UlongRandomGenerator random = new UlongRandomGenerator(); ulong[] y = new ulong[3]; ulong[] copy = new ulong[3]; int size = y.Length * 64; for (int count = 0; count <= size; count++) { for (int pos = 0; pos < size - count; pos++) { for (int shift = 0; shift <= count; shift++) { for (int i = 0; i < RepeatCount; i++) { random.Generate(y.Length, y); Vectors.Copy(y.Length, y, 0, copy, 0); BitUtils.Shl(count, shift, y, pos); // right part that was not copied if (pos > 0) { Assert.IsTrue(BitUtils.Equals(pos, y, 0, copy, 0)); } // shifted part if (shift < count) { Assert.IsTrue(BitUtils.Equals(count - shift, y, pos + shift, copy, pos)); } // zeroed part if (shift > 0) { Assert.AreEqual(0, BitUtils.CountOneBits(shift, y, pos)); } // left part that was not copied if (pos + count < size) { Assert.IsTrue(BitUtils.Equals(size - (pos + count), y, pos + count, copy, pos + count)); } } } } } }
public void SetBitsTest() { const int Size = 3 * 64; ulong[] y = new ulong[3]; for (int count = 1; count < Size; count++) { for (int pos = 0; pos < Size - count; pos++) { y[0] = y[1] = y[2] = 0; BitUtils.SetBits(count, y, pos); Assert.AreEqual(count, BitUtils.CountOneBits(Size, y, 0)); Assert.AreEqual(pos, BitUtils.BitScanOneForward(Size, y, 0)); Assert.AreEqual(pos + count - 1, BitUtils.BitScanOneReverse(Size, y, Size - 1)); Assert.AreEqual(pos + count == Size ? -1 : pos + count, BitUtils.BitScanZeroForward(Size - pos, y, pos)); Assert.AreEqual(pos == 0 ? -1 : pos - 1, BitUtils.BitScanZeroReverse(pos + count, y, pos + count - 1)); } } }
/// <summary> /// De-skews the <see cref="Image"/> and aligns it horizontally. /// </summary> /// <param name="dst">The destination <see cref="Image"/>. Can be <b>null</b>.</param> /// <returns> /// The destination <see cref="Image"/>. /// </returns> /// <exception cref="NotImplementedException"> /// <see cref="Image{T}.BitsPerPixel"/> is not one. /// </exception> /// <remarks> /// <para>This method works with binary (1bpp) images only.</para> /// </remarks> public Image Deskew(Image dst) { if (this.BitsPerPixel != 1) { throw new NotImplementedException(Properties.Resources.E_UnsupportedDepth_1bpp); } int width = this.Width; int height = this.Height; int stride = this.Stride; ulong[] bits = this.Bits; // build histogram ulong endMask = this.EndMask; float[][] histogram = new float[stride][]; for (int ix = 0; ix < stride; ix++) { float[] h = histogram[ix] = new float[height]; ulong mask = ix == stride - 1 ? endMask : ulong.MaxValue; for (int iy = 0, off = ix; iy < height; iy++, off += stride) { h[iy] = BitUtils.CountOneBits(bits[off] & mask); } } // calculate image variance float angleBest = 0.0f; float varianceBest = EstimateSkewAngle(angleBest); // move up or down with 1 degree interval // move counterclockwise for (float angle = -1.0f; angle >= -10.0f; angle -= 1.0f) { float variance = EstimateSkewAngle(angle); if (variance <= varianceBest) { break; } varianceBest = variance; angleBest = angle; } if (angleBest == 0.0f) { // move clockwise for (float angle = 1.0f; angle <= 10.0f; angle += 1.0f) { float variance = EstimateSkewAngle(angle); if (variance <= varianceBest) { break; } varianceBest = variance; angleBest = angle; } } // move up or down with 0.1 degree interval // move counterclockwise float originalAngle = angleBest; for (float angle = angleBest - 0.1f, max = angleBest - 0.9f; angle >= max; angle -= 0.1f) { float variance = EstimateSkewAngle(angle); if (variance <= varianceBest) { break; } varianceBest = variance; angleBest = angle; } if (originalAngle == angleBest) { // move clockwise for (float angle = angleBest + 0.1f, max = angleBest + 0.9f; angle <= max; angle += 0.1f) { float variance = EstimateSkewAngle(angle); if (variance <= varianceBest) { break; } varianceBest = variance; angleBest = angle; } } return(this.Rotate(dst, -angleBest, BorderType.BorderRepl, 0)); float EstimateSkewAngle(float angle) { const float PiConv = 3.1415926535f / 180.0f; int centerX = width / 2; float dblTanA = (float)Math.Tan(angle * PiConv); float[] ds = new float[height]; for (int ix = 0; ix < stride; ix++) { // negative shift is down int shiftY = (dblTanA * (centerX - (ix * 64) - 32)).Round(); Mathematics.Add( height - Math.Abs(shiftY), histogram[ix], shiftY < 0 ? 0 : shiftY, ds, shiftY < 0 ? -shiftY : 0); } return(ds.Variance()); } }