back to the source - 原点回帰😎

自然言語処理 初心者

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)

f:id:planetaria:20170907203314p:plain かわいい

次に画像から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()

f:id:planetaria:20170907203439p:plain

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)

f:id:planetaria:20170907203729p:plain

今回はこの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:ゲームシーン全般
f:id:planetaria:20170907204216p:plain:w400
1:end
f:id:planetaria:20170907204243p:plain:w400
2:わーい
f:id:planetaria:20170907204253p:plain:w400
3:GameOver
f:id:planetaria:20170907204513p:plain:w400
4:!?
f:id:planetaria:20170907204308p:plain:w400
5:キズナアイのみ
f:id:planetaria:20170907204404p:plain:w400

見て分かる通り,全体的に分類できてるのがわかりますね(適当)
簡単に遊んで見ました. 今回は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))