Facebookがセグメンテーションフレームワークをオープンソース化したと聞いて、ちょうどセグメンテーションが必要だったので調べてみた。
Segmenting and refining images with SharpMask
LuaだったりTorchだったりするのは仕方がないとして、今回は教師なしで候補領域を得たかったのだが、このフレームワークは教師ありのようだったので利用を断念して他のものを探した。
そうすると、OpenCVにそのような機能があったので試してみた。
graph_segmentation.py
import cv2
import numpy as np
segmentator = cv2.ximgproc.segmentation.createGraphSegmentation(sigma=0.5, k=300, min_size=1000)
src = cv2.imread('image.jpg')
segment = segmentator.processImage(src)
mask = segment.reshape(list(segment.shape) + [1]).repeat(3, axis=2)
masked = np.ma.masked_array(src, fill_value=0)
for i in range(np.max(segment)):
masked.mask = mask != i
y, x = np.where(segment == i)
top, bottom, left, right = min(y), max(y), min(x), max(x)
dst = masked.filled()[top : bottom + 1, left : right + 1]
cv2.imwrite('segment_{num}.jpg'.format(num=i), dst)
パラメータ | |
---|---|
sigma | 境界線の滑らかさ(複雑な境界線には小さい値、滑らかな境界線には大きい値) |
k | たぶん、どれくらい候補領域を統合するか(値が小さいと多くの小さい領域、大きいと少ない大きな領域に分割?) |
min_size | 領域の最小サイズ(たぶん領域のピクセル数) |
地味に候補領域だけを切り出すところが難しかった。
Numpyでやる以外にも、OpenCVのboundingRectを使う方法があるらしい。
追記:
segmentator.setSigma(value), segmentator.setK(value), segmentator.setMinSize(value)で値を変更可能。
そのままでは載せられないLenaさんの全身像への適用結果(sigma=0.7, k=1200, min_size=5000)