end0tknr's kipple - 新web写経開発

http://d.hatena.ne.jp/end0tknr/ から移転しました

opencv.approxPolyDP() による 画像から抽出された境界(輪郭)の直線近似

opencv.findContours() による 画像の境界(輪郭)探索 - end0tknr's kipple - 新web写経開発

先日のエントリの続き。詳細は、以下参照。

#!/usr/local/bin/python
# -*- coding: utf-8 -*-
from PIL import Image
import cv2
from datetime import datetime
import matplotlib
matplotlib.use('Agg')
import matplotlib.pylab as plb
import numpy as np
import sys

# http://lang.sist.chukyo-u.ac.jp/classes/OpenCV/py_tutorials/py_imgproc/py_contours/py_contour_features/py_contour_features.html

def main():
    org_file = sys.argv[1]

    img_org = cv2.imread(org_file)
    # グレースケール化
    img_tmp = cv2.cvtColor(img_org, cv2.COLOR_BGR2GRAY)

    # 2値化
    # - cv2.findContours()は、黒と背景、白を物体として判定する為
    #   cv2.THRESH_BINARY_INV で 2値化し、ネガポジ反転
    # - cv2.THRESH_BINARY は単なる2値化
    ret, img_tmp = cv2.threshold(img_tmp,
                                 250,                  # 閾値
                                 256,                  # 画素値の最大値
                                cv2.THRESH_BINARY_INV) # 2値化type

    time_str = datetime.now().strftime("%Y%m%d_%H%M%S")
    tmp_file = 'tmp_' + time_str + '.png'
    cv2.imwrite(tmp_file, img_tmp)

    # 境界線探索
    # - 第2引数:
    #   - cv2.RETR_EXTERNAL は最外周のみ探索
    #   - cv2.RETR_TREE     は全境界(輪郭? 等高線?)を探索
    # - 返り値:
    #   - contours : 探索された境界
    #   - hierarchy: 境界が複数ある場合の階層
    ret, contours, hierarchy = cv2.findContours(img_tmp,
                                                cv2.RETR_EXTERNAL,
#                                                 cv2.RETR_TREE,
                                                cv2.CHAIN_APPROX_SIMPLE )
#                                                 cv2.CHAIN_APPROX_NONE )

    contours.sort(key=cv2.contourArea, reverse=True)
    
    i  = 0
    for contour in contours:
        arclen = cv2.arcLength(contour,
                               True) # 対象領域が閉曲線の場合、True
        approx = cv2.approxPolyDP(contour,
                                  0.005*arclen,  # 近似の具合?
                                  True)
        print approx

           #  B   G   R
        color = \
           (  0,  0,255) if i % 6 == 0 else \
           (  0,255,  0) if i % 6 == 1 else \
           (255,  0,  0) if i % 6 == 2 else \
           (  0,255,255) if i % 6 == 3 else \
           (255,255,  0) if i % 6 == 4 else (255,  0,255)

        # 境界の描画 ( img_org データに contours データをマージ )
        cv2.drawContours(img_org,
                         [approx],
                         -1,    # 表示する輪郭. 全表示は-1
                         color,
                         2)    # 等高線の太さ
        i += 1
        if i > 3:
            break
        
    new_file = 'new_' + time_str + '.png'
    cv2.imwrite(new_file, img_org)


if __name__ == '__main__':
    main()

↑こう書くと↓こう変換されます。

以前の単純な境界抽出と比較すると、窓の部分が、直線になっていることが分かります。

f:id:end0tknr:20171104233712p:plain f:id:end0tknr:20171105103250p:plain