今回はこれを
こういう風にパーツに分割したい、という時のコード。
# coding: utf-8
import cv2
from PIL import Image, ImageDraw
from functools import reduce
filename = 'shapes.png'
# 外側の輪郭を取得
def find_contours(name):
im = cv2.cvtColor(cv2.imread(name), cv2.COLOR_BGR2GRAY)
_, im_bw = cv2.threshold(im, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
contours, _ = cv2.findContours(im_bw, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
return contours
image = Image.open(filename)
contours = find_contours(filename)
for i, contour in enumerate(contours):
# 輪郭データからpolygonに渡すための変換(もっと良い方法があるかもしれない)
area = tuple(map(lambda c: tuple(c[0]), contour.tolist()))
# マスク画像を作成
mask = Image.new("L", image.size, 0)
ImageDraw.Draw(mask).polygon(area, fill=255)
copy = image.copy()
copy.putalpha(mask)
# 切り抜き
bbox = reduce(lambda p, c: [
min(p[0], c[0]), min(p[1], c[1]),
max(p[2], c[0]), max(p[3], c[1])
], area, [image.width, image.height, 0, 0])
output = copy.crop(bbox)
output.save('shape_' + str(i+1) + '.png')
まずは、openCVで輪郭を抽出します。
抽出した情報を元にマスク画像(白黒画像)を作成。
そのマスク画像を使って元画像のコピーにアルファチャンネルを追加し、
外接する矩形で切り取って保存する。
という感じで実現できました。
ソースのコメントにも書いてあるとおり、contoursからtupleに切り替えるところがもっとスマートに書けると良いのだけれど、
まあ、とりあえず動いたので良しとします。