Pythonを使ってRGB値のデータから色画像を自動作成〜自宅でできる簡単な研究(FR-4.2)

 Pythonを使ってcsvファイルに記入したR,G,Bの数値データから、モニターに色を出力するプログラムを作成してみました。「2種類の食紅水溶液を混ぜた時の色を予測してみました」で1つのR,G,Bの数値データーを画面に出力する方法を紹介しました。多くのR,G,Bの数値データーを、効率よく出力する時に便利なPythonによる自動化のプログラム作成を検討したので紹介します。
 Pythonのプログラミングは初心者のため、生成AI(EdgeのBing)に質問して、得られたプログラムを参考にプログラムを作成しました。

考え方と目次

考え方
 何かの役には立たないし、人から見たらどうでも良いことで自己満足の世界でありますが、個人研究として取り組んでいます。

目次
 1. 酸性・アルカリ性の指示薬の色変化画像
 2. Pillowモジュールのインストール
 3. Bing AIにPythonプログラムを質問
 4. 画像データーは、csv形式のファイルを使用
 5. 色画像を作成をするプログラムの検討
 6. 完成したプログラム

1. 酸性・アルカリ性の指示薬の色変化画像
 下の写真の左側は、酸性・アルカリ性の指示薬として、市販でも購入可能な「ブロモチモールブルー(BTB)」と「フェノールフタレイン(PP)」のpHによる色の変化の画像をPythonで作成しました。R,G,Bの数値データーは、pH指示薬の変色域,色見本とRGB値(埼玉大学)を利用させていただきました。
 また、写真の右は「紫キャベツと巨峰を使った酸性とアルカリ性による色の変化について」で使用したpH標準液にブロモチモールブルー(BTB)とフェノールフタレイン(PP)をそれぞれ反応させた時の色を示しています。

 ブロモチモールブルー(BTB)試薬は、中性付近の弱酸や塩基の検出に用いられます。変色範囲(pH)は、(黄)6.0-7.6(青)で中性は緑色、酸性は黄色、塩基性は青色になる指示薬です。
 フェノールフタレイン(PP)試薬は、pH7までは無色ですが、pH8を超えると赤みを帯び始めます。変色域は 8.0- 9.8で透明から赤みを帯びるアルカリ性の変化が分かる指示薬です。

2. Pillowモジュールのインストール
 今回は、画像に関するさまざま処理を行う事が出来るPillowモジュールをインストールして使いました。
 「PillowはPython Image Library(PIL:Python画像ライブラリ)から派生したライブラリで、画像のサイズ変更やトリミング、輝度やコントラストの変更など画像に関するさまざま処理を行うことができます。PILを元に作られているライブラリなので、Pillowモジュールを利用する場合はPILという名前を使用します」と説明されています。
 環境によってはインストール済みの場合もありますが、インストールされていない場合はpipコマンドを利用してPillowのインストールを行います。

3. Bing AIにPythonプログラムを質問
 Pythonの標準ライブラリーを使用して、「生成AIで作ったPythonプログラムで、数値化した画像の解析を自動化」の時と同じ様に、Bing AIで質問をしてPythonプログラムの骨格を作りました。
 質問は、
 (A)「pythonの標準ライブラリのみを使用して画像処理するプログラムで、RGBの数値から色を作成し、png形式のファイルに保存するプログラムを教えて」
 (B)「pythonの標準ライブラリのみを使用してcsvファイル’RGB.csv’のi行目から最後まで、2列目の値をR、3列目の値をG、4列目の値をBとし、さらにR, G, Bを整数とするプログラムを教えて」

 (C)「Pythonの画像処理ライブラリPillow(PIL)を用いて画像上にcsvファイルの4列目の文字(テキスト)を順番に描画する方法についてお教えて」
 (D)「pythonで、PILライブラリーを使ってn個のファイルを左から順番にペースとして1つのファイルに保存するプログラムを教えて」

です。これらを基に試行錯誤してプログラムを作成しました。

4. 画像データーは、csv形式のファイルを使用
 作成する画像のデーターは、csv形式のファイルに記入してデーターを読み込むことにしました。
 csvファイルは、下の写真の様な形式です。左はBTBで、右がPPのcsvファイルです。
 1列目は、自然数になります。作成した画像の番号付けに使われます。
 2, 3, 4列目は、それぞれR, G, Bの透過光(反射光)の数値データーです。
 5列目は、テキストのデーターになります。
 表計算ソフトでデーターを作成し、csv形式で書き出すと良いと思います。

5. 色画像を作成をするプログラムの検討
 最初に写真の画像を作成するプログラムは、まずcsvファイルの1〜9の色を100×100ピクセルのpng形式のファイルにし、テキストデーターを書き込みます(下の写真)。

 プログラムを動かすためにまず6行目にcsvファイルの名前を書き込みます(ここでは、CSV_BTB)。画像のデータファイルを保存するフォルダーが同じ名前で作られます(7行目)。
 10〜20行でcsvファイルのデーターを読み込んで、100×100ピクセルの色の画像を作成します。
 21〜28行で色の画像にテキストを書き込みます。22, 23行でテキストの位置を決め、26行でフォント、28行でテキストの色を決めます(ここでは、0, 0, 0:黒)。
 31行で保存するファイルの名前を指定し(ここでは、color_N.png:Nは、1〜9の数字)png形式のファイルとして保存しすます。
 32行でフォルダー(ここでは、CSV_BTBフォルダー)へ移動してまとめます。

 次からは、それぞれ作成した色の画像を左から番号順に並べるプログラムです(下の写真)。

 35〜37行で背景の画像を作成します。ここでは、100×100ピクセルの黒の画像ファイルを’color_0’という名前で保存します。
 39行で画像ファイルの数(ここでは、9)を指定して、背景の画像サイズを(幅100×9ピクセル, 高さ100ピクセル)設定します。
 44〜60行で、左から番号順に背景にペーストしてファイル(CSV_BTB.png)を保存します(CSV_BTBフォルダー内へ保存したければ59行を使用)。
 55行で、color_1〜9のファイルを90×90ピクセルにしてスペースを作ります。
 56行で、背景の左と上から5ピクセル開ける設定にしました。
 62行で結果のファイルを表示します。

6. 完成したプログラム
 Pythonのプログラムは、以下となります。

import csv
from PIL import Image, ImageDraw, ImageFont
import shutil
import os

ymd = 'CSV_PP' #ファイルを保存するフォルダー名
os.makedirs(ymd, exist_ok=True) #フォルダーを作る

#csvファイルからデーターを読み込む
with open(ymd + '.csv', 'r') as file:
    reader = csv.reader(file)
    rows = [row for i, row in enumerate(reader) if i >= 1]
    for row in rows:
        N, R, G, B, text = row[0], row[1], row[2], row[3], row[4]        
        print(f"{N}, R: {R}, G: {G}, B: {B}, text: {text}") #読み込んだデーターを表示

        # RGBの数値から色を作成
        color = (round(float(R)), round(float(G)), round(float(B))) 
        img = Image.new('RGB', (100, 100), color) #100x100ピクセル
        
        # テキストを入れる位置を決める
        x = 20
        y = 70

        # 文字列を描画
        font = ImageFont.truetype('Arial.ttf', 18) #フォントを指定
        draw = ImageDraw.Draw(img)
        draw.text((x, y), text,(0, 0, 0), font=font) #()は、fontの色


        img.save('color_' + N + '.png', 'png') # png形式のファイルに保存  
        shutil.move('color_' + N + '.png', ymd + '/' + 'color_' + N + '.png') #ファイルを移動する

#背景の画像を作成する
color = (0, 0, 0) # RGBの数値から色を作成
img0 = Image.new('RGB', (100, 100), color)
img0.save(ymd + '/color_0.png') # png形式のファイルに保存

n = int(N) # 画像の数
im1 = Image.open(ymd + '/color_0.png')
width, height = im1.width * n, im1.height # 黒のベースとなる画像のサイズ

# 作成した画像を左から順番にペーストして保存
for i in range(n + 1):
    # 画像を開く
    img = Image.open(f'{ymd}/color_{i}.png') # file No.1から

    # 画像をリサイズ
    img = img.resize((width, height))

    if i == 0:
        result = img # べースの黒を作成
        
    else:
        img = img.resize((int(im1.width * 0.9), int(height * 0.9))) # サイズを0.9倍(90ピクセル)
        result.paste(img, (im1.width * (i -1) + 5, 5)) # 左と上から5ピクセル開けてペースト

    # 画像を保存
    #result.save(f'{ymd}/{ymd}.png')
    result.save(f'{ymd}.png')

result.show('result.png') # ファイルを見せる
print('>>>>> 終了 <<<<<')