Skip to content

Commit

Permalink
Added descew functions from leptonica - #11
Browse files Browse the repository at this point in the history
  • Loading branch information
charlesw committed Mar 29, 2013
1 parent 289a28b commit 937ed0f
Show file tree
Hide file tree
Showing 13 changed files with 305 additions and 28 deletions.
7 changes: 7 additions & 0 deletions Tesseract.Net20/Interop/LeptonicaApi.cs
Expand Up @@ -86,6 +86,13 @@ static LeptonicaApi()
[DllImport(Constants.LeptonicaDllName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "pixDestroyColormap")] [DllImport(Constants.LeptonicaDllName, CallingConvention = CallingConvention.Cdecl, EntryPoint = "pixDestroyColormap")]
public static extern int pixDestroyColormap(IntPtr pix); 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 #endregion


#region Color map #region Color map
Expand Down
139 changes: 117 additions & 22 deletions Tesseract.Net20/Pix.cs
Expand Up @@ -6,6 +6,16 @@ namespace Tesseract
{ {
public unsafe sealed class Pix : DisposableBase 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 static readonly List<int> AllowedDepths = new List<int> { 1, 2, 4, 8, 16, 32 };


private IntPtr handle; private IntPtr handle;
Expand All @@ -14,6 +24,11 @@ public unsafe sealed class Pix : DisposableBase
private readonly int height; private readonly int height;
private readonly int depth; private readonly int depth;


#endregion


#region Create\Load methods

public static Pix Create(int width, int height, int depth) public static Pix Create(int width, int height, int depth)
{ {
if (!AllowedDepths.Contains(depth)) if (!AllowedDepths.Contains(depth))
Expand Down Expand Up @@ -43,25 +58,7 @@ public static Pix LoadFromFile(string filename)
} }
return Create(pixHandle); 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> /// <summary>
/// Creates a new pix instance using an existing handle to a pix structure. /// Creates a new pix instance using an existing handle to a pix structure.
/// </summary> /// </summary>
Expand All @@ -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) { get { return colormap; }
throw new IOException(String.Format("Failed to save image '{0}'.", filename)); set
{
if (value != null) {
if (Interop.LeptonicaApi.pixSetColormap(Handle, value.Handle) == 0) {
colormap = value;
}
} else {
if (Interop.LeptonicaApi.pixDestroyColormap(Handle) == 0) {
colormap = null;
}
}
} }
} }


Expand Down Expand Up @@ -116,9 +126,94 @@ public IntPtr Handle
get { return 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) protected override void Dispose(bool disposing)
{ {
Interop.LeptonicaApi.pixDestroy(ref handle); Interop.LeptonicaApi.pixDestroy(ref handle);
} }

#endregion

} }
} }
71 changes: 71 additions & 0 deletions 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

}
}
57 changes: 57 additions & 0 deletions 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

}
}
2 changes: 2 additions & 0 deletions Tesseract.Net20/Tesseract.Net20.csproj
Expand Up @@ -61,6 +61,8 @@
<Compile Include="BitmapToPixConverter.cs" /> <Compile Include="BitmapToPixConverter.cs" />
<Compile Include="PixColor.cs" /> <Compile Include="PixColor.cs" />
<Compile Include="DisposableBase.cs" /> <Compile Include="DisposableBase.cs" />
<Compile Include="Scew.cs" />
<Compile Include="ScewSweep.cs" />
<Compile Include="TesseractEngine.cs" /> <Compile Include="TesseractEngine.cs" />
<Compile Include="EngineConfig.cs" /> <Compile Include="EngineConfig.cs" />
<Compile Include="EngineMode.cs" /> <Compile Include="EngineMode.cs" />
Expand Down
6 changes: 6 additions & 0 deletions Tesseract.Net40/Tesseract.Net40.csproj
Expand Up @@ -135,6 +135,12 @@
<Compile Include="..\Tesseract.Net20\ResultIterator.cs"> <Compile Include="..\Tesseract.Net20\ResultIterator.cs">
<Link>ResultIterator.cs</Link> <Link>ResultIterator.cs</Link>
</Compile> </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"> <Compile Include="..\Tesseract.Net20\TesseractEngine.cs">
<Link>TesseractEngine.cs</Link> <Link>TesseractEngine.cs</Link>
</Compile> </Compile>
Expand Down
6 changes: 6 additions & 0 deletions Tesseract.Net45/Tesseract.Net45.csproj
Expand Up @@ -135,6 +135,12 @@
<Compile Include="..\Tesseract.Net20\ResultIterator.cs"> <Compile Include="..\Tesseract.Net20\ResultIterator.cs">
<Link>ResultIterator.cs</Link> <Link>ResultIterator.cs</Link>
</Compile> </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"> <Compile Include="..\Tesseract.Net20\TesseractEngine.cs">
<Link>TesseractEngine.cs</Link> <Link>TesseractEngine.cs</Link>
</Compile> </Compile>
Expand Down
7 changes: 5 additions & 2 deletions Tesseract.Tests.Console/Program.cs
Expand Up @@ -10,8 +10,11 @@ class Program
{ {
static void Main(string[] args) static void Main(string[] args)
{ {
var testFixture = new Tesseract.Tests.Leptonica.ConvertBitmapToPixTests(); //var testFixture = new Tesseract.Tests.Leptonica.ConvertBitmapToPixTests();
testFixture.Convert_PixToBitmap("photo_8.bmp", true); //testFixture.Convert_PixToBitmap("photo_8.bmp", true);

var testFixture = new Tesseract.Tests.Leptonica.PixTests.ScewTests();
testFixture.DescewTest();
} }
} }
} }
4 changes: 2 additions & 2 deletions Tesseract.Tests.Console/Tesseract.Tests.Console.csproj
Expand Up @@ -14,7 +14,7 @@
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<DebugSymbols>true</DebugSymbols> <DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x86\Debug\</OutputPath> <OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants> <DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType> <DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget> <PlatformTarget>x86</PlatformTarget>
Expand All @@ -24,7 +24,7 @@
<AllowUnsafeBlocks>false</AllowUnsafeBlocks> <AllowUnsafeBlocks>false</AllowUnsafeBlocks>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<OutputPath>bin\x86\Release\</OutputPath> <OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants> <DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize> <Optimize>true</Optimize>
<DebugType>pdbonly</DebugType> <DebugType>pdbonly</DebugType>
Expand Down
Binary file added 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.
Expand Up @@ -4,7 +4,7 @@
using System.Text; using System.Text;
using NUnit.Framework; using NUnit.Framework;


namespace Tesseract.Tests.Leptonica namespace Tesseract.Tests.Leptonica.PixTests
{ {
[TestFixture] [TestFixture]
public unsafe class DataAccessTests public unsafe class DataAccessTests
Expand Down

0 comments on commit 937ed0f

Please sign in to comment.