以下の内容はhttps://touch-sp.hatenablog.com/entry/2025/03/21/235646より取得しました。


ローカルで動くOCRアプリがあれば便利なので最近話題の「Mistral-Small-3.1-24B-Instruct-2503」や「gemma-3-27b-it」で作ってみました。ついでに「EasyOCR」でも作って性能比較もしてみました。

注意

「Mistral-Small-3.1-24B-Instruct-2503」と「gemma-3-27b-it」は自身のPC環境の制限のため4bit量子化して使用しています。

本来はもう少し性能が高いと思いますので今回の結果は参考程度に見て下さい。

パラメーターの設定も詰め切れてないと思います。

お題①


Mistral-Small-3.1-24B-Instruct-2503

この画像から抽出されたテキストは以下の通りです:

---

**警察が捜査しました。**

当院は、安心・信頼の医療の提供を指針としております。

暴力・脅迫・迷惑行為はお断りします!!

これからは厳正に対処します。

---

このテキストは、医療機関が暴力や脅迫、迷惑行為に対して厳正に対処する旨を伝えるポスターのようです。

gemma-3-27b-it

画像から以下のテキストを抽出しました。

**警察OBが 巡回しています**

当院は、安全・安心な医療の提供を目指しております

**暴力・暴言・迷惑行為は お断りします!!**

これらの行為は 厳正に対処します

EasyOCR

警察のが
巡回しでいます
当院は
安全・安心な医療の
提供を目指しております
暴力 ・ 暴言 ・ 迷惑行為は
お断りします ! !
これらの行為は
厳正に対処します

お題②


Mistral-Small-3.1-24B-Instruct-2503

以下は画像から抽出されたテキストです。

---

**条項6**

ドライバーがネジを締めて、M.2 SSDカードを所定の位置に固定します。M.2 SSDカードを損傷する可能性があるため、ネジを締めすぎないようにしてください。M.2 SSDカードがタイプ2280の場合、手順6をスキップしてください。

gemma-3-27b-it

画像からテキストを抽出しました。以下に示します。

**手順6**

ドライバーでネジを締め、M.2 SSDカードを所定の位置に固定します。
M.2 SSDカードを損傷する可能性があるため、ネジを締めすぎないようにしてください。
M.2 SSDカードがタイプ2280の場合は、手順6をスキップしてください。

EasyOCR

手順6
ドライバーでネジを締めて MZSSD
カードを所定の位置に固定します
ML2SSDカードを損傷する可能性が
あるため ネジを締めすぎないように
してください。
M.2
SSD カードがタイプ2280 の場合
は 手順6をスキップしてください。

お題③


Mistral-Small-3.1-24B-Instruct-2503

この画像は、書籍の表紙です。以下にテキストを抽出します。

---

**ChatGPT/LangChainによるチャットシステム構築実践入門**

**吉田真吾、大嶋秀樹**

---

**大規模言語モデルを本番システムで活用するための基礎知識と実践ハンド**

---

**OpenAI API(ChatCompletions API)の利用**

**LLMのプロンプトエンジニアリングを理解し、LangChainの機能、詳細な説明**

**ソースコードをデプロイするためのSlackChatアプリ**

**本書の著者が実際に経験した課題と解決策**

---

**エンタープライズ**

---

この書籍は、ChatGPTやLangChainを用いたチャットシステムの構築に関する実践的なガイドです。大規模言語モデルを本番システムで活用するための基礎知識や実践的なハンドブックを提供しています。

gemma-3-27b-it

画像から以下のテキストを抽出しました。

**表紙のタイトル:**

*   ChatGPT / LangChain による チャットシステム構築[実践]入門

**著者:**

*   吉田英吾、大嶋勇樹 (著)

**キャッチコピー:**

*   本規模言語モデルを本番システムで活用するための基礎知識と実践的ハンズオン

**内容:**

*   OpenAI API (Chat Completions API) の活用
*   LLMを 待ったアプリ開発を支える LangChain の基本と実践的解説
*   ソースコードで学んで今日から使える Slack チャットアプリ
*   すべてクラウドに役立つ実例

EasyOCR

ChatGPTI
Langchain
による
チャットシステム構築[実銭 入門
吉田や
大.田樹衛
ChatGPT
大規模言語モデルを本番システムで活用する
ための基礁知識と実銭的ハンズオン
・r『nal
nttnhnon'nlsmn 山ド川=
川itっr ・つリy… iblonochiinniさと 4e 「いこrーピ
ー・フー‥こ・う-川 == …り-
トバー川
一沼言
aリ川ー  -こりう …川
ーーエ・ーウト川
にl川
だにン江

結果

今回の結果は「gemma-3-27b-it」の圧勝です。

Pythonスクリプト

Mistral-Small-3.1-24B-Instruct-2503

from transformers import BitsAndBytesConfig, AutoProcessor, AutoModelForImageTextToText, TextIteratorStreamer
import torch
import gradio as gr
from threading import Thread

model_checkpoint = "mistralai/Mistral-Small-3.1-24B-Instruct-2503"

quantization_config = BitsAndBytesConfig(load_in_4bit=True)

model = AutoModelForImageTextToText.from_pretrained(
    model_checkpoint,
    torch_dtype=torch.bfloat16,
    device_map="cuda",
    quantization_config=quantization_config
)

processor = AutoProcessor.from_pretrained(model_checkpoint)

streamer = TextIteratorStreamer(
    processor,
    skip_prompt=True,
    skip_special_tokens=True
)

def extract_text(filepath: str):

    messages = [
        {
            "role": "user",
            "content": [
                {"type": "image", "url": filepath},
                {"type": "text", "text": "この画像からテキストを抽出して下さい"},
            ],
        }
    ]

    inputs = processor.apply_chat_template(
        messages,
        add_generation_prompt=True,
        tokenize=True,
        return_dict=True,
        return_tensors="pt"
    ).to(model.device, dtype=torch.bfloat16)

    generation_kwargs = dict(
        **inputs,
        streamer=streamer,
        max_new_tokens=1024,
        do_sample=True,
        temperature=0.15,
        pad_token_id=2
    )

    thread = Thread(target=model.generate, kwargs=generation_kwargs)
    thread.start()

    result = ""
    for new_text in streamer:
        result += new_text
        yield result

with gr.Blocks() as demo:
    gr.Interface(
        fn=extract_text,
        inputs=gr.Image(type="filepath"),
        outputs=gr.Textbox(lines=10, max_lines=40, show_copy_button=True),
        flagging_mode="never"
    )

demo.launch()

gemma-3-27b-it

from transformers import BitsAndBytesConfig, AutoProcessor, Gemma3ForConditionalGeneration, TextIteratorStreamer
import torch
import gradio as gr
from threading import Thread
    
model_checkpoint = "google/gemma-3-27b-it"

quantization_config = BitsAndBytesConfig(load_in_4bit=True)

model = Gemma3ForConditionalGeneration.from_pretrained(
    model_checkpoint,
    torch_dtype=torch.bfloat16,
    device_map="cuda",
    quantization_config=quantization_config
)

processor = AutoProcessor.from_pretrained(model_checkpoint, use_fast=True)

streamer = TextIteratorStreamer(
    processor,
    skip_prompt=True,
    skip_special_tokens=True
)

def extract_text(filepath: str):

    messages = [
        {
            "role": "system",
            "content": [{"type": "text", "text": "あなたは優秀で誠実なAIアシスタントです。"}]
        },
        {
            "role": "user",
            "content": [
                {"type": "image", "image": filepath},
                {"type": "text", "text": "この画像からテキストを抽出して下さい"},
            ],
        }
    ]

    inputs = processor.apply_chat_template(
        messages,
        add_generation_prompt=True,
        tokenize=True,
        return_dict=True,
        return_tensors="pt"
    ).to(model.device, dtype=torch.bfloat16)

    generation_kwargs = dict(
        **inputs,
        streamer=streamer,
        max_new_tokens=1024,
        do_sample=True,
        top_k=64,
        top_p=0.95,
        temperature=0.15
    )

    thread = Thread(target=model.generate, kwargs=generation_kwargs)
    thread.start()

    result = ""
    for new_text in streamer:
        result += new_text
        yield result

with gr.Blocks() as demo:
    gr.Interface(
        fn=extract_text,
        inputs=gr.Image(type="filepath"),
        outputs=gr.Textbox(lines=10, max_lines=40, show_copy_button=True),
        flagging_mode="never"
    )

demo.launch()

EasyOCR

from PIL import ImageDraw
import easyocr
import numpy as np
import gradio as gr

reader = easyocr.Reader(['ja','en'])

def ocr(img):
    result = reader.readtext(np.array(img))
    draw = ImageDraw.Draw(img)
    result_text = []
    for each_result in result:
        draw.rectangle(tuple(each_result[0][0] + each_result[0][2]), outline=(0, 0, 255), width=3)
        result_text.append(each_result[1])
    return [img, "\n".join(result_text)]

with gr.Blocks() as demo:
    gr.Interface(
        fn=ocr,
        inputs=gr.Image(type="pil"),
        outputs=["image", gr.Textbox(lines=10, max_lines=40, show_copy_button=True)],
        flagging_mode="never"
    )

demo.launch()






以上の内容はhttps://touch-sp.hatenablog.com/entry/2025/03/21/235646より取得しました。
このページはhttp://font.textar.tv/のウェブフォントを使用してます

不具合報告/要望等はこちらへお願いします。
モバイルやる夫Viewer Ver0.14