k平均法 (k-means) で画像の減色処理 (クロスステッチデータを作る 第2回)
本日の課題と目標
k平均法 (k-means) を勉強する
前回リサイズした画像データの色数をいい感じに減らす
はじめに
【勘違い】今まで画像ファイルを読み込んで三次元配列に変換してると思ってしましたが実は画像ファイルのデータは元々三次元配列のデータでした。色データが縦横にぎっしり詰まっているイメージです。
例えば1024×768を画素数で示せば、単純にかけ算すればいいのですから、786432画素。約78万画素になります。つまり約78万画素の色データを持っているということです。
ここでもリスト 多次元配列がかなり重要になります。三次元配列をしっかり理解しないと今後苦労すると思ったので復習しました。
画像の減色処理のプログラム
# -*- coding: utf-8 -*- import cv2 import numpy as np # 減色処理 def sub_color(src, K): # 次元数を1落とす Z = src.reshape((-1,3)) # float32型に変換 Z = np.float32(Z) # 基準の定義 criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0) # K-means法で減色 ret, label, center = cv2.kmeans(Z, K, None, criteria, 10, cv2.KMEANS_RANDOM_CENTERS) # UINT8に変換 center = np.uint8(center) res = center[label.flatten()] # 配列の次元数と入力画像と同じに戻す return res.reshape((src.shape)) def main(): # 入力画像とスクリーントーン画像を取得 img = cv2.imread("input.jpg") # 減色処理(三値化) dst = sub_color(img, K=32) # 結果を出力 cv2.imwrite("output.jpg", dst) if __name__ == '__main__': main()
解説
reshapeメソッドの使い方
配列の次元数を変えます
戻り値 = 引数1.reshape( (引数2,引数3,‥引数n) )
戻り値: 指定された多次元配列
引数1: 元の多次元配列
引数2: 一次元目の個数
引数3: 二次元目の個数
引数n: n次元目の個数
( -1 は一つの引数にだけ可。総個数に応じて自動計算される)
例: b = a.reshape(-1, 3)
この三次元配列が (画像データの縦横色)
a =
[[[255 255 255] [255 255 255] [255 255 255]]
[[255 255 255] [255 255 255] [255 255 255]]
[[255 255 255] [255 255 255] [255 255 255]]]
こちらの二次元配列に変換されます。
b =
[[255 255 255]
[255 255 255]
[255 255 255]
⋮
[255 255 255]
[255 255 255]]
shapeメソッドの使い方
配列の次元ごとの個数を返します
配列の形状を確認することができます
戻り値1, 戻り値2, …戻り値n = 引数1.shape
戻り値1: 一次元目の個数
戻り値2: 二次元目の個数
戻り値n: n次元目の個数
引数1: 元の多次元配列
cv2.kmeans関数の使い方
戻り値1, 戻り値2, 戻り値3 = cv2.kmeans(引数1, 引数2, None, 引数3, 引数4, 引数5)
戻り値1: 重心の距離の二乗和
戻り値2: 各要素に与えられたラベル
戻り値3: クラスタ(群れ)の重心
引数1: 画像情報
引数2: クラスタ(群れ)の数
引数3: 3つのパラメータ (繰り返し計算の終了条件, 繰り返し計算の最大回数, 要求される精度)
引数4: コンパクトさ
引数5: 重心の初期値を決める方法
※今回は「戻り値3」がK個の色情報で「戻り値2」で1マスずつ色情報がラベリングされています。(戻り値1 は使っていません)
参考サイト
虹のフリーイラストはこちらでお借りしました。
保存ファイル
lesson22.py
文責:Luke