Delaunay and Voronoi portrait

Motivation

alexwolfe.blogspot.com


このサイトみたいなことがしたくてボロノイ図について調べたらドロネー図とかかわりあったから両方やってみた。
※とても手抜きな記事です!




Voronoi図とDelaunay図

下記リンク参照。キリンさんとかの模様が似ているらしい。すごい!
www.ics.kagoshima-u.ac.jp
f:id:busongames:20190807222330j:plain
f:id:busongames:20190807222539j:plain



コード

Opencvでどちらも描画できるらしいのでコピペする。
note.nkmk.me
自分で実装したりもしたけどそれなりに計算に時間がかかるので却下した(ドロネー図実装の参考にしたサイトの方法だとO(n^2), 木をうまく使うとO(nlogn))。
qiita.com
ボロノイ図についてはここが面白い。
ysmr-ry.hatenablog.com

import numpy as np
import cv2


def main():
    img = make_delaunay(path/to/image)

    cv2.imshow("result", img)
    cv2.waitKey(0)


def make_subdiv(img):
    n_point = 10000

    blur = cv2.GaussianBlur(img, (5, 5), 0)
    _, th = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)
    result = np.zeros((img.shape[0], img.shape[1]))
    rand_xy = []
    cnt = 0
    while True:
        x = np.random.randint(1, img.shape[1])
        y = np.random.randint(1, img.shape[0])
        if th[y][x] == 0:
            rand_xy.append([x, y])
            result[y][x] = 1
            cnt += 1
        if cnt >= n_point:
            break

def make_delaunay(path):
    img = cv2.imread(path)
    img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

    subdiv = make_subdiv(img_gray)

    triangles = subdiv.getTriangleList()
    pols = triangles.reshape(-1, 3, 2)
    img_draw = np.zeros((img.shape[0], img.shape[1]))
    cv2.polylines(img_draw, pols.astype(int), True, 1, thickness=1)
    img_draw = post_pro(img_draw)
    cv2.imwrite("delaunay_cv2.png", img_draw)
    return img_draw


def make_voronoi(path):
    img = cv2.imread(path)
    img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

    subdiv = make_subdiv(img_gray)
    facets, centers = subdiv.getVoronoiFacetList([])
    img_draw = np.zeros((img.shape[0], img.shape[1]))
    cv2.polylines(img_draw, [f.astype(int)
                             for f in facets], True, 1, thickness=1)
    img_draw = post_pro(img_draw)
    cv2.imwrite("voronoi_cv2.png", img_draw)
    return img_draw


def post_pro(img):
    img = (img*255).astype(np.uint8)
    # img = 255-img
    return img


if __name__ == "__main__":
    main()

点群は大津の二値化した画像の黒い方に点を10000個ランダムでうつ。輝度で分けたりいろいろなやり方があるっぽい。



結果

f:id:busongames:20190807225838p:plain
モナリザボロノイ
f:id:busongames:20190807225918p:plain
モナリザドロネー
f:id:busongames:20190807231452p:plain
色付きモナリザボロノイ
f:id:busongames:20190807231537p:plain
色付きレナボロノイ
f:id:busongames:20190807231753p:plain
色付きネコちゃんボロノイ

タイトルを英語にすると伸びることに気づいて味を占めてます...