C# で画像からバーコードを読み取る方法

目標

損傷したバーコードや低品質のバーコードを扱うことができる、さまざまな種類のバーコードを読み取るためのコマンドライン サンプル プログラムを作成します。

必要条件
プログラミングのスキル

C# 中級レベル


バーコードは、物品の整理に最も便利なものの 1 つでしょう。シンプルで、レーザーやカメラで拾い上げることができ、幅広いビジネスや組織で使用されています。

今回は、C# プログラミング言語を使用してカスタム アプリケーションを作成し、画像 (カメラやスキャナなど) からバーコードを読み取る必要があると仮定してみましょう。おそらく、倉庫で在庫を追跡し、アイテムを追跡するための独自のバーコードのセットを持っていると思います。あるいは、医療関係で、医薬品の保管場所への出し入れをスキャンする必要があります。また、書類にバーコードのフラグを立て、顧客に付随するすべてのものをすばやくスキャンして、誰かにアップロードしてもらうことなく、適切なデータベースに入れることができるようにすることもできます。

今回は、様々なバーコードの状況に対応できる Barcode Xpress SDK を使用します。

  • 1次元バーコード
  • 2次元バーコード (QR コード含む)
  • 逆さま、または回転したバーコード
  • 損傷したバーコード/低画質画像
  • 複数のバーコードがある画像

Barcode Xpress は、バーコードの読み取りと生成のニーズに対応するために、どのような問題にも対応できるように設計されています。しかし、今回はシンプルに、読み取りに焦点を当てましょう。


はじめに

Barcode Xpress の評価版をダウンロードし、インストールするところから始めます。無料評価ライセンスのもとで使用することができます。 お客様のプロジェクトのニーズに合わせて評価モードを変更することができます。

今回のプロジェクトでは、Visual Studio 2017、2019 を使用することができます (Visual Studio 2017 以前のバージョンでも問題なく動作します)。
なお、このサンプルでは、Barcode Xpress 12 .NET を使用していますが、最新の Barcode Xpress 13 .NET でも同様です。

最もシンプルなプログラムは、コマンドライン上に置いておくことでしょう。スキャンするファイル名を与えて、どのようなバーコードを探すかを指示し、検出したバーコードを集めて、情報を表示すればいいのです。

以下は、そのプログラムの仕組みです。

  1. コマンドライン プログラムを実行します。 第 1 引数には種類を指定します。 ここでは簡単のために、1次元バーコードと QR コードの 2 つに範囲を絞っています。 しかし、他にもスキャンできるバーコードの種類はたくさんあります。
  2. ファイルが存在する場合は、バーコード イメージ ファイルを読み込みます。
  3. 探しているバーコードの種類に基づいて、ファイル内のバーコードをスキャンします。
  4. 現在読み込んでいるバーコードが何であるか、その種類と値を表示します。

設定方法

  1. Barcode Xpress .NET の評価版をダウンロードし、インストールします。
  2. Accusoft Extension をプロジェクトに追加します。[参照] を右クリックし、[参照の追加] をクリック、[拡張] をクリックし、[Accusoft Barcode Xpress 12 .NET] をプロジェクトに追加します。そうしないと、せっかくの高機能な Barcode Xpress のツールを全く使うことができません。

  3. コマンドライン バーコード リーダーのコード (下記) を追加し、SimpleBarcodeReaderCSharp.exe としてコンパイルします。

コマンドライン バーコード リーダーのコード

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Drawing;
using Accusoft.BarcodeXpressSdk;
/*
 * Simple bar code demonstration file
 *
 * Accusoft
 *
 * October 31, 2017  Happy Halloween!
 *
 *
 * */
namespace SimpleBarcodeReaderCSharp
{
    class SimpleBarcodeReaderCSharp
    {
        //read in an image file
        static void Main(string[] args)
        {
            //set up our switches for the main to read from, default is 1
            int barcodeType = 1;
            //this is to track which argument we’re on.  There are more graceful ways to do this,
            //but this is easiest.
            int count = 0;
            foreach (string arg in args)
            {
                if (count == 0)
                {
                    //make sure this is a number – if we can’t parse it into an integer value, then give an error
                    if (!(int.TryParse(arg.ToString(), out barcodeType)))
                    {
                        Console.WriteLine(“The first argument must be an integer.”);
                        Console.WriteLine(“Press any key to exit.”);
                        Console.ReadKey();
                        Environment.Exit(0);
                    }
                    else
                    {
                        //Console.WriteLine(barcodeType);
                    }
                }
                else
                {
                    //just make each string a file name argument
                    Console.WriteLine(“File name to scan: ” + arg);
                    //scan the file and read the bar codes
                    ReadBarCode(barcodeType, arg);
                }
                //track the current argument
                count++;
            }
            // Keep the console window open in debug mode.
            Console.WriteLine(“Press any key to exit.”);
            Console.ReadKey();
        }
        /*
         * ReadBarCode – this takes in a string which represents a file name.
         *
         * Using the BarcodeXpressSDK object barcodeXpress1, we will:
         *
         *
         *
         *
         * */
        static void ReadBarCode(int barcodetype, string filename)
        {
            Accusoft.BarcodeXpressSdk.BarcodeXpress barcodeXpress1;
            barcodeXpress1 = new BarcodeXpress();
            Accusoft.BarcodeXpressSdk.Result[] results;
            //set the barcode type array object
            System.Array currentBarcodeTypes = new BarcodeType[1];
            /* set the type of bar code to scan for at the command line
                1:  Standard 1-dimensional bar code.
                2:  QR codes.
            */
            switch(barcodetype)
            {
                case 1:
                    currentBarcodeTypes.SetValue(BarcodeType.UnknownBarcode, 0);
                    break;
                case 2:
                    currentBarcodeTypes.SetValue(BarcodeType.QRCodeBarcode, 0);
                    break;
                default:
                    currentBarcodeTypes.SetValue(BarcodeType.UnknownBarcode, 0);
                    break;
            }
            //set the barcodeExpress object reader for what kind of bar code to scan for.
            barcodeXpress1.reader.BarcodeTypes = currentBarcodeTypes;
            //verify the file exists
            if(File.Exists(filename))
            {
                //load the file into a bitmap object
                Bitmap newBitmap = new Bitmap(filename);
                //store the results of the scan into our results array, then
                //parse the results and display the values
                results = barcodeXpress1.reader.Analyze(newBitmap);
                if (results.Length > 0)
                {
                    //for each of the results
                    for (int i = 0; i < results.Length; i++)
                    {
                        //what is the current result we’re displaying
                        Accusoft.BarcodeXpressSdk.Result curResult = (Accusoft.BarcodeXpressSdk.Result)results.GetValue(i);
                        //show which barcode is scanned and what type it is
                        Console.WriteLine(“Symbol #” + i);
                        Console.WriteLine(“Type: ” + curResult.BarcodeName);
                        //if this is a multi-dimensional bar code, such as a QR code,
                        //display the rows and columns detected
                        if ((curResult.Info2D.RowsDetected != 0) || (curResult.Info2D.ColumnsDetected != 0))
                        {
                            Console.WriteLine(“Row Column Detected=” + curResult.Info2D.RowsDetected + “,” + curResult.Info2D.ColumnsDetected);
                            Console.WriteLine(“Rows Columns = ” + curResult.Info2D.Rows + “,” + curResult.Info2D.Columns);
                            Console.WriteLine(“ECL=” + curResult.Info2D.ErrorCorrectionLevel);
                        }
                        //just in case we’re scanning in QR codes with Kanji characters,
                        //use UTF8 instead of ascii
                        Console.WriteLine(“Value: ” + Encoding.UTF8.GetString(curResult.BarcodeDataAsByte));
                    }
                }
                //if you don’t find any barcodes in this file, then say so.
                else
                {
                    Console.WriteLine(“No Barcodes Found.”);
                }
            }
            //there’s no file here – get out of there with that!
            else
            {
                Console.WriteLine(“That file does not exist.”);
            }
        }
    }
}

1次元を読み込む

1次元バーコードは、文字通りの意味での 1次元ではありません。この議論は物理学の領域に入っていくので、このドキュメントの範囲ではありません。 1次元バーコードを水平に切った線が、一連の明暗を読み取り、確立された定義に基づいた値を読み取ります。

では、これでどうなるか見てみましょう。 1 つのファイルに 1 つのバーコード画像を付けます。

SimpleBarcodeReaderCSharp.exe 1 barcode.jpg

そして、その結果はどうでしょうか?

まあ、簡単でしたね。 では、コードを見ながら、何が起こっているのかを探ってみましょう。

入門的なコードは飛ばして、関数 “ReadBarCode” の中に入っていきましょう。

static void ReadBarCode(int barcodetype, string filename)
{
    Accusoft.BarcodeXpressSdk.BarcodeXpress barcodeXpress1;
    barcodeXpress1 = new BarcodeXpress();

ここで実行していることは、画像ファイルを取り込んでスキャンすることができるオブジェクトを生成することだけです。 Windows フォームを使用している場合、おそらく Accusoft ImagXpress を活用してバーコード画像を読み込み、そこから処理することになると思いますが、この例では C# のビットマップ オブジェクトでこれを行うことができます。

switch(barcodetype)
{
 case 1:
   currentBarcodeTypes.SetValue(BarcodeType.UnknownBarcode, 0);
   break;
 case 2:
   currentBarcodeTypes.SetValue(BarcodeType.QRCodeBarcode, 0);
   break;

今回の例では、2種類のバーコードを使うだけなので、それをどう扱うかのスイッチは 2 つしか作っていません。1次元バーコードか、QR バーコードのどちらかになります。でも、もし Aztec や他のものにしたかったら、それでもかまいません。 対応するバーコードの種類は、Accusoft のドキュメント ページでご覧いただけます。

注意:カラー画像の場合、ImagXpress の自動 2 値化メソッドを使用すると、認識精度を大幅に向上させることができます。

まばたきしないでください。ここで、ファイルを Bitmap オブジェクトにロードし、barcodeXpress オブジェクトにそれを分析させるという作業を行います。

//load the file into a bitmap object
Bitmap newBitmap = new Bitmap(filename);
//store the results of the scan into our results array, then
//parse the results and display the values
results = barcodeXpress1.reader.Analyze(newBitmap);

まばたきしましたか?そうなんです、とても速いんです。 Barcode Xpress は 1分間に 1,000 ページまで処理できます。残りのコードは、検出されたバーコードから抽出できるさまざまな種類のデータについて説明しているだけです。

//show which barcode is scanned and what type it is
Console.WriteLine(“Symbol #” + i);
Console.WriteLine(“Type: ” + curResult.BarcodeName);
//if this is a multi-dimensional barcode, such as a QR code,
//display the rows and columns detected
if ((curResult.Info2D.RowsDetected != 0) || (curResult.Info2D.ColumnsDetected != 0))
{
   Console.WriteLine(“Row Column Detected=” + curResult.Info2D.RowsDetected + “,” + curResult.Info2D.ColumnsDetected);
   Console.WriteLine(“Rows Columns = ” + curResult.Info2D.Rows + “,” + curResult.Info2D.Columns);
   Console.WriteLine(“ECL=” + curResult.Info2D.ErrorCorrectionLevel);
}
//just in case we’re scanning in QR codes with Kanji characters,
//use UTF8 instead of ascii
Console.WriteLine(“Value: ” + Encoding.UTF8.GetString(curResult.BarcodeDataAsByte));

早くて、簡単です。

すべてのバーコードを読み込む

1つのファイルから複数のバーコードを読み取る

文書内に複数のバーコードがある場合はどうすればよいのでしょうか。コードを振り返ってみると、results 変数は、ドキュメント内で検索しているバーコードのうち、興味のある種類のバーコードに一致するすべてのバーコードの結果を格納する配列になっていました。これに、複数のバーコードが含まれる別のファイルを与えてみましょう。

そして、それに対してプログラムを実行すると、5種類のバーコードが得られ、そのすべてがスキャンされ、識別、エンコードされ、その値が表示されます。

損傷したバーコードの読み取り

何らかの方法で破損したり、上書きされたバーコードはどうでしょうか? スタンプが押されたり、文字が書き込まれたり、ひどく酷使されていますね。

このファイルに対して、プログラムを実行してみましょう。 Barcode Xpress は、破損したバーコードの処理も可能です。

ひとつひとつに

次の次元へ : 2次元/QR コードの読み取り

もしかしたら、1次元バーコードよりももっと複雑なものが必要かもしれません。2次元バーコードは、より多くのデータを送信し、表示することができます。様々な規格がありますが、ここでは QR コードで説明します。 (その他の規格については、「サポートされるバーコードの種類」のドキュメントを参照してください)。

1次元バーコードから QR コードへの切り替えを処理できるよう、すでにプログラムをセットアップしてあるので、コードの変更は必要ありません – すでに対応されています。 あとは、コマンドラインのスイッチでバーコードの種類を 1 から 2 に変更するだけで、これらの QR コードをすべて処理することができます。

複数のコード、複数の向き、異なるサイズを用意しました。 値を取得するだけでなく、QR コードを構成する行や列も拾い上げることができます。

試しにもう一つやってみましょう。 複数のバーコードがある文書で、1種類のバーコードだけをスキャンしたい場合はどうすればよいでしょうか?

SimpleBarcodeReaderCSharp.exe 1 QR_barcodes_and_1d.jpg

ここでは、QR コードと 1次元バーコードの両方が入ったファイルがありますが、1次元バーコードだけを探すようにスイッチをセットしておきます。

ファイルに埋め込まれたバーコードの結果だけが出ています。逆に、同じファイルでも、今度は QR コードだけを探してみましょう。

SimpleBarcodeReaderCSharp.exe 2 QR_barcodes_and_1d.jpg

何千枚もの書類をスキャンし、整理する必要がある状況を想像してみてください。あるいは、複数のバーコードで情報を追跡しているシステムを。すべてのファイルをスキャンし、すべてのバーコードを見つけ、素早く簡単にデータを利用することができます。

 

SimpleBarcodeReaderCSharp.exe 1 barcode.jpg barcode_multiple.jpg BarcodeDamaged.jpg

アプリケーションへの組み込み

ほとんどの場合、スタンドアローンのコマンドライン バーコード リーダーを構築するのではなく、開発中の大規模なアプリケーションにバーコード読み取り機能を統合することをお考えでしょう。 ほんの少しの簡単な変更で、上記の同じコードを使用して、C#アプリケーションにバーコード読み取り機能を簡単に追加することができます。

この関数は、ReadBarCode を受け取り、それを短縮して、必要に応じて解析される Accusoft BarcodeXpress Results の配列を返します。

以下は、更新されたコードです。

 

/*
         * GetBarCodeResults
         *
         * Inputs:
         *      int barcodetype – the type of barcode that we’re scanning for, default is 1-dimensional
         *      string filename – the name of the file to be scanned
         *
         * Returns:
         *      An array of Accusoft.BarcodeXpressSdk.Result
         *
         * */
        static Accusoft.BarcodeXpressSdk.Result[] GetBarCodeResults(int barcodetype, string filename)
        {
            Accusoft.BarcodeXpressSdk.BarcodeXpress barcodeXpress1;
            barcodeXpress1 = new BarcodeXpress();
            //Create our variable, store nothing in it for now.
            Accusoft.BarcodeXpressSdk.Result[] results = null;
            //set the barcode type array object
            System.Array currentBarcodeTypes = new BarcodeType[1];
            /* set the type of bar code to scan for at the command line
                1:  Standard 1-dimensional bar code.
                2:  QR codes.
            */
            switch (barcodetype)
            {
                case 1:
                    currentBarcodeTypes.SetValue(BarcodeType.UnknownBarcode, 0);
                    break;
                case 2:
                    currentBarcodeTypes.SetValue(BarcodeType.QRCodeBarcode, 0);
                    break;
                default:
                    currentBarcodeTypes.SetValue(BarcodeType.UnknownBarcode, 0);
                    break;
            }
            //set the barcodeExpress object reader for what kind of bar code to scan for.
            barcodeXpress1.reader.BarcodeTypes = currentBarcodeTypes;
            //verify the file exists
            if (File.Exists(filename))
            {
                //load the file into a bitmap object
                Bitmap newBitmap = new Bitmap(filename);
                //store the results of the scan into our results array, then
                results = barcodeXpress1.reader.Analyze(newBitmap);
                //whether or not it detects bar codes, there will be a result, but will be null
                return results;
            }
            //there’s no file here – get out of there with that!
            else
            {
                //Console.WriteLine(“That file does not exist.”);
            }
            //in the event that there was no file scanned for reasons
 //- return the results anyway but they’ll be null
            return results;
        }

 

そして、あなたのアプリケーションでこのコードの行を使用するだけで、任意の画像からバーコードを読み取ることができます。

 

Accusoft.BarcodeXpressSdk.Result[] barCodeResults =
GetBarCodeResults(barcodeType, filename);

 

この関数は、Results の配列を返します。 ここから、返された結果をデータベースに保存したり、アプリケーションの別の部分に渡したりすることが簡単にできます。

さて、問題はこのパワーを使って何をするかということです。

詳細については、Barcode Xpress の概要ページまたは Barcode Xpress の使い方ページをご覧ください。

 

Accusoft Barcode Xpress の製品詳細および評価版の申込みは、こちら


 

この資料は、Accusoft の Blog で公開されている 「How To Read A Barcode From An Image In C# 」Published: December 5, 2017 (Updated: February 21, 2020) の参考訳です。

タイトルとURLをコピーしました