Permalink
Browse files

#2 added Enhance.Imaging with CropAndStraighten *enhancer*

  • Loading branch information...
1 parent a904828 commit 34eeae1e41af5e6ad15dcee6ce63b64ab2a0f63b Jesper Larsen-Ledet committed Mar 14, 2012
View
43 src/Enhance.Imaging/BitmapExtensions.cs
@@ -0,0 +1,43 @@
+using System;
+using System.ComponentModel;
+using System.Windows;
+using System.Windows.Media.Imaging;
+
+namespace Enhance.Imaging
+{
+ ///<summary>
+ /// Contains extension methods for System.Drawing.Bitmap classes
+ ///</summary>
+ public static class BitmapExtensions
+ {
+ ///<summary>
+ /// Converts a System.Drawing.Bitmap to a System.Windows.Media.Imaging.BitmapSource
+ ///</summary>
+ ///<param name="source">The bitmap to convert</param>
+ ///<returns>The converted bitmap</returns>
+ public static BitmapSource ToBitmapSource(this System.Drawing.Bitmap source)
+ {
+ var bitmapHandle = IntPtr.Zero;
+ try
+ {
+ bitmapHandle = source.GetHbitmap();
+ var result = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(bitmapHandle, IntPtr.Zero, Int32Rect.Empty,
+ BitmapSizeOptions.FromEmptyOptions());
+ result.Freeze();
+ source.Dispose();
+ return result;
+ }
+ catch (Win32Exception ex)
+ {
+ throw new ImagingException("Failed to create BitmapSource", ex);
+ }
+ finally
+ {
+ if (bitmapHandle != IntPtr.Zero)
+ {
+ NativeMethods.DeleteObject(bitmapHandle);
+ }
+ }
+ }
+ }
+}
View
71 src/Enhance.Imaging/CropAndStraighten.cs
@@ -0,0 +1,71 @@
+using System.Collections.Generic;
+using System.Drawing;
+using System.Drawing.Imaging;
+using System.Linq;
+using AForge.Imaging;
+using AForge.Imaging.Filters;
+
+namespace Enhance.Imaging
+{
+ /// <summary>
+ /// Extracts, crops, and straightens multiple images in a single scan and returns each as separate bitmaps
+ /// </summary>
+ public class CropAndStraighten
+ {
+ public IEnumerable<Bitmap> Apply(Bitmap bitmap)
+ {
+ // assuming scanned background is white we need to invert for the algo to work
+ var copy = new Invert().Apply(bitmap);
+
+ copy = EnsureGrayscale(copy);
+ new Threshold { ThresholdValue = 25 }.ApplyInPlace(copy);
+ new FillHoles().ApplyInPlace(copy);
+
+ var blobCounter = new BlobCounter
+ {
+ // set filtering options
+ FilterBlobs = true,
+ MinWidth = 50,
+ MinHeight = 50,
+ };
+
+ blobCounter.ProcessImage(copy);
+ var blobs = blobCounter.GetObjectsInformation();
+
+ if (blobs.Any())
+ {
+ var invertedOriginal = new Invert().Apply(bitmap);
+ foreach (var blob in blobs)
+ {
+ // use inverted source to ensure correct edge colors
+ blobCounter.ExtractBlobsImage(invertedOriginal, blob, false);
+ var blobImage = blob.Image.ToManagedImage();
+
+ // straighten
+ var angle = new DocumentSkewChecker().GetSkewAngle(EnsureGrayscale(blobImage));
+ var rotationFilter = new RotateBilinear(-angle) { FillColor = Color.Black };
+ blobImage = rotationFilter.Apply(blobImage);
+
+ // crop
+ blobImage = new ExtractBiggestBlob().Apply(blobImage);
+
+ new Invert().ApplyInPlace(blobImage);
+ yield return blobImage;
+ }
+ }
+ else
+ {
+ yield return bitmap;
+ }
+
+ }
+
+ /// <summary>
+ /// Make image grayscale if it isn't already. Does not ensure you get a copy
+ /// </summary>
+ private static Bitmap EnsureGrayscale(Bitmap source)
+ {
+ return source.PixelFormat == PixelFormat.Format8bppIndexed ? source : Grayscale.CommonAlgorithms.BT709.Apply(source);
+ }
+ }
+}
View
75 src/Enhance.Imaging/Enhance.Imaging.csproj
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <ProductVersion>8.0.30703</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{070B86C5-77F7-4EDD-B473-43407CE33631}</ProjectGuid>
+ <OutputType>Library</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>Enhance.Imaging</RootNamespace>
+ <AssemblyName>Enhance.Imaging</AssemblyName>
+ <TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
+ <FileAlignment>512</FileAlignment>
+ <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\src\</SolutionDir>
+ <RestorePackages>true</RestorePackages>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\Debug\</OutputPath>
+ <DefineConstants>DEBUG;TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\Release\</OutputPath>
+ <DefineConstants>TRACE</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <ItemGroup>
+ <Reference Include="AForge">
+ <HintPath>..\packages\AForge.2.2.4\lib\AForge.dll</HintPath>
+ </Reference>
+ <Reference Include="AForge.Imaging">
+ <HintPath>..\packages\AForge.Imaging.2.2.4\lib\AForge.Imaging.dll</HintPath>
+ </Reference>
+ <Reference Include="AForge.Math">
+ <HintPath>..\packages\AForge.Math.2.2.4\lib\AForge.Math.dll</HintPath>
+ </Reference>
+ <Reference Include="PresentationCore" />
+ <Reference Include="System" />
+ <Reference Include="System.Core" />
+ <Reference Include="System.Drawing" />
+ <Reference Include="System.Xml.Linq" />
+ <Reference Include="System.Data.DataSetExtensions" />
+ <Reference Include="Microsoft.CSharp" />
+ <Reference Include="System.Data" />
+ <Reference Include="System.Xml" />
+ <Reference Include="WindowsBase" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="BitmapExtensions.cs" />
+ <Compile Include="CropAndStraighten.cs" />
+ <Compile Include="NativeMethods.cs" />
+ <Compile Include="ImagingException.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="packages.config" />
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <Import Project="$(SolutionDir)\.nuget\nuget.targets" />
+ <!-- To modify your build process, add your task inside one of the targets below and uncomment it.
+ Other similar extension points exist, see Microsoft.Common.targets.
+ <Target Name="BeforeBuild">
+ </Target>
+ <Target Name="AfterBuild">
+ </Target>
+ -->
+</Project>
View
30 src/Enhance.Imaging/ImagingException.cs
@@ -0,0 +1,30 @@
+using System;
+using System.Runtime.Serialization;
+
+namespace Enhance.Imaging
+{
+ [Serializable]
+ public class ImagingException : Exception
+ {
+ public ImagingException()
+ {
+ }
+
+ public ImagingException(string message)
+ : base(message)
+ {
+ }
+
+ public ImagingException(string message, Exception inner)
+ : base(message, inner)
+ {
+ }
+
+ protected ImagingException(
+ SerializationInfo info,
+ StreamingContext context)
+ : base(info, context)
+ {
+ }
+ }
+}
View
15 src/Enhance.Imaging/NativeMethods.cs
@@ -0,0 +1,15 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace Enhance.Imaging
+{
+ /// <summary>
+ /// FxCop requires all Marshalled functions to be in a class called NativeMethods.
+ /// </summary>
+ internal static class NativeMethods
+ {
+ [DllImport("gdi32.dll")]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ internal static extern bool DeleteObject(IntPtr hObject);
+ }
+}
View
36 src/Enhance.Imaging/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("Enhance.Imaging")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("Enhance.Imaging")]
+[assembly: AssemblyCopyright("Copyright © 2012")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("a13d2962-f5a2-4b58-9d15-f6dda37b4454")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
View
6 src/Enhance.Imaging/packages.config
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+ <package id="AForge" version="2.2.4" />
+ <package id="AForge.Imaging" version="2.2.4" />
+ <package id="AForge.Math" version="2.2.4" />
+</packages>
View
12 src/Enhance.sln
@@ -11,6 +11,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{9EB6B3
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Enhance.Logic", "Enhance.Logic\Enhance.Logic.csproj", "{9E94E49F-57CE-4304-9CB1-E243FAB2B1A3}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Enhance.Imaging", "Enhance.Imaging\Enhance.Imaging.csproj", "{070B86C5-77F7-4EDD-B473-43407CE33631}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -41,6 +43,16 @@ Global
{9E94E49F-57CE-4304-9CB1-E243FAB2B1A3}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
{9E94E49F-57CE-4304-9CB1-E243FAB2B1A3}.Release|Mixed Platforms.Build.0 = Release|Any CPU
{9E94E49F-57CE-4304-9CB1-E243FAB2B1A3}.Release|x86.ActiveCfg = Release|Any CPU
+ {070B86C5-77F7-4EDD-B473-43407CE33631}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {070B86C5-77F7-4EDD-B473-43407CE33631}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {070B86C5-77F7-4EDD-B473-43407CE33631}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
+ {070B86C5-77F7-4EDD-B473-43407CE33631}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
+ {070B86C5-77F7-4EDD-B473-43407CE33631}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {070B86C5-77F7-4EDD-B473-43407CE33631}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {070B86C5-77F7-4EDD-B473-43407CE33631}.Release|Any CPU.Build.0 = Release|Any CPU
+ {070B86C5-77F7-4EDD-B473-43407CE33631}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
+ {070B86C5-77F7-4EDD-B473-43407CE33631}.Release|Mixed Platforms.Build.0 = Release|Any CPU
+ {070B86C5-77F7-4EDD-B473-43407CE33631}.Release|x86.ActiveCfg = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE

0 comments on commit 34eeae1

Please sign in to comment.