画像認識が向上した ChatGPT-4o を超えたと言われるClaude 3.5 Sonnetで名刺を読み取る

画像認識が大幅に向上したと言われるChatGPT-4oを超えたと言われるClaude 3.5 Sonnet で名刺を読み取ってデータ化したいと思います。

内容は、「[画像認識が向上した ChatGPT-4o で名刺を読み取る](https://qiita.com/kanekoyuichi/items/f3c993ae5d4ceaf21de2)」と同じ内容を読み取っています。

https://qiita.com/kanekoyuichi/items/f3c993ae5d4ceaf21de2

GPT-4oでもかなり正確に名刺情報を読み込んでほぼ正しく会社名や部署名、役職などを読み取って構造化してくれましたが、同様にClaude 3.5 Sonnet でも同じようにできるか比較検証してみます。

APIでClaude3.5に名刺画像を渡して、画像を認識してもらいまます。画像をAPIで渡すには、ChatGPT-4oと同じくBase64でエンコードして渡します。

ChatGPT-4oと比較するために、APIで投げるプロンプトは[前回](https://qiita.com/kanekoyuichi/items/f3c993ae5d4ceaf21de2)と同じものにしました。

JSONで書き出すため、systemには「The response should be output in JSON format.」と記載してあります。

また読み取った文字を構造化するために、userのcontentsには、「この名刺の画像から「氏名」、「会社名」、「住所」、「郵便番号」、「電話番号」、「FAX番号」、「メールアドレス」、「部署名」、「役職・肩書」、「URL」を読み取ってください。複数ある場合はそれらを「,」でつないで入れてください。画像が名刺じゃない場合はErrorを返してください。」としています。

Pythonでは、anthropicのライブラリが用意されていますので、それを使います。

```Python:read_card.py
import anthropic
import base64
import argparse

API_KEY = '<YOUR-API-KEY>'

def encode_image(image_path):
  with open(image_path, 'rb') as image_file:
    return base64.b64encode(image_file.read()).decode('utf-8')

def main(args: argparse.Namespace):
    
    image_path = args.target
    client = anthropic.Client(api_key=API_KEY)
    
    message = client.messages.create(
        model = "claude-3-5-sonnet-20240620",
        max_tokens = 1024,
        temperature = 0,
        messages = [
            {
                "role": "user",
                "content": [
                    {
                        "type": "image",
                        "source": {
                            "type": "base64",
                            "media_type": "image/jpeg",
                            "data": encode_image(image_path)
                        }
                    },
                    {
                        "type": "text",
                        "text": "この名刺の画像から「氏名」、「会社名」、「住所」、「郵便番号」、「電話番号」、「FAX番号」、「メールアドレス」、「部署名」、「役職・肩書」、「URL」を読み取ってください。複数ある場合はそれらを「,」でつないで入れてください。画像が名刺じゃない場合はErrorを返してください。"
                    }
                ]
            }
        ],
        system = "You are an Optical Character Recognition (OCR) machine. You will extract all the characters from the image file provided by the user, and you will only privide the extracted text in your response. As an OCR machine, You can only respond with the extracted text.The response should be output in JSON format.",
    )
    
    return message.content[0].text
    
if __name__ == '__main__':
    
    parser = argparse.ArgumentParser()
    parser.add_argument('target', type=str, help='target image')
    args = parser.parse_args()

    print(main(args))    
```
書き方はChatGPT-4oとほぼ同じですね。エラー処理は省いていますので、必要に応じてエラー処理などは入れてください。

また、読み込ませる名刺もChatGPT-4oと比較するために、[前回](https://qiita.com/kanekoyuichi/items/f3c993ae5d4ceaf21de2)作成した手作りのダミーの名刺画像を使いました。

![sample_card.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/191954/70d56f0b-aa7e-8ed4-f032-346ac3142003.jpeg)

実行プログラムと同じディレクトリに画像をおいて、実行します。
```bash
$ python3 read_card.py sample_card.jpg
```
実行結果がJSONで返ってきます。住所やメールアドレスが名刺とは違っています。ぼやけた画像を使ったことが影響しているのかもしれませんが、100%正しく読み取ったとは言えませんでした。
```json:Claude 3.5 Sonnetでの名刺の読み取り結果
{
  "氏名": "名刺 太郎",
  "会社名": "株式会社名刺サンプル",
  "住所": "東京都品川区千代田1丁目2番3号千代田ビル5階",
  "郵便番号": "123-4567",
  "電話番号": "03-1234-5677",
  "FAX番号": "03-1234-5678",
  "メールアドレス": "taro-meishi@example.com",
  "部署名": "営業部営業2課",
  "役職・肩書": "課長",
  "URL": "https://example.com"
}
```
参考までに下記はChatGPT-4oで読み取った場合の結果です。微妙に違いますね。ChatGPT-4oはほぼ正しいですが、URLがhttpになっています（正しくはhttps）。
```json:ChatGTP-4oでの名刺の読み取り結果
{
  "氏名": "名刺 太郎",
  "会社名": "株式会社名刺サンプル",
  "住所": "東京都品川区千代田1-2-3千代田ビル5階",
  "郵便番号": "123-4567",
  "電話番号": "03-1234-5677",
  "FAX番号": "03-1234-5678",
  "メールアドレス": "taro.meishi@example.com",
  "部署名": "営業部営業2課",
  "役職・肩書": "課長",
  "URL": "http://example.com"
}
```
今回のデモ用の名刺画像ではそこまで差がなく、違いを評価しにくい微妙な結果でしたが、より複雑な名刺を利用すると違いが出てくるかもしれません。