画像処理でフィルタ設計や周波数応答検証を行うのに下記のようなチェスボード画像が良く使われますね。これを回転や変形させてコーナー特徴量の検出やSIFTのロバスト性評価にも用いられるようです。
上記は幅640 pixel、縦480 pixelの画像中に25 pixelごとに白黒パターンを交互に配置したものです。白黒パターンを1 pixel単位にすると理論上、最も周波数の高い画像が生成できます。
なんてことない画像なんですが、色々とバリエーションを作りたいことがあって、任意のサイズ、任意のインターバルで画像を作りたいわけです。
C/C++使いなもんで、こういうときはサクッとCINTとかでやってましたが、最近はPythonの方が手軽ですねぇ。Cだとどうしても2次元配列をループで組む必要があって、コード量減らす場合も1次元ループから座標計算することになるわけですが、Pythonの構文みてたらリスト内包記法で書けるんちゃう?思ってやってみました。チェスボード作っている箇所はワンラインです。
import numpy as np, cv2 (W, H, I, V) = (640, 480, 25, 255) im = np.array([(((x//I) ^ (y//I)) & 1) * V for y in range(H) for x in range(W)], np.uint8).reshape(H, W) cv2.imwrite("chessboard.png", cv2.cvtColor(im, cv2.COLOR_GRAY2RGB))
2行目のパラメータは以下の通り。
W | 画像幅 |
H | 画像高さ |
I | チェスボードパターンインターバル |
V | 白部分の画素値 |
Pythonパッケージはnumpyとopencv-pythonを使ってますので、pipでインストールしておく必要あります。
しかしリスト内包記法はコードの可読性が悪いですな。ワンラインで書こうとしなければ、こんな書き方しないのですが。もちろんループを1次元にしてX,Yの座標を計算しても良いですけどね。
チェスボードパターンを作っている箇所は、以下のコードです。
(((x//I) ^ (y//I)) & 1) * V
意味としては、X、Y座標をインターバルで割って、チェスボードパターンの白黒部分の数を算出します。局所的に2×2のパターンを見ると以下のようになるはず。
0 1 +----+----+ 0 | 黒 | 白 | +----+----+ 1 | 白 | 黒 | +----+----+
これを真理値表に当てはめると
X Y +---+---+----+---+ | 0 | 0 | 黒 | 0 | | 1 | 0 | 白 | 1 | | 0 | 1 | 白 | 1 | | 1 | 1 | 黒 | 0 | +---+---+----+---+
ということで、XY座標の1ビット目の排他的論理和を計算すれば黒白パターンと一致することがわかります。上記のコードはそれをやっているわけですね。