給与明細を撮って読ませたら、罫線に負けた
計算が合っているかを、自分の給与明細で確かめたかった。
撮った写真を読ませたら、322,000円が「gm [0m 5o」になって返ってきた。
原因にたどり着くまで2時間かかった。
このツールがいちばん言われたくない言葉は「計算が合っていない」だと思う。
税率も料率も一次資料で確認しているけれど、本当に合っているかを確かめる方法が、これまで無かった。
手元に答えがあることに気づいた。給与明細だ。
毎月そこに、実際に引かれた健康保険料も厚生年金も印刷されている。あれを読み取って突き合わせれば、答え合わせになる。
まず決めたのは、画像を外に出さないこと
給与明細は個人情報のかたまりだ。会社名も、氏名も、いくらもらっているかも全部載っている。
それを外部のOCRサービスに送る作りにだけはしたくなかった。
ブラウザの中だけで文字を読む方法を探して、Tesseract.js を使うことにした。
ライブラリと日本語の学習データはCDNから取りに行くけれど、送るのはそのリクエストだけで、写真そのものはこの端末から出ない。
読ませてみたら、数字が消えていた
サンプルの明細を作って読ませた。返ってきたのがこれだ。
給与 明細 書
株 式 会 社 サ ンプ ル 2026 年 8 月 分 山田 太郎
支給
0 下 | oo
融 結 | go
E E)
日本語はなんとなく読めている。数字が全滅している。
322,000 と印字されているところが「gm [0m 5o」になって返ってくる。
画像が小さいのかと思って1800pxまで拡大した。変わらない。
日本語モデルは数字が苦手だと聞いたので、英語モデルも一緒に読ませた。少し良くなったが、金額はまだ壊れている。
文字の認識モードも変えてみた。だめだった。
犯人は罫線だった
ここで、返ってきた文字列をもう一度眺めた。
「|」が異様に多い。縦棒だ。
明細は表組みになっている。項目名と金額のあいだに縦の罫線があり、行ごとに横の罫線がある。
OCRはそれを文字として読んでいた。数字にくっついた縦線が「1」や「|」に化けて、隣の桁まで巻き込んで壊していた。
対策は単純だった。読ませる前に、長く続く黒い線を白で塗りつぶす。
文字の一画がページの3割の長さになることはないので、そこまで続く黒は罫線だと決めていい。
これを入れた瞬間、同じ画像から全部の金額が正確に読めるようになった。
総 支給 額 322,000
健康 保険 料 16,100
厚生 年 金 保 険 料 29,280
雇用 保険 料 1,771
拡大も英語モデルも効いてはいたのだと思う。でも決定打は罫線を消すことだった。
2時間ほど、画像の解像度と認識モードばかり疑っていた。原因が紙のほうにあるとは考えなかった。
もうひとつ、日本語の読まれ方でつまずいた
金額が読めるようになっても、今度は項目に結びつかない。
上の引用をよく見ると「厚生 年 金 保 険 料」と分かち書きされている。
プログラムは「厚生年金」という言葉を探していたので、これでは一致しない。
照合する前に空白を落とす。これだけで全項目が拾えるようになった。
厚生年金が、1円も違わなかった
読み取った金額と、このツールの計算結果を並べてみた。
厚生年金保険料は明細29,280円に対して計算29,280円。1円も違わなかった。
健康保険料は16,100円に対して16,128円で、差は28円。
所得税と住民税はもっとずれた。所得税が2,408円、住民税が4,492円の差。
これは計算が間違っているのではなく、そうなるのが正しい。毎月の所得税は源泉徴収税額表による概算で年末調整で精算されるし、住民税は前年の所得で決まって6月から翌年5月まで同じ額が引かれる。
画面にもその説明を出すようにした。「ずれている」ではなく「ずれて当然」だと分かるほうが、読む人の役に立つ。
作ってみて分かったのは、答え合わせの機能は計算の正しさを証明するためだけのものではないということだった。
自分の明細のどの数字が何で決まっているのかが、並べてみると見えてくる。
そちらのほうが、たぶん価値がある。
ほかにも書いています
note・スタンプ※noteは運営者が個人で書いているものです。
