Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Added descew functions from leptonica - #11

  • Loading branch information...
commit 937ed0feba912a161054153ff914273aa2369771 1 parent 289a28b
@charlesw authored
View
7 Tesseract.Net20/Interop/LeptonicaApi.cs
@@ -86,6 +86,13 @@ static LeptonicaApi()
[DllImport(Constants.LeptonicaDllName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "pixDestroyColormap")]
public static extern int pixDestroyColormap(IntPtr pix);
+ // image analysis and manipulation functions
+
+ // skew
+
+ [DllImport(Constants.LeptonicaDllName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "pixDeskewGeneral")]
+ public static extern IntPtr pixDeskewGeneral(IntPtr pix, int redSweep, float sweepRange, float sweepDelta, int redSearch, int thresh, out float pAngle, out float pConf);
+
#endregion
#region Color map
View
139 Tesseract.Net20/Pix.cs
@@ -6,6 +6,16 @@ namespace Tesseract
{
public unsafe sealed class Pix : DisposableBase
{
+ #region Constants
+
+ // Skew Defaults
+ public const int DefaultBinarySearchReduction = 2; // binary search part
+ public const int DefaultBinaryThreshold = 130;
+
+ #endregion
+
+ #region Fields
+
private static readonly List<int> AllowedDepths = new List<int> { 1, 2, 4, 8, 16, 32 };
private IntPtr handle;
@@ -14,6 +24,11 @@ public unsafe sealed class Pix : DisposableBase
private readonly int height;
private readonly int depth;
+ #endregion
+
+
+ #region Create\Load methods
+
public static Pix Create(int width, int height, int depth)
{
if (!AllowedDepths.Contains(depth))
@@ -43,25 +58,7 @@ public static Pix LoadFromFile(string filename)
}
return Create(pixHandle);
}
-
- public PixColormap Colormap
- {
- get { return colormap; }
- set
- {
- if (value != null) {
- if (Interop.LeptonicaApi.pixSetColormap(Handle, value.Handle) == 0) {
- colormap = value;
- }
- } else {
- if (Interop.LeptonicaApi.pixDestroyColormap(Handle) == 0) {
- colormap = null;
- }
- }
- }
- }
-
-
+
/// <summary>
/// Creates a new pix instance using an existing handle to a pix structure.
/// </summary>
@@ -83,11 +80,24 @@ private Pix(IntPtr handle)
}
}
+ #endregion
- public void Save(string filename, ImageFormat format = ImageFormat.Default)
+ #region Properties
+
+ public PixColormap Colormap
{
- if (Interop.LeptonicaApi.pixWrite(filename, handle, format) != 0) {
- throw new IOException(String.Format("Failed to save image '{0}'.", filename));
+ get { return colormap; }
+ set
+ {
+ if (value != null) {
+ if (Interop.LeptonicaApi.pixSetColormap(Handle, value.Handle) == 0) {
+ colormap = value;
+ }
+ } else {
+ if (Interop.LeptonicaApi.pixDestroyColormap(Handle) == 0) {
+ colormap = null;
+ }
+ }
}
}
@@ -116,9 +126,94 @@ public IntPtr Handle
get { return handle; }
}
+ #endregion
+
+ #region Methods
+
+
+ public void Save(string filename, ImageFormat format = ImageFormat.Default)
+ {
+ if (Interop.LeptonicaApi.pixWrite(filename, handle, format) != 0) {
+ throw new IOException(String.Format("Failed to save image '{0}'.", filename));
+ }
+ }
+
+ // image manipulation
+
+ /// <summary>
+ /// Determines the scew angle and if confidence is high enough returns the descewed image as the result, otherwise returns clone of original image.
+ /// </summary>
+ /// <remarks>
+ /// This binarizes if necessary and finds the skew angle. If the
+ /// angle is large enough and there is sufficient confidence,
+ /// it returns a deskewed image; otherwise, it returns a clone.
+ /// </remarks>
+ /// <returns>Returns deskewed image if confidence was high enough, otherwise returns clone of original pix.</returns>
+ public Pix Deskew()
+ {
+ Scew scew;
+ return Deskew(DefaultBinarySearchReduction, out scew);
+ }
+
+ /// <summary>
+ /// Determines the scew angle and if confidence is high enough returns the descewed image as the result, otherwise returns clone of original image.
+ /// </summary>
+ /// <remarks>
+ /// This binarizes if necessary and finds the skew angle. If the
+ /// angle is large enough and there is sufficient confidence,
+ /// it returns a deskewed image; otherwise, it returns a clone.
+ /// </remarks>
+ /// <param name="scew">The scew angle and confidence</param>
+ /// <returns>Returns deskewed image if confidence was high enough, otherwise returns clone of original pix.</returns>
+ public Pix Deskew(out Scew scew)
+ {
+ return Deskew(DefaultBinarySearchReduction, out scew);
+ }
+
+ /// <summary>
+ /// Determines the scew angle and if confidence is high enough returns the descewed image as the result, otherwise returns clone of original image.
+ /// </summary>
+ /// <remarks>
+ /// This binarizes if necessary and finds the skew angle. If the
+ /// angle is large enough and there is sufficient confidence,
+ /// it returns a deskewed image; otherwise, it returns a clone.
+ /// </remarks>
+ /// <param name="redSearch">The reduction factor used by the binary search, can be 1, 2, or 4.</param>
+ /// <param name="scew">The scew angle and confidence</param>
+ /// <returns>Returns deskewed image if confidence was high enough, otherwise returns clone of original pix.</returns>
+ public Pix Deskew(int redSearch, out Scew scew)
+ {
+ return Deskew(ScewSweep.Default, redSearch, DefaultBinaryThreshold, out scew);
+ }
+
+ /// <summary>
+ /// Determines the scew angle and if confidence is high enough returns the descewed image as the result, otherwise returns clone of original image.
+ /// </summary>
+ /// <remarks>
+ /// This binarizes if necessary and finds the skew angle. If the
+ /// angle is large enough and there is sufficient confidence,
+ /// it returns a deskewed image; otherwise, it returns a clone.
+ /// </remarks>
+ /// <param name="sweep">linear sweep parameters</param>
+ /// <param name="redSearch">The reduction factor used by the binary search, can be 1, 2, or 4.</param>
+ /// <param name="thresh">The threshold value used for binarizing the image.</param>
+ /// <param name="scew">The scew angle and confidence</param>
+ /// <returns>Returns deskewed image if confidence was high enough, otherwise returns clone of original pix.</returns>
+ public Pix Deskew(ScewSweep sweep, int redSearch, int thresh, out Scew scew)
+ {
+ float pAngle, pConf;
+ var resultPixHandle = Interop.LeptonicaApi.pixDeskewGeneral(handle, sweep.Reduction, sweep.Range, sweep.Delta, redSearch, thresh, out pAngle, out pConf);
+ if (resultPixHandle == IntPtr.Zero) throw new TesseractException("Failed to deskew image.");
+ scew = new Scew(pAngle, pConf);
+ return new Pix(resultPixHandle);
+ }
+
protected override void Dispose(bool disposing)
{
Interop.LeptonicaApi.pixDestroy(ref handle);
}
+
+ #endregion
+
}
}
View
71 Tesseract.Net20/Scew.cs
@@ -0,0 +1,71 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Tesseract
+{
+ public struct Scew
+ {
+ private float angle;
+ private float confidence;
+
+ public Scew(float angle, float confidence)
+ {
+ this.angle = angle;
+ this.confidence = confidence;
+ }
+
+ public float Angle
+ {
+ get { return angle; }
+ }
+
+
+ public float Confidence
+ {
+ get { return confidence; }
+ }
+
+ #region ToString
+
+ public override string ToString()
+ {
+ return String.Format("Scew: {0} [conf: {1}]", Angle, Confidence);
+ }
+
+ #endregion
+
+ #region Equals and GetHashCode implementation
+ public override bool Equals(object obj)
+ {
+ return (obj is Scew) && Equals((Scew)obj);
+ }
+
+ public bool Equals(Scew other)
+ {
+ return this.confidence == other.confidence && this.angle == other.angle;
+ }
+
+ public override int GetHashCode()
+ {
+ int hashCode = 0;
+ unchecked {
+ hashCode += 1000000007 * angle.GetHashCode();
+ hashCode += 1000000009 * confidence.GetHashCode();
+ }
+ return hashCode;
+ }
+
+ public static bool operator ==(Scew lhs, Scew rhs)
+ {
+ return lhs.Equals(rhs);
+ }
+
+ public static bool operator !=(Scew lhs, Scew rhs)
+ {
+ return !(lhs == rhs);
+ }
+ #endregion
+
+ }
+}
View
57 Tesseract.Net20/ScewSweep.cs
@@ -0,0 +1,57 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Tesseract
+{
+ /// <summary>
+ /// Represents the parameters for a sweep search used by scew algorithms.
+ /// </summary>
+ public struct ScewSweep
+ {
+ public static ScewSweep Default = new ScewSweep(DefaultReduction, DefaultRange, DefaultDelta);
+
+ #region Constants and Fields
+
+ public const int DefaultReduction = 4; // Sweep part; 4 is good
+ public const float DefaultRange = 7.0F;
+ public const float DefaultDelta = 1.0F;
+
+ private int reduction;
+ private float range;
+ private float delta;
+
+ #endregion
+
+ #region Factory Methods + Constructor
+
+ public ScewSweep(int reduction = DefaultReduction, float range = DefaultRange, float delta = DefaultDelta)
+ {
+ this.reduction = reduction;
+ this.range = range;
+ this.delta = delta;
+ }
+
+ #endregion
+
+ #region Properties
+
+ public int Reduction
+ {
+ get { return reduction; }
+ }
+
+ public float Range
+ {
+ get { return range; }
+ }
+
+ public float Delta
+ {
+ get { return delta; }
+ }
+
+ #endregion
+
+ }
+}
View
2  Tesseract.Net20/Tesseract.Net20.csproj
@@ -61,6 +61,8 @@
<Compile Include="BitmapToPixConverter.cs" />
<Compile Include="PixColor.cs" />
<Compile Include="DisposableBase.cs" />
+ <Compile Include="Scew.cs" />
+ <Compile Include="ScewSweep.cs" />
<Compile Include="TesseractEngine.cs" />
<Compile Include="EngineConfig.cs" />
<Compile Include="EngineMode.cs" />
View
6 Tesseract.Net40/Tesseract.Net40.csproj
@@ -135,6 +135,12 @@
<Compile Include="..\Tesseract.Net20\ResultIterator.cs">
<Link>ResultIterator.cs</Link>
</Compile>
+ <Compile Include="..\Tesseract.Net20\Scew.cs">
+ <Link>Scew.cs</Link>
+ </Compile>
+ <Compile Include="..\Tesseract.Net20\ScewSweep.cs">
+ <Link>ScewSweep.cs</Link>
+ </Compile>
<Compile Include="..\Tesseract.Net20\TesseractEngine.cs">
<Link>TesseractEngine.cs</Link>
</Compile>
View
6 Tesseract.Net45/Tesseract.Net45.csproj
@@ -135,6 +135,12 @@
<Compile Include="..\Tesseract.Net20\ResultIterator.cs">
<Link>ResultIterator.cs</Link>
</Compile>
+ <Compile Include="..\Tesseract.Net20\Scew.cs">
+ <Link>Scew.cs</Link>
+ </Compile>
+ <Compile Include="..\Tesseract.Net20\ScewSweep.cs">
+ <Link>ScewSweep.cs</Link>
+ </Compile>
<Compile Include="..\Tesseract.Net20\TesseractEngine.cs">
<Link>TesseractEngine.cs</Link>
</Compile>
View
7 Tesseract.Tests.Console/Program.cs
@@ -10,8 +10,11 @@ class Program
{
static void Main(string[] args)
{
- var testFixture = new Tesseract.Tests.Leptonica.ConvertBitmapToPixTests();
- testFixture.Convert_PixToBitmap("photo_8.bmp", true);
+ //var testFixture = new Tesseract.Tests.Leptonica.ConvertBitmapToPixTests();
+ //testFixture.Convert_PixToBitmap("photo_8.bmp", true);
+
+ var testFixture = new Tesseract.Tests.Leptonica.PixTests.ScewTests();
+ testFixture.DescewTest();
}
}
}
View
4 Tesseract.Tests.Console/Tesseract.Tests.Console.csproj
@@ -14,7 +14,7 @@
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<DebugSymbols>true</DebugSymbols>
- <OutputPath>bin\x86\Debug\</OutputPath>
+ <OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
@@ -24,7 +24,7 @@
<AllowUnsafeBlocks>false</AllowUnsafeBlocks>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
- <OutputPath>bin\x86\Release\</OutputPath>
+ <OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
View
BIN  Tesseract.Tests/Data/Scew/scewed-phototest.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
2  ...act.Tests/Leptonica/PixDataAccessTests.cs → .../Leptonica/PixTests/PixDataAccessTests.cs
@@ -4,7 +4,7 @@
using System.Text;
using NUnit.Framework;
-namespace Tesseract.Tests.Leptonica
+namespace Tesseract.Tests.Leptonica.PixTests
{
[TestFixture]
public unsafe class DataAccessTests
View
26 Tesseract.Tests/Leptonica/PixTests/ScewTests.cs
@@ -0,0 +1,26 @@
+using NUnit.Framework;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Tesseract.Tests.Leptonica.PixTests
+{
+ [TestFixture]
+ public class ScewTests
+ {
+ [Test]
+ public void DescewTest()
+ {
+ using(var sourcePix = Pix.LoadFromFile(@".\Data\Scew\scewed-phototest.png")) {
+ Scew scew;
+ using (var descewedImage = sourcePix.Deskew(new ScewSweep(range: 45), Pix.DefaultBinarySearchReduction, Pix.DefaultBinaryThreshold, out scew)) {
+ Assert.That(scew.Angle, Is.EqualTo(-9.953125F).Within(0.00001));
+ Assert.That(scew.Confidence, Is.EqualTo(3.782913F).Within(0.00001));
+ descewedImage.Save("descewedImage.bmp");
+ }
+ }
+ }
+ }
+}
View
6 Tesseract.Tests/Tesseract.Tests.csproj
@@ -69,7 +69,8 @@
<Compile Include="Leptonica\ColorTests.cs" />
<Compile Include="Leptonica\ConvertBitmapToPixTests.cs" />
<Compile Include="Leptonica\LoadFromFileTests.cs" />
- <Compile Include="Leptonica\PixDataAccessTests.cs" />
+ <Compile Include="Leptonica\PixTests\PixDataAccessTests.cs" />
+ <Compile Include="Leptonica\PixTests\ScewTests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="TesseractResultSet.cs" />
</ItemGroup>
@@ -95,6 +96,9 @@
<Content Include="Data\Conversion\photo_8.bmp">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
+ <Content Include="Data\Scew\scewed-phototest.png">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
<Content Include="phototest.tif">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
Please sign in to comment.
Something went wrong with that request. Please try again.