📊

2次元ではなく1次元バーコードの仕組みを調べてみた

に公開

はじめに

私はカロリーメイトが好きで常備しているんですが、今日、仕事中にふと側面の(1次元)バーコードに目が止まりました。

jan-code

昨今では、QRコードをはじめとする2次元バーコードばかりが取り沙汰されていますね。
1次元バーコードについての技術面が語られる機会は聞いたことがなかった。

ということで、改めて1次元バーコードの理解を深めるため、日本の食品に広く使われているJANコードの仕様から、画像を読み取ってデコードするまでの処理フローを調べた結果を整理したいと思いました。

日本の食品についているバーコード

JANコード

日本の一般的な食料品には、 JANコード(Japanese Article Number) が使用されているそうです。これは国際標準である EAN-13(European Article Number) と互換性がある一次元バーコード。

基本仕様:

  • 規格名: JIS X 0501(EAN/UPC互換)
  • 構成: 13桁の数字
  • 例: 4901234567894

jan-code

上記の図は、JANコードの構造を示している。13桁の数字列は4つの要素に分解される。

バーコードを読み取る仕組み

「画像から一次元バーコード(JAN/EAN-13)を読む」処理は、以下の6ステップで構成される。

jan-code

生成AIで作った図なので少し雑ですが、ご容赦ください。

ステップ1: 画像入力・前処理

カメラやスキャナから画像を取得し、以下の前処理を施す:

  1. グレースケール化: カラー情報を輝度に変換
  2. 平滑化: ガウシアンフィルタでノイズを低減
  3. コントラスト強調: 明暗差を明確化
  4. 二値化: バーとスペースを黒/白に分離

スマートフォンアプリでは、ガイド枠の表示やオートフォーカスの調整により、撮影品質を向上させている。

ステップ2: バーコード領域検出

画像全体から「バーコードらしい部分」を探す。主な手法:

  • エッジ検出: Sobelフィルタで平行な縦線が密集した領域を抽出
  • 投影プロファイル: 横方向スキャンで明暗の周期的変化を検出
  • 形状判定: 細長い長方形で縦線が多い領域を候補に

複数候補がある場合、コントラスト・線の整列度・アスペクト比などでスコアリングし、最適な領域を選択する。

ステップ3: 姿勢・歪み補正

撮影角度によるバーコードの斜めや台形歪みを補正する。

  • 回転補正: バーの向きを推定し、垂直/水平に回転
  • 射影変換: 4頂点を推定し、正面から見た長方形に変換

ステップ4: バー・スペースパターン抽出

補正済み画像から1次元の明暗パターンを抽出する。

処理フロー:

  1. 画像中央の水平ラインをスキャン
  2. ピクセルの輝度を取得
  3. しきい値処理で黒/白に分類
  4. 連続する黒=バー幅、白=スペース幅として測定

全体の幅から「最小モジュール幅」を推定し、各バー/スペースを正規化する。これにより、「バー幅・スペース幅のシーケンス」が得られる。

ステップ5: 規格に従ったデコード(EAN-13の場合)

ガードパターンの検出

EAN-13は以下の固定パターンで構成される:

jan-code

ガードパターンを起点として、開始・中央・終了位置を特定する。

数字への変換

1桁ごとに7モジュールのパターンが割り当てられている。左側6桁は偶数/奇数パリティ付き、右側6桁は別パターンを使用。

各バー/スペース配列をパターン表と照合し、「0〜9」の数字に変換する。左側6桁のパリティ組み合わせから先頭桁を決定し、13桁の数字列を得る。

ステップ6: チェックディジット検証と結果出力

EAN-13では以下の式でチェックディジットを計算する:

チェックディジット = 10 - ((奇数桁合計 + 3 × 偶数桁合計) mod 10)

計算結果と13桁目が一致すれば「正しく読めた」と判定し、コード値をアプリケーションに渡す。不一致の場合は、別のスキャンラインで再デコードする。

実例: カロリーメイトのバーコード

ここでは、大塚製薬の「カロリーメイト ブロック」を例に、実際のバーコードデコード処理を見る。

バーコード情報

  • コード: 4987035648918
  • 国コード: 49(日本)
  • メーカーコード: 4987035(大塚製薬株式会社)
  • 商品コード: 64891
  • チェックディジット: 8

チェックディジット計算の実例

実際に 4987035648918 のチェックディジットを計算してみる。

計算手順:

  1. 奇数桁の合計(左から1, 3, 5, 7, 9, 11桁目):

    4 + 8 + 0 + 5 + 4 + 9 = 30
    
  2. 偶数桁の合計(左から2, 4, 6, 8, 10, 12桁目):

    9 + 7 + 3 + 6 + 8 + 1 = 34
    
  3. チェックディジット計算:

    (30 + 3 × 34) = 30 + 102 = 132
    132 mod 10 = 2
    10 - 2 = 8
    
  4. 検証結果:

    • 計算結果: 8
    • 実際の13桁目: 8
    • 一致 → 検証OK

メーカーコードは誰が決めてるの?

GS1 Japanが決めてる

JANコードの事業者コード(例: 4987035)は、 GS1 Japan(一般財団法人流通システム開発センター) が管理・付与している。

GS1 Japanは日本国内でのバーコード識別番号(JAN企業コード)の発行機関であり、国際機関GS1本部(ベルギー)の管理下で運営されている。企業ごとに「事業者コード(Company Prefix)」を登録し、その範囲内で企業が独自に商品コードを付与するそうだ。

コード体系の構造

日本のJANコード(13桁)は以下のように構成される:

区分 桁数 内容 管理主体
国コード 2桁 国識別(49, 45など) GS1本部
事業者コード 4〜7桁 企業識別 GS1 Japan
商品コード 3〜6桁 商品識別 各企業
チェックディジット 1桁 検証用 自動算出

カロリーメイトの例:

  • 国コード: 49(日本)
  • 事業者コード: 87035(大塚製薬)
  • 商品コード: 6489
  • チェックディジット: 8

事業者コードの桁数

事業者コードの桁数は、登録時の企業の登録商品数によって異なる:

  • 短いコード(4桁): 登録範囲が広い大企業向け
  • 長いコード(7桁): 登録範囲が狭い小規模企業向け

まとめ

本記事では、日本の食品に広く使われている一次元バーコード「JANコード」について、ふとした疑問から調査を行いました。ゼロからのプログラム実装もそこまで難しくなさそうですし、書いてみても面白いかもしれませんね。

参考文献

Discussion