Ce este “deskew” (și de ce contează)

Skew se întâmplă atunci când un document este scanat sau fotografiat la un unghi ușor (de obicei ±0-5°). Rezultatul: liniile de text nu sunt orizontale, marginea verticală este atașată, iar imaginea are o rotație subtilă. Deskev este procesul de Detectarea unghiului de schi și rotația imaginii înapoi Liniile devin din nou orizontale/verticale.

Cum îți dăunează tubul

  • Acuratețea OCR scade: Baselele lipite împiedică segmentarea, găsirea liniilor și clasificarea caracterului; unghiile mici pot reduce precizia dramatic.
  • Barcodele nu se decodează: Multe simboluri lineare (de exemplu, codul 128/39) sunt sensibile la rotație; schiul excesiv reduce citirile de succes.
  • Cropping & layout detection break: detecția marginii paginii și a liniei de tabel adesea presupune geometrie aproape ortagonală.

Cum Aspose.Imagining fixă schiul – exact

Aspose.Imaging expune un un-call deskew pe imagini raster:

  • RasterImage.NormalizeAngle() — detectează în mod automat unghiul schiului (utilizat intern GetSkewAngleși rotează imaginea în loc.
  • Supraîncărcare : NormalizeAngle(bool resizeProportionally, Color backgroundColor) — alegeți dacă să extindeți canalul pentru a păstra toate conținuturile și care ** culoarea de fundal** umple colțurile create prin rotație.

Există, de asemenea, companii Cloud & UI (REST și instrument online) care expun aceleași operațiuni dacă construiți servicii sau prototipuri.

Exemplă completă (copy-paste)

Acest exemplu arată preprocesarea sigură și decoctarea robustă cu Aspose.Imaging:

  • Încărcați un scan (JPG / PNG / TIFF).
  • Convertează opțional la grayscale și normalizează contrastul pentru o detecție mai bună a unghiului.
  • Calls NormalizeAngle(resizeProportionally: true, background: White).
  • salvează imaginea strălucită.
  • Bonus: arată cum să descărcați fiecare pagină într-un TIFF de mai multe pagini.
  • Cerințe *
  • .NET 8 (sau 6+)
  • Încă nu: Aspose.Imaging

using System;
using System.IO;
using Aspose.Imaging;
using Aspose.Imaging.FileFormats.Tiff;
using Aspose.Imaging.ImageOptions;

class Program
{
    static int Main(string[] args)
    {
        if (args.Length < 2)
        {
            Console.WriteLine("Usage: dotnet run -- <inputImageOrTiff> <outputImageOrTiff>");
            return 1;
        }

        string inputPath  = args[0];
        string outputPath = args[1];

        try
        {
            using (var image = Image.Load(inputPath))
            {
                // Multi-page TIFF? Deskew frame-by-frame.
                if (image is TiffImage tiff)
                {
                    foreach (var frame in tiff.Frames)
                    {
                        // --- Optional: lightweight preprocessing for better angle detection ---
                        // Convert to grayscale-like statistics to reduce chroma noise.
                        // Many real scans already are gray/bilevel; if not, Normalize() helps.
                        TryNormalizeForDeskew(frame);

                        // --- Deskew ---
                        // true  = expand canvas to avoid cropping
                        // White = fill color for the new corners created by rotation
                        frame.NormalizeAngle(true, Aspose.Imaging.Color.White);
                    }

                    tiff.Save(outputPath); // encoder inferred from extension
                }
                else
                {
                    // Single-page raster image
                    var raster = image as RasterImage 
                                 ?? throw new InvalidOperationException("Input is not a raster image.");

                    TryNormalizeForDeskew(raster);
                    raster.NormalizeAngle(true, Aspose.Imaging.Color.White);

                    // Choose encoder explicitly (e.g., PNG/JPEG/TIFF). Here we mirror input extension.
                    image.Save(outputPath);
                }
            }

            Console.WriteLine($"✅ Deskew complete: {Path.GetFullPath(outputPath)}");
            return 0;
        }
        catch (Exception ex)
        {
            Console.Error.WriteLine("❌ " + ex.Message);
            return 2;
        }
    }

    /// <summary>
    /// Minimal, safe preprocessing to stabilize skew detection.
    /// Avoid heavy blurs that can smear thin text.
    /// </summary>
    private static void TryNormalizeForDeskew(RasterImage raster)
    {
        // Ensure pixels are accessible (performance hint for subsequent operations).
        raster.CacheData();

        // If the image has wildly varying brightness (camera shots), a light contrast
        // normalization can help align text lines for skew detection. The exact set
        // of helpers varies by version; keep it simple and non-destructive.
        //
        // Tip: If your version exposes BinarizeOtsu/AdaptiveBinarize, try them
        // *after* deskew for OCR workflows to preserve thin strokes.

        // Example: If available in your build, uncomment one of these:
        // raster.AdjustBrightnessContrast(brightness: 0, contrast: 10); // gentle contrast pop
        // raster.Grayscale(); // reduce chroma noise if present

        // Leave as-is if your scans are already clean (e.g., 300 dpi monochrome).
    }
}

Why NormalizeAngle Funcţionează bine

  • ** detectează** unghiul de scanare al textului tipic (utilizând statisticile bazelor/edge) și rotatele într-o singură apelare.
  • pe care resizeProportionally opțiunea împiedică clipul de corner, și backgroundColor Parametru controlează culoarea plăcută a zonelor nou expuse.

Multi-page TIFF deskew (care să vezi)

  • Run NormalizeAngle * pentru un cadru *; TiffFrame este o pagină raster, astfel încât aceeași API se aplică.
  • Salvați o dată la capăt; luați în considerare o compresie ** fără pierdere** (de exemplu, LZW/Deflate pentru RGB, CCITT Group 4 pentru bilevel).
  • Dacă intenționați să mergeți la OCR mai târziu, păstrați paginile la 300 dpi (sau mai mare) pentru a salva glifele mici.

Pădurea obișnuită - și cum să le evitați

  • Croping după rotațieDacă rotiți fără a extinde canapea, colțurile sunt tăiate. NormalizeAngle(true, Color.White) să fie *proporționată *.

  • Fonturi murdare trick detectorul unghiuluiRăspândirea zgomotului sau gradientelor poate înfrânge estimarea unghiului. faceți normalizarea luminii (tweet de contrast sau grayscale) înainte de decoctare, dar evitați blurele puternice care elimină accidentele subțiri.

  • Deschiderea supra-binarizăriiFrontierele grele pot crea bazilele cu coajă; întoarceți-vă mai întâi, apoi binarizați pentru OCR dacă este necesar. (orientația OCR subliniază corecția precoce a pipelinei.)

    • Scanarea codului de bare la unghiuri stepe*În cazul în care codurile de frunze încă eșuează după descărcare, verificați că unghiul nu a fost saturat; fotografiile foarte subțire pot avea nevoie de rotație inițială/flip prin metadata (EXIF) înainte NormalizeAngle.

FAQ-uri

**Q: Schimbă deskew dimensiunea imaginii?**A: Dacă treceți resizeProportionally: true, canvele cresc doar suficient pentru a menține toate conținutul - nu creșterea - umplerea unghiilor noi cu culoarea pe care o alegeți.

**Q: Pot să mă batch pentru a detecta unghiile mai întâi?**A: Deskew este de obicei unic cu NormalizeAngle, dar dacă aveți nevoie de unghiuri pentru analiză, puteți măsura folosind API-uri conexe (de exemplu, produsele OCR expun calculul unghiei).

**Q: Ce se întâmplă cu Cloud/REST?**A: Aspose.Imaging Cloud expune un deskew În cazul în care construiți un serviciu în loc de a utiliza biblioteca .NET.

Takeaways

  • Skew doare OCR, citirea codului de noroc și analiza layout-ului.
  • Aspose.Imaging RasterImage.NormalizeAngle vă oferă o soluție rapidă și fiabilă cu o singură apelare, plus opțiuni pentru a proteja limitele conținutului.
  • Combinați preprocesarea gentle (opțional) cu per-page deskew pentru TIFF-uri de mai multe pagini pentru a maximiza precizia.

Cu aceste practici, aplicațiile .NET vor produce scanuri mai stricte, mai citibile – iar etapele OCR și codul de bar va fi recunoscătoare.

More in this category