Pyhotn 線図の細線化「scikit-image × sknw」とsvgファイルの作成「svgwrite」

 本記事では、下図のような画像ファイル(.jpgや.png)の線図のラインをpathとしたsvgファイルを作成するPythonの雛形コードを作成しました。

作成したsvgファイルは、CADソフトで読み込むことが出来ます。下図は、オープンソースのFreeCADで読み込んだ例です。

■ライブラリのインストール

pipの場合

pip install scikit-image
pip install sknw
pip install svgwrite

anaconda環境下の場合

conda install -c anaconda scikit-image
conda install -c conda-forge sknw
conda install svgwrite

 

■本プログラム

import os
import cv2
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from skimage.morphology import skeletonize
import sknw
import svgwrite

# 画像ファイルのパス
file_path = './pictures/tubo.png'
file_name = os.path.basename(file_path)
fname, ext = os.path.splitext(file_name)
print(fname, ext)

# 保存フォルダパス
save_dir = './save_dir/'

# 画像をOpenCVで読み込む
img = cv2.imread(file_path)
plt.imshow(img)


# In[2]:


# グレースケールに変換する
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
plt.imshow(gray)


# In[3]:


# 上下反転(座標抽出する際に反転するため)
gray_flip = cv2.flip(gray, 0)
plt.imshow(gray_flip)


# In[4]:


# 90度回転(座標抽出時に回転するため)
gray_rotate = cv2.rotate(gray_flip, cv2.ROTATE_90_CLOCKWISE)
plt.imshow(gray_rotate)


# In[5]:


# しきい値処理
retval, dst = cv2.threshold(gray_rotate, 192, 255, cv2.THRESH_OTSU) # THRESH_OTSU THRESH_BINARY THRESH_TOZERO
plt.imshow(dst)


# In[6]:


# .svgファイルを出力するファイルパス
outfile_name = f'{save_dir}{fname}_sknw_Draw.svg'

# ファイルがすでにある場合は削除する
if os.path.exists(outfile_name):
    os.remove(outfile_name)
    print('delete ', outfile_name)

# skimageによるskeleton化
ske = skeletonize(~(dst != 0))

# skeleton networkを作成
graph = sknw.build_sknw(ske.astype(np.uint32), multi=True)

# svgwriteのインスタンス生成
dwg = svgwrite.Drawing(outfile_name,
                       profile = 'tiny', #'tiny', 'full'
                      )

# edge
for i, (s,e) in enumerate(graph.edges()):
    pt_s = graph.nodes[s]['o'].tolist()
    pt_e = graph.nodes[e]['o'].tolist()
    
    for g in graph[s][e].values():
        points = g['pts'].tolist()
        points = [pt_s] + points + [pt_e]
        
        # パスメソッドで生成する場合(データ間を直線で結ぶ座標を作る)
        p = ""
        for i in range(len(points)):
            if i == 0:
                p = "M " + str(points[i][0]) + " " + str(points[i][1]) 
            else:
                p += " L " + str(points[i][0]) + " " + str(points[i][1]) 
        path = dwg.path(p).stroke(width = 1).fill('none')
        dwg.add(path) 

#         # ポリゴンラインで生成する場合
#         dwg.add(dwg.polyline(points = points,
#                             #stroke = color,
#                             stroke_width = 1,
#                             fill = 'none', #'none', 'red', color
#                             id = 'id_' + '{0:03}'.format(num),
#                            ))

dwg.save()
del dwg
print('save', outfile_name)

(参考)scikit-image × sknwを使わずに、OpenCVのみで同様のことをする雛形コードは次のリンクを参照下さい。線図のラインを閉じたポリゴンで作成します。

hk29.hatenablog.jp

以上

<広告>