PR

NovelAIの生成画像のメタデータを理解する【Python解説あり】

NovelAIの生成画像のメタデータを理解する【Pythonコードあり】
この記事は約19分で読めます。

以前の記事では画像ファイルの「メタデータ」について解説しました。

本記事では、この知識を踏まえて、NovelAIの生成画像のメタデータについてさらに深く理解していきましょう。

メタデータについて簡単におさらい

画像ファイルにおける「メタデータ」とは、画像データを説明するためのデータのことです。

画像ファイルには「メタデータ」を付与できる

特にNovelAIなどの画像生成AIのメタデータには、「プロンプト」や「シード値」「ステップ」などの画像生成時のパラメータ情報が含まれていることがあります。

PNGファイルにおけるデータ構造は、「シグネチャ」と複数の「チャンク」から成ります。

PNGファイルの全体的な構造

「チャンク」の中身がPNGファイルを理解するポイントになりますが、どのようなチャンクでも必ずこのような構成になっています。

名前サイズ説明
Length4byteChank Dataのサイズ
Chank Type4byteチャンクの種類
Chank Data0byte以上データ本体
CRC4byteエラー検出のための情報
「チャンク」の構成
[PNGファイル] チャンクの構造

NovelAIのPNG構造

以下の解説は2024年2月にNovelAIで生成した画像を前提としています。
それ以降にNovelAI側で仕様変更があった場合、付与されるメタデータも本記事の解説と異なる可能性があります。ご了承ください。

それでは、いよいよNovelAIのPNGファイルの構造を見てみましょう。
ファイルは次のような構造になっています。

NovelAIの生成画像(PNGファイル)の構造

「IDATチャンク」が「画像データ」です。
そして、その前の「tEXtチャンク」または「iTXtチャンク」にプロンプトなどのメタデータが格納されています。

らん
らん

「tEXt」とか「iTXt」ってどんなチャンクなの?

るん
るん

いずれも文字情報を格納するためのチャンクです

tEXtチャンク(テキストデータ)

文字情報が格納されるチャンクです。

[PNGファイル] tEXtチャンク

Chunk Dataはテキストデータなので基本的にはそのまま読み出せばいいのですが、このテキストデータは情報の種類を示す「キーワード」から始まることがポイントです。
その後、「ヌル文字」で区切られて「テキスト」が続きます。

キーワードには以下のものが事前定義されていますが、ここにないプライベートキーワード(1文字以上、80文字未満)を用いてもよいことになっています。

キーワード意味
Title画像の短い(1 行)タイトルまたはキャプション
Author画像の作成者の名前
Description画像の説明 (長い場合もあります)
Copyright著作権表示
Creation Time元画像の作成時間
Softwareイメージの作成に使用したソフトウェア
Disclaimer法的免責事項
Warningコンテンツの性質に関する警告
Sourceイメージの作成に使用されたソースデバイス
Commentその他のコメント
tEXtのキーワードの種類

そして重要なことですが、このテキストに格納できる文字は「Latin-1(ラテン1)」です。
「Latin-1(ラテン1)」は数字・記号・ラテンアルファベットが含まれますが、日本語は含まれません

つまり、もし日本語でプロンプトを書いていた場合、このtEXtチャンクにその情報を格納できないということです。

らん
らん

あ、でもNovelAIって日本語プロンプトには反応しないよね?

るん
るん

確かにそうなのですが…

NovelAIのプロンプトは日本語に反応しないので英語で書くことが基本です。
ですので、プロンプトに日本語が入っているケースは少ないとは思いますが…可能性はあります。

このように「Latin-1」以外の文字も扱う必要があるときには「iTXtチャンク」を使います。

iTXtチャンク(国際テキストデータ)

iTXtチャンクは意味合いとしてはtEXtチャンクと同じですが、UTF-8の文字を格納することができます。つまり、日本語もOKということです。

ですが、チャンクの構造はtEXtよりもちょっとだけ複雑です。
詳しくはこちらの仕様をご覧ください。

[PNGファイル] iTXtチャンク

では、この2つのチャンクに着目して、Pythonで実装しながらひとつずつ見ていきましょう。

Pythonでメタデータを読み出してみよう

こちらの記事で解説したコードを再掲します。
pngファイルのメタデータを読み出すコードです。

with open("kimono-girl.png", "rb") as bin:
    # 最初の8バイトはPNGであることのシグネチャ(89 50 4E 47 0D 0A 1A 0A)
    signature = bin.read(8)

    # チャンクの読み出し
    while True:
        # Length データのサイズ
        data_len_b = bin.read(4)
        data_len = int.from_bytes(data_len_b, "big")

        # Chunk Type チャンクの種類
        chunk_type_b = bin.read(4)
        chunk_type = chunk_type_b.decode()

        print(f"{chunk_type} : {data_len} byte")

        # Chunk Data データ
        data_b = bin.read(data_len)
        if chunk_type == "tEXt":
            data = data_b.decode()
            print(data.split("\0"))
        elif chunk_type == "iTXt":
            data = data_b.decode()

            print(data.split("\0"))

        # CRC
        crc_b = bin.read(4)

        if chunk_type == "IEND":
            break

英語プロンプトの画像

では、まずは「英語のプロンプト」で生成したこの画像を使います。

プロンプト

girl, blonde hair, smile, kimono, upper body, profile, watercolor (medium),

PNG構造を理解するための画像ファイル

whileループを回しながらチャンクをひとつずつ読み出していきます。

NovelAIの場合、「tEXt」または「iTXt」チャンクにメタデータが含まれているので、チャンクタイプがこのいずれかの場合に中身を表示させます。

実行結果がこちらです。

IHDR : 13 byte
tEXt : 24 byte
['Title', 'AI generated image']
tEXt : 146 byte
['Description', 'girl, blonde hair, smile, kimono, upper body, profile, watercolor (medium), , best quality, amazing quality, very aesthetic, absurdres']
tEXt : 16 byte
['Software', 'NovelAI']
tEXt : 35 byte
['Source', 'Stable Diffusion XL C1E1DE52']
tEXt : 32 byte
['Generation time', '4.84797209315002']
tEXt : 1429 byte
['Comment', '{"prompt": "girl, blonde hair, smile, kimono, upper body, profile, watercolor (medium), , best quality, amazing quality, very aesthetic, absurdres", "steps": 28, "height": 640, "width": 640, "scale": 5.0, "uncond_scale": 1.0, "cfg_rescale": 0.0, "seed": 1534611758, "n_samples": 1, "hide_debug_overlay": false, "noise_schedule": "native", "legacy_v3_extend": false, "sampler": "k_euler", "controlnet_strength": 1.0, "controlnet_model": null, "dynamic_thresholding": false, "dynamic_thresholding_percentile": 0.999, "dynamic_thresholding_mimic_scale": 10.0, "sm": false, "sm_dyn": false, "skip_cfg_below_sigma": 0.0, "lora_unet_weights": null, "lora_clip_weights": null, "uc": "nsfw, lowres, {bad}, error, fewer, extra, missing, worst quality, jpeg artifacts, bad quality, watermark, unfinished, displeasing, chromatic aberration, signature, extra digits, artistic error, username, scan, [abstract], bad anatomy, bad hands, @_@, mismatched pupils, heart-shaped pupils, glowing eyes, lowres, bad anatomy, bad hands, text, error, missing fingers, extra digit, fewer digits, huge breasts,worst quality, low quality, normal quality, jpeg artifacts, signature, watermark, username, blurry, missing fingers, bad hands, missing arms, long neck, Humpbacked, shadow, huge breasts, ", "request_type": "PromptGenerateRequest", "signed_hash": "2YV+AgiVe6tOOGt35NslOLkk4JirTLL9zfKsCGR8BK2UfitQB0Spm7lVdh3rLzPkN13ZWKwyYzL4X5tdRzymCg=="}']
IDAT : 65536 byte
IDAT : 65536 byte
IDAT : 65536 byte
IDAT : 65536 byte
IDAT : 65536 byte
IDAT : 65536 byte
IDAT : 65536 byte
IDAT : 65536 byte
IDAT : 65536 byte
IDAT : 38355 byte
IEND : 0 byte

6つのtEXtチャンクにメタデータが格納されていますね。
1つずつ順番に見てみましょう。

1つめのチャンク

[‘Title’, ‘AI generated image’]

1つめのtEXTチャンクにはAIの生成画像だということが「Title」として格納されています。

2つめのチャンク

[‘Description’, ‘girl, blonde hair, smile, kimono, upper body, profile, watercolor (medium), , best quality, amazing quality, very aesthetic, absurdres’]

「Description」として、「プロンプト」が格納されています。
注目したいのは「品質タグ有効」の設定にしていたため、自動で品質タグ(best quality, amazing quality, very aesthetic, absurdres)が付けられているということです。

3つめのチャンク

[‘Software’, ‘NovelAI’]

NovelAIを使って作られた画像だということが「Software」キーワードとして格納されています。

4つめのチャンク

[‘Source’, ‘Stable Diffusion XL C1E1DE52’]

この「Source」がNovelAIのモデルを表しているようです。正確な仕様は公表されていないようですが、私が実際の生成画像を使って調べた限りでは以下のような対応のようです。

テキストモデル
Stable Diffusion XL C1E1DE52NAI Diffusion Anime V3
Stable Diffusion F1022D28NAI Diffusion Anime V2
Stable Diffusion 3B3287AFNAI Diffusion Anime V1 (Full)
Stable Diffusion F4D50568NAI Diffusion Anime V1 (Curated)
Stable Diffusion F64BA557NAI Diffusion Furry (Beta V1.3)
SourceとNovelAIのモデルとの対応関係
5つめのチャンク

[‘Generation time’, ‘4.84797209315002’]

「Generation time」として画像の生成時間が格納されています。

るん
るん

「Generation time」というのはNovelAIオリジナルのキーワードだと思われます

6つめのチャンク

[‘Comment’, ‘{“prompt”: “girl, blonde hair, smile, kimono, upper body, profile, watercolor (medium), , best quality, amazing quality, very aesthetic, absurdres”, “steps”: 28, “height”: 640, “width”: 640, “scale”: 5.0, “uncond_scale”: 1.0, “cfg_rescale”: 0.0, “seed”: 1534611758, “n_samples”: 1, “hide_debug_overlay”: false, “noise_schedule”: “native”, “legacy_v3_extend”: false, “sampler”: “k_euler”, “controlnet_strength”: 1.0, “controlnet_model”: null, “dynamic_thresholding”: false, “dynamic_thresholding_percentile”: 0.999, “dynamic_thresholding_mimic_scale”: 10.0, “sm”: false, “sm_dyn”: false, “skip_cfg_below_sigma”: 0.0, “lora_unet_weights”: null, “lora_clip_weights”: null, “uc”: “nsfw, lowres, {bad}, error, fewer, extra, missing, worst quality, jpeg artifacts, bad quality, watermark, unfinished, displeasing, chromatic aberration, signature, extra digits, artistic error, username, scan, [abstract], bad anatomy, bad hands, @_@, mismatched pupils, heart-shaped pupils, glowing eyes, lowres, bad anatomy, bad hands, text, error, missing fingers, extra digit, fewer digits, huge breasts,worst quality, low quality, normal quality, jpeg artifacts, signature, watermark, username, blurry, missing fingers, bad hands, missing arms, long neck, Humpbacked, shadow, huge breasts, “, “request_type”: “PromptGenerateRequest”, “signed_hash”: “2YV+AgiVe6tOOGt35NslOLkk4JirTLL9zfKsCGR8BK2UfitQB0Spm7lVdh3rLzPkN13ZWKwyYzL4X5tdRzymCg==”}’]

この「Comment」のチャンクには、NovelAIの画像生成パラメータがほぼ盛り込まれているようです。

  • プロンプト(prompt)
  • 除外したい要素(uc)
  • 画像の幅(width)
  • 画像の高さ(height)
  • シード値(seed)
  • ステップ(steps)
  • サンプラー(sampler)
  • プロンプトを反映する正確度(scale)
  • 除外したい要素の強さ(uncond_scale)
  • 同時生成数(n_samples)
  • i2iの強度(strength)
  • i2iのノイズ(noise)
  • Txt2ImgかImg2Imgか(request_type)

この画像は英語のプロンプトだったので「iTXt」チャンクの出番はありませんでした。
では次は、日本語プロンプトで生成した画像について見てみましょう💡

日本語プロンプトの画像

こちらの画像を使ってみましょう。以下の日本語プロンプトで生成した画像です。

プロンプト

女性、着物、黒髪、桜

PNG構造を理解するための画像ファイル(日本語プロンプト)
IHDR : 13 byte
tEXt : 24 byte
['Title', 'AI generated image']
iTXt : 104 byte
['Description', '', '', '', '', '女性、着物、黒髪、桜, best quality, amazing quality, very aesthetic, absurdres']
tEXt : 16 byte
['Software', 'NovelAI']
tEXt : 35 byte
['Source', 'Stable Diffusion XL C1E1DE52']
tEXt : 33 byte
['Generation time', '4.244049072731286']
tEXt : 1413 byte
['Comment', '{"prompt": "\\u5973\\u6027\\u3001\\u7740\\u7269\\u3001\\u9ed2\\u9aea\\u3001\\u685c, best quality, amazing quality, very aesthetic, absurdres", "steps": 28, "height": 640, "width": 640, "scale": 5.0, "uncond_scale": 1.0, "cfg_rescale": 0.0, "seed": 1598853643, "n_samples": 1, "hide_debug_overlay": false, "noise_schedule": "native", "legacy_v3_extend": false, "sampler": "k_euler", "controlnet_strength": 1.0, "controlnet_model": null, "dynamic_thresholding": false, "dynamic_thresholding_percentile": 0.999, "dynamic_thresholding_mimic_scale": 10.0, "sm": false, "sm_dyn": false, "skip_cfg_below_sigma": 0.0, "lora_unet_weights": null, "lora_clip_weights": null, "uc": "nsfw, lowres, {bad}, error, fewer, extra, missing, worst quality, jpeg artifacts, bad quality, watermark, unfinished, displeasing, chromatic aberration, signature, extra digits, artistic error, username, scan, [abstract], bad anatomy, bad hands, @_@, mismatched pupils, heart-shaped pupils, glowing eyes, lowres, bad anatomy, bad hands, text, error, missing fingers, extra digit, fewer digits, huge breasts,worst quality, low quality, normal quality, jpeg artifacts, signature, watermark, username, blurry, missing fingers, bad hands, missing arms, long neck, Humpbacked, shadow, huge breasts, ", "request_type": "PromptGenerateRequest", "signed_hash": "cOOKxXryxkWfIuRXOcmpFj5bRLVWuPilpURZYEwMhU1FZyt+QHeTcrlWCsEoApCjEY0OkZybO1+K3zYlrYlpAw=="}']
IDAT : 65536 byte
IDAT : 65536 byte
IDAT : 65536 byte
IDAT : 65536 byte
IDAT : 65536 byte
IDAT : 65536 byte
IDAT : 65536 byte
IDAT : 65536 byte
IDAT : 65536 byte
IDAT : 9088 byte
IEND : 0 byte

6つのチャンクにメタデータが格納されている点は、英語プロンプトのときと同じです。
差異があるチャンクに注目してみましょう。

2つめのチャンク

[‘Description’, ”, ”, ”, ”, ‘女性、着物、黒髪、桜, best quality, amazing quality, very aesthetic, absurdres’]

2つめのチャンクにはプロンプトが格納されていますが、日本語プロンプトの場合は「tEXt」ではなく「iTXt」チャンクになっています。

このチャンクをバイナリで確認すると次のようにヌル文字が5つ連続しています。
区切りのヌル文字は仕様上は3つのはずなのですが…謎です💦

Description\x00\x00\x00\x00\x00\xe5\xa5\xb3\xe6\x80\xa7...
6つめのチャンク

[‘Comment’, ‘{“prompt”: “\\u5973\\u6027\\u3001\\u7740\\u7269\\u3001\\u9ed2\\u9aea\\u3001\\u685c, best quality, amazin…(以下省略)]

そして、最後6つめのチャンクです。ここにもプロンプト(日本語)が格納されるのでiTXtチャンクになるのかと思いきや、実際にはtEXtチャンクになっています。そして、日本語プロンプトがそのまま格納されているようです。

るん
るん

tEXtチャンクは「Latin-1」の文字しか使えないので、これは仕様から外れている気がします…

まとめ

NovelAIの生成画像では「プロンプト」などのメタデータが6つのチャンクに格納されています。

チャンクタイプキーワード内容
tEXtTitle固定文字列(AI generated image)
tEXtまたはiTXtDescriptionプロンプト
tEXtSoftware固定文字列(NovelAI)
tEXtSourceモデル
tEXtGeneration生成時間
tEXtCommentすべてのパラメータ情報
NovelAIの生成画像のチャンク

Pythonなどでこれらのデータを読み出すことができます。

プロフィール
この記事を書いた人
千鳥 るん | Chidori Run

画像生成AIで思い通りのイラストを描くためのノウハウを試行錯誤で模索しています。IT企業でAI戦略に関わっていたこともあるAIエンジニアです。大学生の頃から趣味でイラストを描いていましたが、仕事が忙しくなり一旦筆を置きました。最近、NovelAIと出会ってまたお絵描きへの情熱を取り戻しています。

千鳥るんをフォローする
NovelAIプログラミング
スポンサーリンク
シェアする
千鳥るんをフォローする

コメント