k-meansでシーン分類はできるのか?
久々に画像処理やろうと思ったら何かも地獄の釜に忘れてきたせいか何も思い出せない.
なので思い出しながら作業したいと思います.
今回はYouTubeのキズナアイちゃんのある1動画のシーンを分類します. まず動画を適当にDLしてきてffmpegで1秒1フレームで切り出し保存します.
ライブラリはこの辺りを使います. opencv3
を使ったらもっと楽かもしれない.
from PIL import Image import numpy as np import matplotlib.pyplot as plt from sklearn.cluster import KMeans #k-means %matplotlib inline
まずは画像を表示して見ます
img = Image.open("sample.jpg") plt.imshow(img)
かわいい
次に画像からRGBやHSVを取得してみます.
img = Image.open("sample.jpg") r,g,b = img.split() rh = np.array(r).flatten() gh = np.array(g).flatten() bh = np.array(b).flatten() plt.hist((rh, gh, bh), bins=120, color=("r", "g", "b"), rwidth=0.9) plt.show()
def plt_pic(img): h,s,v = img.convert("HSV").split() plt.figure(figsize=(10,8)) plt.subplot(311) plt.imshow(np.array(h)) plt.subplot(312) plt.imshow(np.array(s)) plt.subplot(313) plt.imshow(np.array(v)) plt.show() #hist_plot(h,s,v) return h,s,v plt_pic(img)
今回はこのhue(色相)を特徴量としてk-meansでクラスタリングして見ます👊
fileList = glob.glob("aichan/*.jpg") hue=[] for name in fileList: #img = Image.open(name) img = Image.open(name).resize((160,100),Image.ANTIALIAS) h,s,v = img.convert("HSV").split() ht,be = np.histogram(np.array(h),bins=120) hue.append(ht)
est = KMeans(n_clusters=6)
est.fit(hue)
labels=est.labels_
0:ゲームシーン全般
1:end
2:わーい
3:GameOver
4:!?
5:キズナアイのみ
見て分かる通り,全体的に分類できてるのがわかりますね(適当)
簡単に遊んで見ました. 今回はk-meansで遊んだんですけどクラスタ数を決めない,クラスタ数を自動で推定するx-meansとか気になってたりします.
以下はタイル状に保存とかのコードとか..
画像をタイルにするならばImageMagickのmontage使った方が綺麗になる気がする..
def tile(board,height,width,filename): img = np.array(Image.open(filename).resize((160,100),Image.ANTIALIAS)) board[height*img.shape[0]:height*img.shape[0]+img.shape[0],width*img.shape[1]:width*img.shape[1]+img.shape[1]] = img return board
result=[] disp=0 for i,name in enumerate(fileList): if labels[i] == disp: result.append(name) print(len(result)) MEL=int(np.ceil(np.sqrt(len(labels[labels==disp])))) board_width,board_height = int(160*MEL),int(100*MEL) board = np.zeros((board_height,board_width,3),dtype='uint8') print(board.shape) cnt=0 for x in range(MEL): for y in range(MEL): try: #print(result[cnt]) board = tile(board,x,y,result[cnt]) cnt+=1 except Exception as e: #print(e) break plt.imshow(board) cv2.imwrite("board{}.png".format(disp),cv2.cvtColor(board, cv2.COLOR_BGR2RGB))