本記事では、下図左のような線図の線を検出して、下図右のようにCADで読み込めるsvgファイルを作成する雛形コードを載せました。

線図の線は、領域ごとに閉じたポリゴンとして作成します。そのため、押し出すことができます。下図は、オープンソフトのFreeCADでsvgを読み込み、Extrudeでソリッド(立体)を作成した例です。

本プログラムでは、OpenCVのcv2.ximgproc.thinningメソッドを使用します。もし使用しない場合、線図の線が枝分かれしてる箇所で2重線となり、領域が分かれてしまいます(下図)。

■ライブラリのインストール
pip install opencv-contrib-python
pip install svgwrite
■本プログラム
import os
import cv2
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
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/'
img = cv2.imread(file_path)
plt.imshow(img)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
plt.imshow(gray)
gray_inv = cv2.bitwise_not(gray)
plt.imshow(gray_inv)
gray_flip = cv2.flip(gray_inv, 0)
plt.imshow(gray_flip)
skeleton = cv2.ximgproc.thinning(gray_flip, thinningType=cv2.ximgproc.THINNING_GUOHALL)
plt.imshow(skeleton)
contours, hierarchy = cv2.findContours(skeleton, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_NONE)
print(len(contours))
print(hierarchy)
x_list = []
y_list = []
df_group_list = []
for i in range(len(contours)):
if hierarchy[0][i][-1] == 0:
buf_np = contours[i].flatten()
for i, elem in enumerate(buf_np):
if i%2 == 0:
x_list.append(elem)
else:
y_list.append(elem * (-1))
mylist = list(zip(x_list, y_list))
df_buf = pd.DataFrame(mylist, columns = ['x', 'y'])
df_group_list.append(df_buf)
x_list.clear()
y_list.clear()
print('df_group_list', len(df_group_list))
for i, df_buf in enumerate(df_group_list, start=1):
plt.scatter(df_buf['x'], df_buf['y'], s = 0.5)
plt.xlabel('x')
plt.ylabel('y')
plt.grid()
plt.savefig(f'{save_dir}{fname}_03_scatter.jpg')
if False:
for i, df_buf in enumerate(df_group_list):
if not df_buf[(df_buf['x'] == 0) & (df_buf['y'] == 0)].empty:
df_group_list.pop(i)
DF_name_list = []
DF_list = []
for i, df_buf in enumerate(df_group_list, start=1):
plt.scatter(df_buf['x'], df_buf['y'], s = 0.5)
plt.xlabel('x')
plt.ylabel('y')
plt.grid()
DF_name_list.extend(['id_'+ '{0:03}'.format(i) + '_x', 'id_'+ '{0:03}'.format(i) + '_y'])
DF_list.append(df_buf)
DF = pd.concat(DF_list, axis=1)
DF.columns = DF_name_list
outfile_name = f'{save_dir}{fname}_05_Draw.svg'
dwg = svgwrite.Drawing(outfile_name,
profile = 'tiny',
)
for num, df_buf in enumerate(df_group_list, start=1):
print(num, 'before', len(df_buf))
if False:
df_buf = df_buf[::10]
print(num, 'after', len(df_buf))
if len(df_buf) < 10:
continue
points = df_buf.to_numpy().tolist()
p = ""
for i in range(len(points)):
if i == 0:
p = "M " + str(points[i][0]) + " " + str(points[i][1])
elif i == len( points ) - 1:
p += " L " + str(points[i][0]) + " " + str(points[i][1]) + " Z"
else:
p += " L " + str(points[i][0]) + " " + str(points[i][1])
path = dwg.path(p).stroke(width = 1).fill('none')
dwg.add(path)
dwg.save()
del dwg
print('save', outfile_name)
(参考)線を閉じたポリゴン出なくて、pathとして作成したい場合の例は次のリンク先を参照下さい。
hk29.hatenablog.jp
以上
<広告>
リンク
リンク