国旗の色比率を円グラフにする
TBSのクイズ番組「東大王」で、国旗の色比率を円グラフにしたものを見て国旗を当てる、というクイズをやっていたのを見て同じようなグラフを作ってみました。
環境
- windows10 home
- Anaconda 3/ jupyter notebook 5.6.0
- Python 3.8.8
- OpenCV 4.5.5
- pandas 1.4.0
- matplotlib 3.5.1
準備
国旗画像は国旗 | 地図に使えるフリー素材.jpからダウンロードさせていただき、jupyter notebookファイル(***.ipynb)と同じディレクトリに保存しました。
コード
まず、OpenCVで画像を読み込み全画素の色リストを作ります。その際に色情報を処理しやすいようBx1000000+G*1000+Rと1つの数字にまとめます。collections.Counterで色の出現回数を求め、出現回数(ピクセル数)と色情報をpandasのデータフレーム化します。ピクセル数が全体の1%未満の色をノイズとして削除し降順に並べ替えます。ピクセル数と色のリストを作り、matplotlibで円グラフを作ります。
まず、UAEの国旗でやってみます(ファイル名 'UAE.png')
import cv2 import collections import pandas as pd import numpy as np import matplotlib.pyplot as plt # 国旗画像読み込みと、サイズの取得 img = cv2.imread('UAE.png') h, w, _ = img.shape # 全画素の色リストを作成 # 色情報は B*1000000 + G*1000 + R に変換し # 0埋めした9桁の文字列に color_list = [] for y in range(h): for x in range(w): color_list.append(str(img[y, x, 0]*1000000 + img[y, x, 1]*1000 + img[y, x, 2]).zfill(9)) # 出現回数(ピクセル数)をカウントする counter = collections.Counter(color_list) # ピクセル数と色をpandasデータフレーム化 df = pd.DataFrame(data=[list(counter.values()), list(counter.keys())], index = ['pixels', 'BGR']).T # ピクセル数が全体の1%未満の行を削除(ノイズとみなす) df2 = df[df['pixels'] > h*w*0.01] # 降順に並べ替え df3 = df2.sort_values(by=['pixels'], ascending=False) # ndarrayに変換し一行ずつ読み出しリストに追加 # 色情報は9桁の文字列なので3文字ずつ読み出し # 255で割って0~1の数字に変換 # 順番をBGR→RGBに変更 x_list =[] rgb_list =[] for i in df3.to_numpy(): x_list.append(i[0]) rgb_list.append([int(i[1][6:9])/255, int(i[1][3:6])/255, int(i[1][0:3])/255]) # 円グラフの作成 plt.pie(x_list, colors=rgb_list, wedgeprops={'linewidth': 1, 'edgecolor':'black'}, counterclock=None, startangle=90) plt.show()
実行結果
国旗の色比に応じた円グラフが作成されます。
もとの国旗画像はこちら。
別の国旗を試します。
スリランカの国旗(ファイル名 'Sri_Lanka.png' )を使います。
実行結果
国旗の色比に応じた円グラフが作成されます。
もとの国旗画像はこちら。
以下のサイトを参考にさせていただきました
子供の落書き帳 Renaissance > [pandas]特定の条件を満たす行を削除する
note.nkmk.me > Pythonで文字列・数値をゼロ埋め(ゼロパディング)