J'ai cherché partout un moyen fiable de redresser une image en .Net, mais je n'ai pas eu beaucoup de chance.
Pour l'instant, j'utilise Aforge. C'est un problème car je travaille avec WPF, donc les images avec lesquelles je travaille sont des objets BitmapImage, par opposition aux objets Bitmap, ce qui signifie que je dois commencer avec un objet BitmapImage, l'enregistrer dans un flux de mémoire, créer un nouvel objet Bitmap à partir du flux de mémoire, passer par le processus d'élimination de la distorsion, enregistrer l'image modifiée dans un nouveau flux de mémoire et ensuite créer un nouvel objet BitmapImage à partir dudit flux de mémoire. En plus de cela, le redressement n'est pas génial.
J'essaie de lire les données OMR d'un morceau de papier numérisé par un scanner, et je dois donc compter sur le fait qu'une case OMR particulière se trouve toujours aux mêmes coordonnées, de sorte que le désalignement doit être fiable.
J'utilise donc Aforge pour le moment, je n'arrive pas à trouver d'autres bibliothèques gratuites/open source pour le désalignement d'images en .Net, tout ce que j'ai trouvé est soit très cher, soit en C/C++.
Ma question est la suivante : existe-t-il d'autres bibliothèques gratuites/open source qui aident à la correction des images dans .Net ? Si oui, comment s'appellent-elles ? Sinon, comment dois-je aborder ce problème ?
Edit : Par exemple, disons que j'ai la page ci-dessous :
Note : Ceci n'est qu'à titre d'illustration, mais l'image réelle a effectivement un rectangle noir à chaque coin de la page, peut-être que cela vous aidera.
Lorsque j'imprime ce document et que je le numérise dans mon scanner, il ressemble à ceci :
Je dois redresser cette image pour que ma boîte soit à la même place à chaque fois. Dans le monde réel, il y a beaucoup de boîtes, elles sont plus petites et proches les unes des autres, donc la précision est importante.
La méthode que j'utilise actuellement pour cela est un casse-tête inefficace :
using AForge.Imaging;
using AForge.Imaging.Filters;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Windows.Media.Imaging;
public static BitmapImage DeskewBitmap(BitmapImage skewedBitmap)
{
//Using a memory stream to minimise disk IO
var memoryStream = BitmapImageToMemoryStream(skewedBitmap);
var bitmap = MemoryStreamToBitmap(memoryStream);
var skewAngle = CalculateSkewAngle(bitmap);
//Aforge needs a Bppp indexed image for the deskewing process
var bitmapConvertedToBbppIndexed = ConvertBitmapToBbppIndexed(bitmap);
var rotatedImage = DeskewBitmap(skewAngle, bitmapConvertedToBbppIndexed);
//I need to convert the image back to a non indexed format to put it back into a BitmapImage object
var imageConvertedToNonIndexed = ConvertImageToNonIndexed(rotatedImage);
var imageAsMemoryStream = BitmapToMemoryStream(imageConvertedToNonIndexed);
var memoryStreamAsBitmapImage = MemoryStreamToBitmapImage(imageAsMemoryStream);
return memoryStreamAsBitmapImage;
}
private static Bitmap ConvertImageToNonIndexed(Bitmap rotatedImage)
{
var imageConvertedToNonIndexed = rotatedImage.Clone(
new Rectangle(0, 0, rotatedImage.Width, rotatedImage.Height), PixelFormat.Format32bppArgb);
return imageConvertedToNonIndexed;
}
private static Bitmap DeskewBitmap(double skewAngle, Bitmap bitmapConvertedToBbppIndexed)
{
var rotationFilter = new RotateBilinear(-skewAngle) { FillColor = Color.White };
var rotatedImage = rotationFilter.Apply(bitmapConvertedToBbppIndexed);
return rotatedImage;
}
private static double CalculateSkewAngle(Bitmap bitmapConvertedToBbppIndexed)
{
var documentSkewChecker = new DocumentSkewChecker();
double skewAngle = documentSkewChecker.GetSkewAngle(bitmapConvertedToBbppIndexed);
return skewAngle;
}
private static Bitmap ConvertBitmapToBbppIndexed(Bitmap bitmap)
{
var bitmapConvertedToBbppIndexed = bitmap.Clone(
new Rectangle(0, 0, bitmap.Width, bitmap.Height), PixelFormat.Format8bppIndexed);
return bitmapConvertedToBbppIndexed;
}
private static BitmapImage ResizeBitmap(BitmapImage originalBitmap, int desiredWidth, int desiredHeight)
{
var ms = BitmapImageToMemoryStream(originalBitmap);
ms.Position = 0;
var result = new BitmapImage();
result.BeginInit();
result.DecodePixelHeight = desiredHeight;
result.DecodePixelWidth = desiredWidth;
result.StreamSource = ms;
result.CacheOption = BitmapCacheOption.OnLoad;
result.EndInit();
result.Freeze();
return result;
}
private static MemoryStream BitmapImageToMemoryStream(BitmapImage image)
{
var ms = new MemoryStream();
var encoder = new JpegBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(image));
encoder.Save(ms);
return ms;
}
private static BitmapImage MemoryStreamToBitmapImage(MemoryStream ms)
{
ms.Position = 0;
var bitmap = new BitmapImage();
bitmap.BeginInit();
bitmap.StreamSource = ms;
bitmap.CacheOption = BitmapCacheOption.OnLoad;
bitmap.EndInit();
bitmap.Freeze();
return bitmap;
}
private static Bitmap MemoryStreamToBitmap(MemoryStream ms)
{
return new Bitmap(ms);
}
private static MemoryStream BitmapToMemoryStream(Bitmap image)
{
var memoryStream = new MemoryStream();
image.Save(memoryStream, ImageFormat.Bmp);
return memoryStream;
}
En rétrospective, quelques autres questions :
- Est-ce que j'utilise AForge correctement ?
- AForge est-elle la meilleure bibliothèque à utiliser pour cette tâche ?
- Comment pourrais-je améliorer mon approche actuelle pour obtenir des résultats plus précis ?