現在、図面の画像データをCADデータにしようとしています。
スクリプトでは、potraceというソフトとpythonを連携してラスター画像をベクター画像に変換しています。
ソフト:http://iphone.moo.jp/app/?p=386
アルゴリズム:http://sesamecake.blog84.fc2.com/blog-entry-155.html
おおよそ上手くできているのですが、以下のことをルールベースで改善したいと思っています.
・アウトラインの修正
potraceの特性上、ラスター画像での1本線はベクター画像では外枠の2本線で表現されるため、隣接する2本線を1本に統合したいです。
おすすめのアルゴリズムがあれば,ご教授いただきたいです.
・修正方法
細かく見ると、雑な箇所もありこれらを特定の閾値を使って修正したいと思っていますが,手法が思いつきません.
また、上記のような箇所を特定するために、ラスベク変換において定量的に精度を示すものが有れば教えてください。
よろしくお願い致します。
(0302 追記)
もう一点伺いたいことがあります.
ご回答いただいスクリプトで別画像のラスベク変換をした際,直角に曲がる線分が大きな曲線となる箇所がありましたが,原因は推測できるでしょうか.
よろしくお願いいたします.
気になる質問をクリップする
クリップした質問は、後からいつでもマイページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
下記のような質問は推奨されていません。
- 質問になっていない投稿
- スパムや攻撃的な表現を用いた投稿
適切な質問に修正を依頼しましょう。
回答2件
1
隣接する2本線を1本に統合したいです
アップロードされたラスター画像は線が楕円形の丸になっているような箇所がありますので、ここの連続した楕円の連続から接続された線に復元するのは、恐らくラスター→ベクター変換より大変だろうと察します。
というのも、これをやろうとすると、楕円から長手方向の向きの検出、楕円ではない部分の長手方向の向きの検出、これらの接続が必要になるためです。この処理は、ラスター画像からベクター画像を起こす処理と同じだと思います。
そう考えると、タイトルにある(=本当にやりたいことの)
ラスター画像からベクター画像への変換
をやろうとするには、ラスター画像からそのまま「線画のベクター」を吐き出すソフトを探した方が筋が良さそうです。CADにしたい、とのことですが、使っているソフトがpotraceだそうですので、SVGで出力できれば十分と判断しました。
オフラインであればこれが使えそうです。inkscapeのモジュールのようですが、pythonで書かれていますので、必要な機能を抜き出して使えそうな気がします。
※https://github.com/fablabnbg/inkscape-centerline-traceより借用
オンラインでもOKであればこんなのもありますね。
[ともにSVGに変換後PNGにして1/4に縮小 左:センターライン 右:アウトライン]
投稿2020/02/29 02:57
編集2020/02/29 03:05総合スコア2768
1
ベストアンサー
アウトラインの修正
Skeletonizeという手法が使えそうです。
これにて閉領域の中心を通る線を得られます。
さらにSkeleton Networkにてこれをグラフ化できます。
グラフのEdge
から線、あるいはBezier曲線を得ることができます。
以上を組み合わせると以下のようなSVGを出力するコードになります。
Python
1import numpy as np 2from numpy import array, linalg, matrix 3from scipy.special import comb 4import cv2 5from skimage.morphology import skeletonize 6import sknw 7import svgwrite 8 9# 10# Bézier curve fitting with SciPy 11# https://stackoverflow.com/questions/12643079/b%C3%A9zier-curve-fitting-with-scipy 12# 13Mtk = lambda n, t, k: t**(k)*(1-t)**(n-k)*comb(n,k) 14bezierM = lambda ts: matrix([[Mtk(3,t,k) for k in range(4)] for t in ts]) 15 16def lsqfit(points, M): 17 M_ = linalg.pinv(M) 18 return M_ * points 19 20def get_bezier(pts): 21 points = array(pts) 22 ts = array(range(points.shape[0]), dtype='float')/(points.shape[0]-1) 23 M = bezierM(ts) 24 control_points = lsqfit(points, M) 25 return control_points.tolist() 26 27 28if __name__ == '__main__': 29 30 fname = 'test' 31 src = cv2.imread(fname + '.png', cv2.IMREAD_GRAYSCALE) 32 _, src = cv2.threshold(src, 192, 255, cv2.THRESH_BINARY) 33 34 # Skeleton化 35 # https://scikit-image.org/docs/dev/auto_examples/edges/plot_skeleton.html 36 ske = skeletonize(~(src != 0)) 37 ske_gray = (ske * 255).astype(np.uint8) 38 ske_rgb = cv2.cvtColor(ske_gray, cv2.COLOR_GRAY2RGB) 39 cv2.imwrite(fname + '_ske.png', ske_rgb) 40 41 # Skeleton Networkを作成 42 # https://github.com/Image-Py/sknw 43 graph = sknw.build_sknw(ske.astype(np.uint16), multi=True) 44 45 dwg = svgwrite.Drawing(fname + '.svg', profile='tiny') 46 47 # Edge 48 for (s,e) in graph.edges(): 49 50 pt_s = graph.node[s]['o'].tolist() 51 pt_e = graph.node[e]['o'].tolist() 52 53 for g in graph[s][e].values(): 54 55 # 開始 + 中間点 + 終点 56 pts = g['pts'].tolist() 57 pts = [pt_s] + pts + [pt_e] 58 59 # 点群にフィットするBezierのパラメータを取得 60 params = get_bezier(pts) 61 62 # Bezierとして描画 63 d = 'M{},{} C{},{} {},{}, {},{}'.format( params[0][0], params[0][1], params[1][0], params[1][1], params[2][0], params[2][1], params[3][0], params[3][1]) 64 p = dwg.path( d=d, stroke='#000', fill='none', stroke_width=5) 65 dwg.add(p) 66 67 # 線をそのまま描画 68 #for i in range(len(pts)-1): 69 # dwg.add(dwg.line(pts[i], pts[i+1], stroke='#000', stroke_width=5)) 70 71 dwg.save()
結果は、まあそれなりですね。
元画像

Skelton化した画像

SVGをpng化した画像

修正前
変換結果の画像を見ると、アウトラインのひとつひとつはもともとは2次元ポリゴンで構成されているかと思われます。
であればMedial axis、限定(直線)的にはStraight skeletonが求めたいラインに近いものになるかと思います。
python
でのそのものずばりの実装は見つかりませんでしたが、以下が参考になるかと思います。
投稿2020/02/29 02:46
編集2020/03/01 12:35総合スコア36993
下記のような回答は推奨されていません。
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
このような回答には修正を依頼しましょう。
回答へのコメント
関連した質問
Q&A
解決済
C言語でIFFTを実装したい
回答1
クリップ0
更新
2023/03/22
意見交換
受付中
プログラマー歴6年目、未だに分からないことが多く困っています
回答7
クリップ0
更新
2023/03/26
Q&A
受付中
EXCELでのデータの良い分類方法がわかりません
回答2
クリップ1
更新
2023/03/21
Q&A
解決済
GASのfor文で繰り返すと1回目で時間フォーマットが合わないとエラーになる
回答2
クリップ0
更新
2023/03/28
意見交換
受付中
プログラミングの設計が分からない
回答24
クリップ10
更新
2023/03/17
意見交換
受付中
データベースの負荷を下げたい
回答29
クリップ0
更新
2023/03/28
Q&A
受付中
デシクショナリーオブジェクトを利用して、重複データを格納したい
回答6
クリップ0
更新
2023/03/27
Q&A
受付中
【GAS】フォルダ内の全ファイルに対し処理を行う際の処理順
回答1
クリップ2
更新
2023/03/28
同じタグがついた質問を見る
Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。
下記のような回答は推奨されていません。
このような回答には修正を依頼しましょう。