【python】画像データをmatplotlibでRGB値のヒストグラムにしてグラフ表示する

デジカメで撮った写真をRGB値を調べたくなることはないでしょうか。
先日、画像からRGB値のデータ化したり、逆に戻したりをしました。
今回はmatplotlibモジュールを使います。
RGB値のヒストグラムにしてグラフ表示して、視覚的に分析しやすくするところまでやってみたいと思います。

せっかくですので、画像を読み込んでRGB値に変換する際に、numpyモジュールで別のアプローチをしたいと思います。
解釈がしづらいですが、こちらの方がスマートに記述できます。

やること1
・画像を読み込んでRGB値に変換する
・ヒストグラムにする
・グラフ表示する
・RGB値をテキスト出力する

やること2
・RGB値を読み込んで画像に変換する

それでは順番に見ていきましょう!

目次

やること1

最終的に次のようにグラフ表示したいと思います。
上段に元画像、下段にヒストグラム。
ヒストグラムはRGBに分けてそれぞれグラフ表示します。

サンプル画像はこちらのサイトからお借りしました。フリーの画像素材を提供してくださっています。
いつもお世話になっております。

画像を読み込んでRGB値に変換する

今回使用するモジュールをインストールします。
どちらも少し時間が掛かるかもしれません。

pip install opencv-python
pip install matplotlib

まずは画像を読み込んでRGB値のリストとして取り込みます。

import cv2
import numpy as np

# 画像を読み込む
image = cv2.imread(image_path)

# R、G、Bそれぞれの値をリストに格納
r_values = image[:, :, 2].flatten()
g_values = image[:, :, 1].flatten()
b_values = image[:, :, 0].flatten()

画像の扱いにOpenCVモジュールを使いました。
Numpyモジュールだとこれだけでデータ変換完了です。
とてもシンプルになりました。

flatten()で一次元のデータとして取り出しています。
ヒストグラムにするのに都合が良いためです。

ヒストグラムにする

次の手順でmatplotlibでグラフ表示します。
・グラフデータを作成する
・グラフ表示する。

それではヒストグラムでにグラフデータを作成していきましょう。

import matplotlib.pyplot as plt

def plot_histogram(values, color_name):
    plt.hist(values, bins=256, range=(0, 256), color=color_name, alpha=0.7)
    plt.title(f'{color_name.upper()} Histogram')
    plt.xlabel('Value')
    plt.ylabel('Frequency')
    plt.grid(True)

plot_histogram(r_values, 'red')

RGBそれぞれ実行したいので関数化しています。def ~がそうです。
r_valuesは先ほど抽出したRed値のリストです。

グラフ表示する

最後にグラフ表示部分です。

import cv2
import matplotlib.pyplot as plt

# ヒストグラムを1つのプロットにまとめて表示
plt.figure(figsize=(12, 6))

# plt.subplot(rows, columns, index)
plt.subplot(2, 3, 2)
plt.imshow(cv2.cvtColor(cv2.imread(image_path), cv2.COLOR_BGR2RGB))
plt.title('Original Image')
plt.axis('off')

plt.subplot(2, 3, 4)
plot_histogram(r_values, 'red')

plt.subplot(2, 3, 5)
plot_histogram(g_values, 'green')

plt.subplot(2, 3, 6)
plot_histogram(b_values, 'blue')

plt.tight_layout()
plt.show()

subplotを使い、行列でグラフ位置を指定しています。
plt.subplot(2, 3, 2)は2行3列のグラフで、2番目の位置に指定する、という意味です。
この例だと、1~3が上段で、4~6が下段です。
最後にplt.show()で表示させています。

これらを実行すると、冒頭に示したグラフ表示になります。
後述のサンプルコードのところで再掲します。

RGB値をテキスト出力する

今回の目的に対して補助的になりますが、RGB値をテキスト出力したいと思います。

def save_to_txt(data, filename):
    with open(filename, 'w') as file:
        for value in data:
            file.write(str(value) + '\n')

テキスト出力です。
特に追加モジュールは必要ありません。
1行1データで出力します。


jpgを出力すると、結構なサイズになります。
今回のサンプルで約8MB×3色分です。
オリジナル画像が532kBですので、いかにjpgの効率が優れているか!素晴らしいですね。

やること2

RGB値を読み込んで画像に変換する

こちらも、目的に対して補助的になります。
RGB値を読み込んで画像に変換します。

検算にもなりますので、やってみたいと思います。

ここまでの解説で触れませんでしたが、
一次元のRGBデータを画像に戻すには、幅や高さデータが必要です。
サンプルコードでは、あらかじめ「image_size.txt」として出力しています。

この「image_size.txt」に記載された幅と高さデータをもとに、
「r_values.txt」などを読み込み、
画像データに戻していきます。

import numpy as np

def load_image_from_txt(image_path):
    # 画像サイズの読み込み
    with open('image_size.txt', 'r') as file:
        height = int(file.readline().split(':')[1])
        width = int(file.readline().split(':')[1])

    # R、G、Bそれぞれの値を読み込み
    r_values = np.loadtxt('r_values.txt', dtype=np.uint8)
    g_values = np.loadtxt('g_values.txt', dtype=np.uint8)
    b_values = np.loadtxt('b_values.txt', dtype=np.uint8)

    # 画像を復元, BGR
    image = np.zeros((height, width, 3), dtype=np.uint8)
    image[:, :, 2] = r_values.reshape((height, width))
    image[:, :, 1] = g_values.reshape((height, width))
    image[:, :, 0] = b_values.reshape((height, width))

    return image

テキストの扱いには、特に追加モジュールは必要ありません。
データの扱いにnumpyモジュールを利用しています。
関数だけの登場なので、そういうものか~という感じですが、
これでimageデータに復元しています。

サンプルコード

サンプルコードその1

やること1で紹介したコードをまとめたサンプルコードがこちらです。

ファイル構成は次の想定です。
RGBデータと幅高さデータを出力します。

sample.py (実行ファイル)
example.jpg (読み込み対象)
image_size.txt (幅と高さデータ(実行結果))
r_values.txt (Redデータ(実行結果))
g_values.txt (Greenデータ(実行結果))
b_values.txt (Blueデータ(実行結果))

実行ファイルの記述は下記のとおりです。

import cv2
import numpy as np
import matplotlib.pyplot as plt

def image_to_rgb_lists(image_path):
    # 画像を読み込む
    image = cv2.imread(image_path)

    # 画像の高さと幅を取得
    height, width, _ = image.shape

    # R、G、Bそれぞれの値をリストに格納
    r_values = image[:, :, 2].flatten()
    g_values = image[:, :, 1].flatten()
    b_values = image[:, :, 0].flatten()

    return height, width, r_values, g_values, b_values

def save_to_txt(data, filename):
    with open(filename, 'w') as file:
        for value in data:
            file.write(str(value) + '\n')

def plot_histogram(values, color_name):
    plt.hist(values, bins=256, range=(0, 256), color=color_name, alpha=0.7)
    plt.title(f'{color_name.upper()} Histogram')
    plt.xlabel('Value')
    plt.ylabel('Frequency')
    plt.grid(True)

# 画像ファイルのパスを指定してRGBデータと画像のサイズを取得
image_path = 'example.jpg'  # 画像ファイルのパスを適切に指定してください
height, width, r_values, g_values, b_values = image_to_rgb_lists(image_path)


# ヒストグラムを1つのプロットにまとめて表示
plt.figure(figsize=(12, 6))

# plt.subplot(rows, columns, index)
plt.subplot(2, 3, 2)
plt.imshow(cv2.cvtColor(cv2.imread(image_path), cv2.COLOR_BGR2RGB))
plt.title('Original Image')
plt.axis('off')

plt.subplot(2, 3, 4)
plot_histogram(r_values, 'red')

plt.subplot(2, 3, 5)
plot_histogram(g_values, 'green')

plt.subplot(2, 3, 6)
plot_histogram(b_values, 'blue')

plt.tight_layout()
plt.show()


# 画像のサイズとRGB値をテキストファイルに出力
with open('image_size.txt', 'w') as file:
    file.write(f'Height: {height}\n')
    file.write(f'Width: {width}\n')
save_to_txt(r_values, 'r_values.txt')
save_to_txt(g_values, 'g_values.txt')
save_to_txt(b_values, 'b_values.txt')

実行した結果がこのようになります。

サンプルコードその2

ファイル構成は上記と同様で、次のファイルを出力します。

sample2.py
restored_image.jpg
import cv2
import numpy as np

def load_image_from_txt(image_path):
    # 画像サイズの読み込み
    with open('image_size.txt', 'r') as file:
        height = int(file.readline().split(':')[1])
        width = int(file.readline().split(':')[1])

    # R、G、Bそれぞれの値を読み込み
    r_values = np.loadtxt('r_values.txt', dtype=np.uint8)
    g_values = np.loadtxt('g_values.txt', dtype=np.uint8)
    b_values = np.loadtxt('b_values.txt', dtype=np.uint8)

    # 画像を復元, BGR
    image = np.zeros((height, width, 3), dtype=np.uint8)
    image[:, :, 2] = r_values.reshape((height, width))
    image[:, :, 1] = g_values.reshape((height, width))
    image[:, :, 0] = b_values.reshape((height, width))

    return image

def save_image(image, filename):
    cv2.imwrite(filename, image)

# 画像を復元して表示
restored_image = load_image_from_txt('image_size.txt')
cv2.imshow('Restored Image', restored_image)
cv2.waitKey(0)
cv2.destroyAllWindows()

# 画像をファイルに保存
save_image(restored_image, 'restored_image.jpg')

実行結果がこちらです。

無事、復元することができました。

以上となります。
この記事が少しでもお役に立てれば幸いです。
それでは、読んで頂きありがとうございました!

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次