質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.37%
Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

2回答

8108閲覧

ラスター画像からベクター画像への変換について

93monocro

総合スコア8

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

1クリップ

投稿2020/02/29 00:15

編集2020/03/02 16:01

現在、図面の画像データを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 追記)
もう一点伺いたいことがあります.
ご回答いただいスクリプトで別画像のラスベク変換をした際,直角に曲がる線分が大きな曲線となる箇所がありましたが,原因は推測できるでしょうか.

よろしくお願いいたします.
イメージ説明

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

隣接する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
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ベストアンサー

アウトラインの修正

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
can110

総合スコア38339

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

93monocro

2020/03/02 15:58

わざわざ,コードを書いてくださりありがとうございます!! おかげで,ラスベク変換がうまくいきました. skimageというモジュールがあることもわかり勉強になりました. よろしくお願い申し上げます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.37%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問