こんにちは。いつもはMediumというサイトに投稿してます。ですが少し日本の政治に関係することなので日本語のコミュニティーがあるQiitaのほうで投稿することにしました。
目的
この記事の目的は最近出てきたGPT4o並のオープンソースのVLM(llama3.2, qwen2 72b)などを用いて総務省にアップロードされている手書きの政治資金収支報告書をテキストデータに変換できるか確かめることです。この記事は安く日本語のOCRしたい方、VLMのデプロイがしたい方にも役に立つかもしれません。
使うモデル
今回試してみるモデルはQwen2-VLです。GPT4oよりほぼすべてのベンチマークでパフォーマンスがよく、普通は英語と中国語のみで学習されたモデルが多い中、日本語でも学習したモデルです。一つ欠点があるとするならばアリババに作られているので中国で検閲されている内容を出力できないことだと思います。ですが、政治資金収支報告書を読み取る分には問題ないはずです。このモデルの7bモデルを試してみます。
Llama 3.2というメタ/facebookが作ったモデルhuggingface spaceでも少し試しましたがQwenのパフォーマンスと比べると政治資金収支報告書においては今一つでした。なのでこのブログでは紹介しません。
日本の会社・政府が作った良いVLMは今のところは見つかりませんでした。
使うデーター
この際使うデーターは総務省のサイトからスクレイピングしたデーターです(出典:総務省ホームページ )。日本の政治家が使えるお金は政治資金と政党交付金があります。ここで法律上の二つの制約があります。
- 政党交付金のほうは閲覧できてもダウンロードは無理です。ダウンロードしようとすると白紙のpdfが出ます。これは法律で見れないようにしているので今は対象外とします。ですがもし詳しい方がいてスクリーンショットしてVLMで解析することが可能/法律違反でなければ教えてください。seleniumなどでそれをやってここに追記します。
- 期間は政治資金は5年間のみ政党交付金は3年間のみしか公表されてません。それ以前のデーターは配布は著作権の問題で無理かもしれません。ですが公共の利益のためには著作権は無視できるとか書いてあると思いますが詳しい人がいたら教えてください。
もし需要があれば解説しますがスクレイピングに使ったスクリプトはこれです。
これはpdfをdata/jp/money_for_parties/balancesというフォルダーにダウンロードします。pdfを画像に変換するためにこのスクリプトが用意されています。
ここですべてダウンロード・変換したデーターを出典込みでHuggingfaceに載せることを検討しています。もし詳しい方がおりましたら法律上問題ないか教えてください。
環境構築
まずある程度vramがあるGPUが必要です。この記事ではA40のGPUを使いますが特にパラメーターが低い7bモデルの場合は12gb vramくらいのGPUで十分先に進めると思います。
pythonとcudaのインストールはこの記事で説明してあるのでその通りにすればできると思います。一つの変えるとするならばanacondaではなくminicondaがお勧めです。
ほかにもpytorchをインストールしてください。これはこのサイトでcudaのバージョンとpythonのバージョンにあったpytorchをインストールできます。
次に必要なパッケージをインストールします。このためには
pip install vllm transformers huggingface_hub openai
で十分なはずです。僕はlinuxの環境ので追加で
cp /usr/lib/x86_64-linux-gnu/libstdc++.so.6 /path/to/miniconda3/envs/ml_client/lib/python3.10/site-packages/torch/lib/../../../.././libstdc++.so.6
が必要でした。
LLMのダウンロード
このステップではもうLLMが32bitから4bitに圧縮(量子化)されているモデルをダウンロードします。具体的に何をしているかというと普通の小数点の数値は32 bitで表現されています。
これだとLLMの大きさが冗談にならないくらい大きくなりかつどのGPUにも入らないという状態が起こったので4 bitだけで表現できないかと考えた方がいました。この手法が量子化と呼ばれています。具体的なやり方について何が一番いいかはまだ研究段階です(もし興味ある方がいれば後日ブログにします)。ですが本質的に1/8の大きさでもパフォーマンスがあまり落ちないことはLLMの面白さの一つだと思います。
ですが今回はvllmがサポートするやり方なのでgptqを使ったモデルをダウンロードします。
--cache-dirには保存したいフォルダーを指定してください。
huggingface-cli download --cache-dir .cache Qwen/Qwen2-VL-7B-Instruct-GPTQ-Int4
huggingface-cli download --cache-dir .cache Qwen/Qwen2-VL-2B-Instruct-GPTQ-Int4
まず残念ながら72BのほうはHuggingfaceのスペースで試す分にはパフォーマンスは素晴らしいですが筆者が使っているGPUとvllmではモデルが大きすぎて動かせませんでした。exllamav2などでできるかもしれないので後で試してみます。
ですがベンチマークを見てみましょう。72Bのモデルのパフォーマンスは以下の通りで
7bは
です。MMMUとMathVistaという論理などが必要なタスクではパラメーターが低い7bモデルが不利なのがわかりますがDocVQAといった画像にかかれているテキストを読み取って質問に事得るベンチマークではあまりパフォーマンスが落ちてないことが読み取れます。
流石に2bではかなり落ちました
では実際にデプロイしていきましょう。
デプロイ
もしsshサーバーを使ってデプロイしているのでしたらポートフォーワディングが必要です。vLLMは0.0.0.0:8000にサーバーを開くので、sshで繋げる際に
ssh -L 8000:0.0.0.0:8000 username@ip_address
と-Lを使ってください。
もし自分のパソコンでデプロイする場合は上を無視して大丈夫です。次にモデルがダウンロードした場所を見つけましょう。これはcache-dirでモデルの名前、snapshot、ハッシュで保存されてあります。筆者の場合は.cache/models--Qwen--Qwen2-VL-7B-Instruct-GPTQ-Int4/snapshots/dec510a35a3e9b6481b6427c7a08984df2402535でした。これを使い、
vllm serve .cache/models--Qwen--Qwen2-VL-7B-Instruct-GPTQ-Int4/snapshots/dec510a35a3e9b6481b6427c7a08984df2402535/ --max-model-len 8192 --api-key token-abc123
でサーバーを立ち上げられます。モデルをロードするのに6gb vramを使います。max-model-lenを32768と32768トークン(文字)をLLMが読めるようにした結果35gb vram必要でした。これを低めるとよりkv cacheというものにvramをあまり使わなくてよくなるので速くなります。画像の大きさによりますが正直1024や512トークンで十分だと思いますのでGPUのサイズに合わせて調整してください。
これでデプロイは完了し、sshでしたらlocalhost:8000に、ローカルでしたら0.0.0.0:8000でモデルのサーバーをアクセスできます。
テストデータ
このブログでは簡単なドキュメントと難しいドキュメントなどでどこまでOCRできるか試してみます。全部高いクオリティーでできるようでしたら後でHuggingfaceにデーターセットとして載せようと考えてます。
では令和5年8月31日公表(令和4年分解散分)、自由民主党鹿児島県参議院比例区第三十一支部の2ページを見ていきましょう。
また6ページなどは
そして8ページは
ここで普通のOCRで難しい理由が少しわかると思います。こういった訂正・手書きの後が結構多いです。もちろんもっときれいなのもあります。例えば令和5年8月31日公表(令和4年分解散分)の自由民主党東京都参議院比例区第八十六支部では手書きの箇所が一切なくパソコンですべて出力されているようです。
ですがこれもこれで文字の量が多いので読み取れるか興味あります。では試していきましょう。
テスト
ではまずは"何かいてあるか文字で出力してください。"という入力で結果を見ていきましょう。それぞれ2回出力しました。2回目はtemperatureを0.8にしました。
from openai import OpenAI
import base64
from io import BytesIO
client = OpenAI(
base_url="http://localhost:8000/v1",
api_key="token-abc123",
)
image_urls = ["1.jpg", "5.jpg", "7.jpg", "22.jpg"]
chat_responses = []
# from https://community.openai.com/t/how-to-load-a-local-image-to-gpt4-vision-using-api/533090/3
def encode_image(image_path):
with open(image_path, "rb") as image_file:
return base64.b64encode(image_file.read()).decode('utf-8')
for image_url in image_urls:
base64_image = encode_image(image_url)
chat_response = client.chat.completions.create(
model=".cache/models--Qwen--Qwen2-VL-7B-Instruct-GPTQ-Int4/snapshots/dec510a35a3e9b6481b6427c7a08984df2402535/",
messages=[{
"role": "user",
"content": [
# NOTE: The prompt formatting with the image token `<image>` is not needed
# since the prompt will be processed automatically by the API server.
{"type": "text", "text": "何かいてあるか文字で出力してください。"},
{"type": "image_url", "image_url": {"url": f"data:image/jpeg;base64,{base64_image}"}},
],
}],
temperature=1.0
)
print(chat_response)
chat_responses.append(chat_response)
この画像は、日本語で記載されたビジネスまたは財務文書のスキャン画像です。主に以下のような情報を含んでいます。
### 収支の状況 (1)
1. **収入」**
- 総額: 21,714,829円
- 本年から前年の継越額: 21,300,000円
- 本年の収入額: 21,514,829円
2. **支出」**
- 総額: 21,714,829円
- 本年から前年の継越額: 19,000,000円
- 本年の支出額: 24,014,829円
3. **翌年への継越額」**
- 17,438円
### 収入項目別金払内訳 (2)
1. **個人の内容する党費又は会費」**
- 金額: 0円
- 員数: 0人
2. **寄付」**
- 金額: 230,000円
この表は、業務計画、収支紹介、紙上表記の具体的な情報などに関する情報源と見られるか、それに見合うものにいました。
---
Do you need the translations of the written content?
と
以下は画像内のテキストです。
---
**収支の状況**
1. **収支の総括表**
| 収入 | 総額 | 出資金 | 資産 |
|----------------|------|-----------------|-----------------|
| 24,014,829 | | 2,714,829 | 19,000,000 |
| 支出 | 総額 | 支出資金 | 傺 |
| 24,014,812 | | 21,714,391 | 17,438 |
2. **収入項目別の内訳**
(1) **個人の負担する会費**
| 金額 | 員数(会費を納めた人の数) | 傍 |
|------|--------------------------|----------------|
| 0 | 0 | 0 |
(2) **寄 附**
| 分区 | 金額 | 傍 |
|----------------|------|----------------|
| (a) 個人からの寄付 | 0 | 0 |
| (b) うち特定寄付 | 0 | 0 |
| (c) 法人その他の団体からの寄付 | 0 | 0 |
| (d) 政治団体からの寄付 | 0 | 0 |
| 小計 | (a) + (b) + (c) + (d) | 2,300,000 |
| (寄附のうち寄附の有無に係る部分) | 0 | 0 |
| 思党匿名寄附 | 0 | 0 |
| 合計 | (a) + (イ) | 2,300,000 |
---
**注意**
この画像には、会計の詳細な記録が含まれていますが、特定の条件や文脈で使用する場合に注意が必要です。具体的な目的や上下文が記載されていないため、適切な意味を理解するために追加の情報が必要かもしれません。ただし、この情報が特定の会計ハンドブックやガイドラインに従って整理されている場合は、以下のようなものに該当していると思われます。
以下は画像から抽出されたテキストです。
3. 項目別の金額の内訳
(1) 支出の管理表
- 当用品購入費:9,219,999
- 光熱水費:39,435
- 道品・票品購入費:1,906,506
- 事務費用:2,757,962
- 小計:13,729,702
- 政治活動費:6,304,071
- 受けドングリ設備費:10,078,110
- 発行費:4,356,830
- 副表設立費:291,50
- 事前事前費:4,065,330
- その他の事業費:0
- 小計:10,854,110
- 合計:21,714,281
備考:本批次又は部類において供与した重量金に関連する費用
と
当然、以下の内容を文字で出力します。
---
**表の画像は、私が手動で読み取り、文字に変換した内容です。以下、可能な範囲で詳細に分類と新規文字コードの記載を行いました。**
### 支出の總括表
| 項目 | 金額 | 備考 | 考 |
|-------|-------|--------|--------|
| 1 | 人件費 | 13,917,899 | 0 |
| 2 | 光熱水費 | 119,990 | 0 |
| 3 | 備品・消耗品費 | 5,435 | 0 |
| 4 | 事務所費 | 2,797,962 | 0 |
| 小計 | | 1,390,506 | 0 |
| 2 政治活動費 | | 728,280 | 0 |
| 3 政治資金銀行掛支払金 | | 1,793,162 | 0 |
| 計 | | 13,929,702 | 0 |
| 檢討 | | 11,880,121 | 0 |
| 合計 | | 21,714,391 | 0 |
---
注:この表は、特定の会計年度の支出を整理し、項目ごとの金額を詳細に記載しています。各項目の総計は13,929,702円で、これが合計として21,714,391円と一致しています。
以下は、あなたのフォントの読み取りに誤りがあるため、正確さが確保されていないかもしれません。それでも、他の説明者がそれを直訳できる範囲でそれを適切に読み取ります。
(その14)
(2)粟常料理。の入り..."
このページの小計: 11,816
その他の支出: 927,525
と
以下は、画像に書かれているテキストです。
(2) 経常経費(人件費を除く。)の内訳
| 行番号 | 支出の目的 | 金額 | 年 月 日 | | | | | |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
| 1 | ガソリン代 | 99,026 | R4/1/4 | トヨタファイナンス(株) | 名古屋市西区牛島町6-1 | | | |
| 2 | ガソリン代 | 109,329 | R4/2/2 | トヨタファイナンス(株) | 名古屋市西区牛島町6-1 | | | |
| 3 | ガソリン代 | 89,107 | R4/3/2 | トヨタファイナンス(株) | 名古屋市西区牛島町6-1 | | | |
| 4 | ガソリン代 | 84,697 | R4/4/4 | トヨタファイナンス(株) | 名古屋市西区牛島町6-1 | | | |
| 5 | ガソリン代 | 70,012 | R4/5/2 | トヨタファイナンス(株) | 名古屋市西区牛島町6-1 | | | |
| 6 | ガソリン代 | 95,517 | R4/6/2 | トヨタファイナンス(株) | 名古屋市西区牛島町6-1 | | | |
| 7 | ガソリン代 | 75,123 | R4/7/4 | トヨタファイナンス(株) | 名古屋市西区牛島町6-1 | | | |
| 8 | 備品費 | 10,227 | R4/1/20 | リコージャパン(株) | 大阪府吹田市江の木町34-5-3F | | | |
| 9 | 備品費 | 15,452 | R4/2/21 | リコージャパン(株) | 大阪府吹田市江の木町34-5-3F | | | |
| 10 | 備品費 | 10,655 | R4/3/22 | リコージャパン(株) | 大阪府吹田市江の木町34-5-3F | | | |
| 11 | 備品費 | 19,236 | R4/4/20 | リコージャパン(株) | 大阪府吹田市江の木町34-5-3F | | | |
| 12 | 備品費 | 25,284 | R4/5/20 | リコージャパン(株) | 大阪府吹田市江の木町34-5-3F | | | |
| 13 | 備品費 | 37,734 | R4/6/20 | リコージャパン(株) | 大阪府吹田市江の木町34-5-3F | | | |
| 14 | 備品費 | 126,561 | R4/7/20 | リコージャパン(株) | 大阪府吹田市江の木町34-5-3F | | | |
| 15 | 備品費 | 47,749 | R4/8/22 | リコージャパン(株) | 大阪府吹田市江の木町34-5-3F | | | |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
| | | | | | | | | |
| | | | | | | | | |
| | | | | | | | | |
| | | | | | | | | |
| | | | | | | | | |
| | | | | | | | | |
| | | | | | | | | |
| | | | | | | | | |
| | | | | | | | | |
| | | | | | | | | |
| | | | | | | | | |
| | | | | | | | | |
合計:1927,525
このページの小計:915,709
その他の支出:11,816
下記のように文字を出力します。
| 行番号 | 支 出 の 目 的 | 金 額 | 年 月 日 | 支出を受けた者の氏名 | 支出を受けた者の住所(団体にあっては、その名称) |
|---------|---------------|--------|-----------|--------------------|--------------------------------------------------|
| 46 | | 23,170 | R4/5/21 | 日本航空(株) | 東京都品川区東品川二丁目4番11号野村不動産天王洲ビル |
| 47 | | 21,770 | R4/5/22 | 日本航空(株) | 東京都品川区東品川二丁目4番11号野村不動産天王洲ビル |
| 48 | | 43,890 | R4/5/22 | 日本航空(株) | 東京都品川区東品川二丁目4番11号野村不動産天王洲ビル |
| 49 | | 21,770 | R4/5/23 | 日本航空(株) | 東京都品川区東品川二丁目4番11号野村不動産天王洲ビル |
| 50 | | 57,730 | R4/5/24 | (株)JTB | 東京都千代田区永田町2-2-1 A京都第一議員会館内地下4階 |
| 51 | | 81,560 | R4/5/24 | (株)JTB | 東京都千代田区永田町2-2-1 A京都第一議員会館内地下4階 |
| 52 | | 20,110 | R4/5/24 | 日本航空(株) | 東京都品川区東品川二丁目4番11号野村不動産天王洲ビル |
| 53 | | 19,590 | R4/5/25 | 東日本旅客鉄道(株) | 東京都渋谷区代々木二丁目2番2号 |
| 54 | | 11,900 | R4/5/25 | レム新大阪 | 大阪府大阪市淀川区宮原1-1-1 |
| 55 | | 19,590 | R4/5/26 | 東海旅客鉄道(株) | 愛知県名古屋市中村区名駅一丁目1番4号 JRセントラルタワーズ |
| 56 | | 25,120 | R4/5/28 | 日本航空(株) | 東京都品川区東品川二丁目4番11号野村不動産天王洲ビル |
| 57 | | 59,840 | R4/5/30 | (株)JTB | 東京都千代田区永田町2-2-1 A京都第一議員会館内地下4階 |
| 58 | | 21,720 | R4/5/31 | 日本航空(株) | 東京都品川区東品川二丁目4番11号野村不動産天王洲ビル |
| 59 | | 20,250 | R4/5/31 | 東日本旅客鉄道(株) | 東京都渋谷区代々木二丁目2番2号 |
| 60 | | 12,800 | R4/5/31 | ANAクラウンプラザホテル神戸 | 兵庫県神戸市中央区北野町1丁目 |
このページの小計 | 460,810 |
と
(その15)
(3) 政治活動費の内訳
| 行番号 | 支出の目的 | 金額 | 年月日 | 支出を受けた者の氏名(団体にあっては、その名称) | 支出を受けた者の住所(団体にあっては、主たる事務所の所在地) | 備考 |
| --- | --- | --- | --- | --- | --- | --- |
| 46 | 航空券代 | 23,170 | R4/5/21 | 日本航空(株)東京都品川区東品川二丁目4番11号野村不動産天王洲ビル | | |
| 47 | 航空券代 | 21,770 | R4/5/22 | 日本航空(株) | | |
| 48 | 航空券代 | 43,890 | R4/5/22 | 日本航空(株) | 東京都品川区東品川二丁目4番11号野村不動産天王洲ビル | |
| 49 | 航空券代 | 21,770 | R4/5/23 | 日本航空(株) | 東京都品川区東品川二丁目4番11号野村不動産天王洲ビル | |
| 50 | 航空券代 | 57,730 | R4/5/24 | (株)JTB(衆議院第一議員会館内地下4階) | 大阪府大阪市北区永田町2-2-1 | |
| 51 | 鉄道運賃 | 81,560 | R4/5/24 | (株)JTB(衆議院第一議員会館内地下4階) | | |
| 52 | 航空券代 | 20,110 | R4/5/24 | 日本航空(株) | 東京都品川区東品川二丁目4番11号野村不動産天王洲ビル | |
| 53 | 鉄道運賃 | 19,590 | R4/5/25 | 東日本旅客鉄道(株) | 東京都渋谷区代々木二丁目2番2号 | |
| 54 | 宿泊代 | 11,900 | R4/5/25 | レム新大阪 | 大阪府大阪市淀川区宗原1-1-1 | |
| 55 | 鉄道運賃 | 19,590 | R4/5/26 | 東海旅客鉄道(株) | 愛知県名古屋市中央区名駅一丁目1番4号JRCENTRALTOWERS | |
| 56 | 航空券代 | 25,120 | R4/5/28 | 日本航空(株)東京都品川区東品川二丁目4番11号野村不動産天王洲ビル | | |
| 57 | 鉄道運賃 | 59,840 | R4/5/30 | (株)JTB(衆議院第一議員会館内地下4階) | 東京都千代田区永田町2-2-1 | |
| 58 | 航空券代 | 21,720 | R4/5/31 | 日本航空(株) | 東京都品川区東品川二丁目4番11号野村不動産天王洲ビル | |
| 59 | 鉄道運賃 | 20,250 | R4/5/31 | 東日本旅客鉄道(株) | 東京都渋谷区代々木二丁目2番2号 | |
| 60 | 宿泊代 | 12,800 | R4/5/31 | ANAクラウンプラザホテル神戸 兵庫県神戸市中央区北野町1丁目 | | |
この頁の小計 460,810
上を見た通り温度を下げたほうがいい結果が出ました。あとOCRしてくださいとやると間違いが増えたので日本語のみでやるほうがいいと思います。ただ上を見てみるとわかる通り手書きの場所においてはほぼ全滅しています。なので手書きがあるか検出し、あったらスキップして活字の場所のみをデーター化すると面白いかもしれません。
ですが最後の画像でもわかるように手書きがなくとも多少の間違いが見られたりします。これは温度をより下げるとよくなるのかもしれません。
あともう一つ考えられる工夫はドキュメントの構成は決まっているので一つ一つの項目でqwenに個々の値は何かと聞くのも面白いかもしれません。ただこれの欠点は空欄の項目の扱いが多少面倒になりそうなことです。constrained generationという出力の形式を限定するようにしたら問題を乗り越えられるかもしれません。
上の手書きの問題/手書きを無視する問題はこのスペースで試した結果72Bでも起きました。面白いことに最後の画像でも72Bで似たような失敗などが見られました。
要約すると結構いいところまで行きましたが何の工夫もなく政治資金収支報告書をVLMに入れてもすべて読み取れませんでした。少し時間が空いたらこのブログのpart 2としてそのちょっとした工夫などを試してみて紹介したいと思います。ですが今回のブログはさすがに長くなりすぎたのでいったん終わります。
OCRとの比較
どの程度上のVLMがすごいか実感するためにOCRもやってみましょう。PaddleOCRを使いました。
# From https://qiita.com/ku_a_i/items/d4c1ce70836b8035a449
from paddleocr import PaddleOCR
from PIL import Image, ImageEnhance, ImageFont, ImageDraw
import numpy as np
import cv2
from loguru import logger
# Paddleocr supports Chinese, English, French, German, Korean and Japanese.
# You can set the parameter `lang` as `ch`, `en`, `fr`, `german`, `korean`, `japan`
# to switch the language model in order.
image_urls = ["1.jpg", "5.jpg", "7.jpg", "22.jpg"]
def japanese_puttext(img, text, position, font, fill = (255, 0, 0)):
""" cv2.putTextが日本語対応してないので、自分で関数を定義する"""
img_pil = Image.fromarray(img) # PIL Imageに変換。
draw = ImageDraw.Draw(img_pil) # drawインスタンスを生成
draw.text(position, text, font = font , fill = fill) # drawにテキストをのせる
img = np.array(img_pil) # PILを配列に変換
return img
def run_ocr(img_path, output_path):
""" OCRメイン関数"""
#画像読み込み+前処理(適当)+PaddleOCR入力用にnpへ
im = Image.open(img_path).convert('L')
enhancer= ImageEnhance.Contrast(im) #コントラストを上げる
im_con = enhancer.enhance(2.0) #コントラストを上げる
np_img = np.asarray(im_con)
logger.debug('画像読み込み完了') #logは今までと変わらない!
#PaddleOCRを定義
ocr = PaddleOCR(
use_gpu=False, #GPUあるならTrue
lang = "japan", #英語OCRならen
det_limit_side_len=im_con.size[1], #画像サイズが960に圧縮されないように必須設定
max_text_length = 30, #検証してないがテキスト最大長のパラメータ。今回は不要だが紹介
)
logger.debug('PaddleOCR設定完了')
#PaddleOCRでOCR ※cls(傾き設定)は矩形全体での補正なので1文字1文字の補正ではない為不要
result = ocr.ocr(img = np_img, det=True, rec=True, cls=False)
logger.debug('PaddleOCR実行完了')
#OCR結果転記用
result_img = np_img.copy()
result_img = cv2.cvtColor(result_img, cv2.COLOR_BGR2RGB)
fontpath ='PaddleOCR/doc/fonts/japan.ttc'
font = ImageFont.truetype(fontpath, 30) #サイズ指定
#OCR結果を画像に転記
for detection in result[0]:
t_left = tuple([int(i) for i in detection[0][0]]) #左上
# t_right = tuple([int(i) for i in detection[0][1]]) #右上
b_right = tuple([int(i) for i in detection[0][2]]) #右下
b_left = tuple([int(i) for i in detection[0][3]]) #左下
ocr_text = detection[1][0] #テキスト(detection[1][1]なら自信度取得も可能)
#画像に文字範囲の矩形を載せる(緑色)
result_img = cv2.rectangle(result_img, t_left, b_right, (0, 255, 0), 3)
"""putTextだと日本語が??になってしまうので自作関数で処理。文字の位置は左下とした"""
# result_img = cv2.putText(result_img, ocr_text, t_left, cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 0, 0), 1, cv2.LINE_AA)
result_img = japanese_puttext(result_img, ocr_text, (b_left[0], b_left[1]), font)
logger.debug('画像にOCR結果記載完了')
#保存する
result_img = cv2.cvtColor(result_img, cv2.COLOR_RGB2BGR)
cv2.imwrite(output_path, result_img)
logger.debug('結果画像の保存完了')
image_urls = ["1.jpg", "5.jpg", "7.jpg", "22.jpg"]
for image_url in image_urls:
run_ocr(image_url, f"result_{image_url}")
上で見てわかるように文字の一つ一つを一応検出できるかもしれませんが全体の文字の関連性、例えば予算であれば「合計」であるはずなのに今、計と読み取るなど結構全体のドキュメントとして見ていないことから起こる間違いが多いようです。これと比べるとVLMのほうがより良い結果を出すことがわかると思います。
一番面白いのはOCRとVLMに何かしらの連携を加えることだと思いますが今の段階ではまだ思いついてません。
まとめ/動機
ここまで読んでいただいてありがとうございます。僕は成田悠輔さんの政治家ではなく政策に投票するべきという主張に感銘を受けてこのプロジェクトを始めました。
今の段階ではまだ政策に投票すること自体は無理だと思いますが選択肢にある政治家がどのような政策をするか、どこから金を貰っているか、発言などという情報をデータベース化・オープンソースにしてみたいなと思ってます。もっと具体的には政治家一人一人のなぜ政治家をやっているか、何を成し遂げたいか、政策の変化、癒着などの「人物像」を作りたいと思っています。そのためのデーターと知って国会の発言、法令索引なども考えています。
最近の日本の政治がインターネット/SNSともっとつながり活発になってきたのも一つの動機です。正直AIの活用方法などはまだ決まってませんが結構面白い研究基盤になったらいいなと思ってますので何か出来たらその都度qiitaのブログにしてみる予定です。このgithubのリポを使う予定なので質問・協力など大歓迎です。
後もし誤字・脱字などがありましたら教えてくれるとありがたいです。