Օգտագործեք երկչափ շտրիխ կոդեր՝ .NET/C#-ում պատկերը հավասարեցնելու համար

Բլոգի կատեգորիա՝ BarcodeForms processing.NET

15.05.2020

Ձևերի մշակման և օպտիկական նշանների ճանաչման (OMR) տեխնոլոգիան լայնորեն օգտագործվում է էլեկտրոնային փաստաթղթերի ձևերի դասակարգման, ուղղորդման և ձևանմուշներով ճանաչման համար, ինչպիսիք են հաշիվ-ապրանքագրերը, բեռնագրերը և այլն, ինչպես նաև թեստի, հարցաթերթիկի, քվեաթերթիկի և այլնի ձևաթղթում լրացված օպտիկական նշանների ճանաչման համար:

VintaSoft Forms Processing .NET Plug-in-ը կարող է օգտագործվել ինչպես ձևերի ճանաչման, այնպես էլ պատկերը ձևանմուշով հավասարեցնելու համար: Այս հոդվածը նկարագրում է, թե ինչպես օգտագործել շտրիխ կոդեր գծերի փոխարեն՝ պատկերի նույնականացման համար և այդպիսով բարելավել ճանաչման ճշգրտությունն ու հուսալիությունը:

Պատկերի հավասարեցման գործընթացը բաղկացած է պատկերի ձևանմուշով նույնականացումից և ձևափոխման մատրիցայի ստացումից, որը սահմանում է պատկերի շեղումը, սեղմումը և պտույտը ձևանմուշի նկատմամբ: Հաջորդը, ձևափոխման մատրիցն օգտագործվում է պատկերը հավասարեցնելու համար:

Պատկերի նույնականացում ձևանմուշով, որն օգտագործում է շտրիխ կոդերի հիման վրա հիմնական գոտիներ


Պատկերի նույնականացումը կատարվում է TemplateMatchingCommand դասի միջոցով: Հաջող նույնականացման արդյունքը փոխակերպումների մատրից է, որը սահմանում է պատկերի շեղումները, սեղմումը և պտույտը ձևանմուշի նկատմամբ:

TemplateMatchingCommand դասը ստեղծում է մուտքային պատկերի և ձևանմուշի պատկերի տպագրություն, համեմատում է տպագրությունները և որոշում, թե արդյոք պատկերները նման են: Ըստ լռելյայնի, դասը ստեղծում է պատկերի տպագրություն՝ հիմնվելով ուղիղ գծերի վրա:

Այս հոդվածում մենք կփոխենք պատկերի տպագրություն ստեղծող ալգորիթմը և կօգտագործենք կոմպակտ 2D շտրիխ կոդեր Ացտեկյան ռունաների համար պատկերի տպագրություն ստեղծելու համար: Ացտեկյան ռունան կատարելապես համապատասխանում է մեր խնդրին, քանի որ՝

Պատկերի նույնականացման համար՝ օգտագործելով բանալիային գոտիներ՝ շտրիխ կոդերի հիման վրա, մենք պետք է կատարենք հետևյալ քայլերը՝


Հավասարեցնել պատկերը շաբլոնի միջոցով, որն օգտագործում է բանալիային գոտիներ՝ հիմնված շտրիխ կոդերի վրա


Պատկերի հավասարեցումը կատարվում է TemplateAligningCommand դասի միջոցով։Դասը օգտագործում է պատկերի նույնականացման ընթացքում ստացված փոխակերպումների մատրիցը։

Պատկերի հավասարեցման համար՝ օգտագործելով բանալիային գոտիներ՝ հիմնված շտրիխ կոդերի վրա, մենք պետք է կատարենք հետևյալ քայլերը՝


Պատկերի հավասարեցման օրինակ


Ահա մի պատկեր, որը մենք կօգտագործենք որպես շաբլոնային պատկեր՝
Document template image with key zones based on barcodes

Այն պարունակում է 3 շտրիխ կոդ, որոնք չեն համընկնում (այսինքն՝ 3 հղման կետ), ինչը ալգորիթմի ճիշտ աշխատանքի համար անհրաժեշտ հղման կետերի նվազագույն թույլատրելի քանակն է: Թույլատրվում է օգտագործել ավելի շատ շտրիխ կոդեր այն դեպքում, երբ դրանք կարող են վնասվել կամ կրճատվել:
Շտրիխ կոդերը կարող են տեղադրվել էջի ցանկացած հատվածում, սակայն աղավաղումների նույնականացման լավագույն ճշգրտությունը ձեռք է բերվում, երբ շտրիխ կոդերը գտնվում են փաստաթղթի եզրերին։

Օգտվենք 3 փորձնական փաստաթղթի պատկերներից։

Ահա 90 աստիճանով պտտված փաստաթղթի պատկերը՝ շտրիխ կոդերի հիման վրա հիմնված հիմնական գոտիներով։
90-degree rotated document image with key zones based on barcodes

Ահա 150 աստիճանով պտտված և մասշտաբավորված փաստաթղթի պատկերը՝ շտրիխ կոդերի հիման վրա հիմնված հիմնական գոտիներով։
150-degree rotated and scaled document image with key zones based on barcodes

Ահա 180 աստիճանով պտտված և մասշտաբավորված փաստաթղթի պատկերը՝ շտրիխ կոդերի հիման վրա հիմնված հիմնական գոտիներով։
180-degree rotated and scaled document image with key zones based on barcodes


Ահա C# կոնսոլային ծրագրի օրինակ, որը կատարում է պատկերների համեմատման և հավասարեցման գործընթացը։
public static void Test()
{
    AlignImages(
        new string[] { "BarcodeTemplateMatching_template1.png" },
        new string[] {
    "BarcodeTemplateMatching_1_rotate90.png",
    "BarcodeTemplateMatching_1_scale-rotate150.png",
    "BarcodeTemplateMatching_1_scale-rotate180.png"});
}

public static void AlignImages(string[] templates, string[] images)
{
    // create barcode key zone recognizer
    BarcodeKeyZoneRecognizerCommand barcodeRecognizer = new BarcodeKeyZoneRecognizerCommand();
    // set barcode reader settings
    barcodeRecognizer.Settings.ScanBarcodeTypes = Vintasoft.Barcode.BarcodeType.Aztec;
    barcodeRecognizer.Settings.ScanDirection = Vintasoft.Barcode.ScanDirection.Horizontal | Vintasoft.Barcode.ScanDirection.Vertical;
    barcodeRecognizer.Settings.AutomaticRecognition = true;
    // specify that image contains 3 barcodes
    barcodeRecognizer.Settings.ExpectedBarcodes = 3;

    // create an imprint generator, which is based on barcode key zones
    Vintasoft.Imaging.FormsProcessing.TemplateMatching.ImageImprintGeneratorCommand barcodeImprintGenerator =
        new Vintasoft.Imaging.FormsProcessing.TemplateMatching.ImageImprintGeneratorCommand(barcodeRecognizer);

    // create template matching command
    Vintasoft.Imaging.FormsProcessing.TemplateMatching.TemplateMatchingCommand templateMatchingCommand =
        new Vintasoft.Imaging.FormsProcessing.TemplateMatching.TemplateMatchingCommand();
    // specify that the template matching command must use imprint generator, which is based on barcode key zones
    templateMatchingCommand.ImageImprintGenerator = barcodeImprintGenerator;

    // for each template image file
    foreach (string template in templates)
    {
        // add template image file to the templates of template matching command
        templateMatchingCommand.TemplateImages.Add(template);
    }

    // for each input image file
    foreach (string imageFilename in images)
    {
        // create input image
        using (Vintasoft.Imaging.VintasoftImage image = new Vintasoft.Imaging.VintasoftImage(imageFilename))
        {
            // find a template for the image
            templateMatchingCommand.ExecuteInPlace(image);
            // get the image compare result
            Vintasoft.Imaging.FormsProcessing.TemplateMatching.ImageImprintCompareResult compareResult = templateMatchingCommand.Result.ImageCompareResult;

            // print image file name
            System.Console.WriteLine(imageFilename);
            // print the image comparison result
            System.Console.WriteLine(string.Format(" IsReliable ={0}", compareResult.IsReliable));

            // if template for image is found
            if (compareResult.IsReliable)
            {
                // print the image comparison confidence
                System.Console.WriteLine(string.Format(" Confidence ={0}%", compareResult.Confidence * 100));
                // print information about matrix, which defines image transformation relative to the template image
                System.Console.WriteLine(string.Format(" TransformMatrix ={0}", compareResult.TransformMatrix));

                // create the template aligning command
                Vintasoft.Imaging.FormsProcessing.TemplateMatching.TemplateAligningCommand templateAligningCommand =
                    new Vintasoft.Imaging.FormsProcessing.TemplateMatching.TemplateAligningCommand();
                // specify that template aligning command must use matrix, which defines image transformation relative to the template image
                templateAligningCommand.CompareResult = compareResult;
                // apply the aligning command to the image
                templateAligningCommand.ExecuteInPlace(image);
                // save aligned image to a file
                image.Save(string.Format("{0}_result.png", System.IO.Path.GetFileNameWithoutExtension(imageFilename)));
            }
            System.Console.WriteLine();
        }
    }
}

Ծրագիրը գործարկելուց հետո մենք կստանանք փաստաթղթերի պատկերներ, որոնք չեն պտտվել և չեն մասշտաբավորվել։

Ահա 90 աստիճանով պտտված փաստաթղթի պատկերի ձևի ճանաչման արդյունքը՝ շտրիխ կոդերի հիման վրա բանալիային գոտիներով.
The form recognition result for 90-degrees rotated document image with keyzones based on barcodes

Ահա 150 աստիճանով պտտված և մասշտաբավորված փաստաթղթի պատկերի ձևի ճանաչման արդյունքը՝ շտրիխ կոդերի հիման վրա բանալիային գոտիներով.
The form recognition result for 150-degree rotated and scaled document image with keyzones based on barcodes

Ահա 180 աստիճանով պտտված և մասշտաբավորված փաստաթղթի պատկերի ձևի ճանաչման արդյունքը՝ շտրիխ կոդերի հիման վրա բանալիային գոտիներով.
The form recognition result for 180-degree rotated and scaled document image with keyzones based on barcodes



Այս հոդվածում օգտագործված սկզբնաղբյուրի կոդերը


Ահա BarcodeKeyZone դասի C# կոդը, որը որոշում է շտրիխ կոդ պարունակող բանալիային գոտին.
/// <summary>
/// Represents key zone based on recognized barcode.
/// </summary>
public class BarcodeKeyZone : Vintasoft.Imaging.FormsProcessing.TemplateMatching.KeyZone
{

    #region Constructors

    /// <summary>
    /// Initializes a new instance of the <see cref="BarcodeKeyZone"/> class.
    /// </summary>
    /// <param name="barcodeInfo">The barcode information.</param>
    public BarcodeKeyZone(Vintasoft.Barcode.IBarcodeInfo barcodeInfo)
        : base()
    {
        _barcodeInfo = barcodeInfo;
        if (barcodeInfo is Vintasoft.Barcode.BarcodeInfo.AztecInfo)
        {
            // get the barcode center from barcode info
            _location = ((Vintasoft.Barcode.BarcodeInfo.AztecInfo)barcodeInfo).BulleyeCenter;
        }
        else
        {
            // calculate the barcode center

            _location = System.Drawing.PointF.Empty;
            System.Drawing.Point[] points = barcodeInfo.Region.GetPoints();
            for (int i = 0; i < points.Length; i++)
            {
                _location.X += points[i].X;
                _location.Y += points[i].Y;
            }
            _location.X /= points.Length;
            _location.Y /= points.Length;
        }
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="BarcodeKeyZone"/> class.
    /// </summary>
    /// <param name="barcodeInfo">The barcode information.</param>
    /// <param name="location">The location.</param>
    private BarcodeKeyZone(Vintasoft.Barcode.IBarcodeInfo barcodeInfo, System.Drawing.PointF location)
        : base()
    {
        _barcodeInfo = barcodeInfo;
        _location = location;
    }

    #endregion



    #region Properties

    System.Drawing.PointF _location;
    /// <summary>
    /// Gets the location of the key zone on the image.
    /// </summary>
    public override System.Drawing.PointF Location
    {
        get
        {
            return _location;
        }
    }

    Vintasoft.Barcode.IBarcodeInfo _barcodeInfo;
    /// <summary>
    /// Gets the barcode information.
    /// </summary>
    public Vintasoft.Barcode.IBarcodeInfo BarcodeInfo
    {
        get
        {
            return _barcodeInfo;
        }
    }

    #endregion



    #region Methods

    /// <summary>
    /// Applies a transformation to the key zone.
    /// </summary>
    /// <param name="m">The <see cref="Vintasoft.Imaging.AffineMatrix" />
    /// that specifies the transformation to apply.</param>
    public override void Transform(Vintasoft.Imaging.AffineMatrix m)
    {
        if (m == null)
            return;
        _location = Vintasoft.Imaging.PointFAffineTransform.TransformPoint(m, _location);
    }

    /// <summary>
    /// Returns the similarity of specified <see cref="Vintasoft.Imaging.FormsProcessing.TemplateMatching.KeyZone" /> and the current key zone.
    /// </summary>
    /// <param name="zone">The <see cref="Vintasoft.Imaging.FormsProcessing.TemplateMatching.KeyZone" /> to compare with.</param>
    /// <returns>
    /// The similarity of specified keyzone and the current key zone in range from 0 to 1.<br />
    /// 0 means that zones are absolutely NOT similar;
    /// 1 means that zones are perfectly similar.
    /// </returns>
    public override double CalculateSimilarity(Vintasoft.Imaging.FormsProcessing.TemplateMatching.KeyZone zone)
    {
        BarcodeKeyZone barcodeZone = zone as BarcodeKeyZone;
        if (barcodeZone == null)
            return 0;

        if (barcodeZone.BarcodeInfo.Value == BarcodeInfo.Value &&
            barcodeZone.BarcodeInfo.BarcodeType == BarcodeInfo.BarcodeType)
            return 1;

        return 0;
    }

    /// <summary>
    /// Creates a new object that is a copy of the current instance.
    /// </summary>
    /// <returns>A new object that is a copy of this instance.</returns>
    public override object Clone()
    {
        return new BarcodeKeyZone(BarcodeInfo, Location);
    }

    #endregion

}


Ահա BarcodeKeyZoneRecognizerCommand դասի C# կոդը, որը սահմանում է շտրիխ կոդ պարունակող բանալիային գոտիների որոնման հրամանը.
/// <summary>
/// Recognizes key zones, based on barcodes, on an image.
/// </summary>
public class BarcodeKeyZoneRecognizerCommand : Vintasoft.Imaging.FormsProcessing.TemplateMatching.KeyZoneRecognizerCommand
{

    #region Constructors

    /// <summary>
    /// Initializes a new instance of the <see cref="BarcodeKeyZoneRecognizerCommand"/> class.
    /// </summary>
    public BarcodeKeyZoneRecognizerCommand()
        : base()
    {
    }

    #endregion



    #region Properties

    static System.Collections.ObjectModel.ReadOnlyCollection<Vintasoft.Imaging.PixelFormat> _supportedNativePixelFormats;
    /// <summary>
    /// Gets a list of supported pixel formats for this processing command.
    /// </summary>
    public override System.Collections.ObjectModel.ReadOnlyCollection<Vintasoft.Imaging.PixelFormat> SupportedNativePixelFormats
    {
        get
        {
            if (_supportedNativePixelFormats == null)
            {
                System.Collections.Generic.List<Vintasoft.Imaging.PixelFormat> supportedPixelFormats = new System.Collections.Generic.List<Vintasoft.Imaging.PixelFormat>();
                supportedPixelFormats.Add(Vintasoft.Imaging.PixelFormat.BlackWhite);
                supportedPixelFormats.Add(Vintasoft.Imaging.PixelFormat.Bgr24);
                supportedPixelFormats.Add(Vintasoft.Imaging.PixelFormat.Bgr32);
                supportedPixelFormats.Add(Vintasoft.Imaging.PixelFormat.Indexed1);
                supportedPixelFormats.Add(Vintasoft.Imaging.PixelFormat.Indexed8);
                supportedPixelFormats.Add(Vintasoft.Imaging.PixelFormat.Gray8);
                _supportedNativePixelFormats = supportedPixelFormats.AsReadOnly();
            }
            return _supportedNativePixelFormats;
        }
    }

    Vintasoft.Barcode.ReaderSettings _settings = new Vintasoft.Barcode.ReaderSettings();
    /// <summary>
    /// Gets or sets the barcode reader settings.
    /// </summary>
    /// <value>
    /// The reader settings.
    /// </value>
    public Vintasoft.Barcode.ReaderSettings Settings
    {
        get
        {
            return _settings;
        }
        set
        {
            if (value == null)
                throw new System.ArgumentNullException();
            _settings = value;
        }
    }

    #endregion



    #region Methods

    /// <summary>
    /// Creates a new <see cref="BarcodeKeyZoneRecognizerCommand"/> that is a copy of the current
    /// instance.
    /// </summary>
    /// <returns>A new <see cref="BarcodeKeyZoneRecognizerCommand"/> that is a copy of this
    /// instance.</returns>
    public override object Clone()
    {
        BarcodeKeyZoneRecognizerCommand recognizer = new BarcodeKeyZoneRecognizerCommand();
        recognizer.IsNested = IsNested;
        recognizer.RegionOfInterest = RegionOfInterest;
        recognizer.Settings = Settings.Clone();
        return recognizer;
    }


    /// <summary>
    /// Recognizes key zones in the specified rectangle of the specified image.
    /// </summary>
    /// <param name="image">The image where key zones must be searched.</param>
    /// <param name="rect">The region of interest on image.</param>
    /// <returns>An array of recognized key zones.</returns>
    protected override Vintasoft.Imaging.FormsProcessing.TemplateMatching.KeyZone[] Recognize(Vintasoft.Imaging.VintasoftImage image, System.Drawing.Rectangle rect)
    {
        Vintasoft.Barcode.BarcodeReader reader = new Vintasoft.Barcode.BarcodeReader();
        reader.Settings = Settings.Clone();
        reader.Settings.ScanRectangle = rect;
        using (System.Drawing.Bitmap bitmap = image.GetAsBitmap())
        {
            Vintasoft.Barcode.IBarcodeInfo[] infos = reader.ReadBarcodes(bitmap);
            Vintasoft.Imaging.FormsProcessing.TemplateMatching.KeyZone[] result = new Vintasoft.Imaging.FormsProcessing.TemplateMatching.KeyZone[infos.Length];
            for (int i = 0; i < infos.Length; i++)
                result[i] = new BarcodeKeyZone(infos[i]);
            return result;
        }
    }

    #endregion

}