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

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

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

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

解決済

2回答

811閲覧

格子状データの軸投影によるデータ処理の方法

monkey.0435

総合スコア22

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

0グッド

0クリップ

投稿2019/03/04 06:14

編集2019/03/29 01:44

初めまして,python初心者です.
以下のようなデータ処理を行いたいのですが,プログラムのアイディアが浮かばず困っています.
どなたかお力をかしてもらえませんでしょうか.
python3.7.1 , Anaconda3ディストリビューションを利用しています.
なお,csvファイルを読み込みリスト型にするなどの,超基本的なことは一応できます.

図(a)に示す例のように格子状正方領域にデータがcsv形式で保存されています.このデータを読み込み,各ピクセルのデータをx軸上に投影するとともに,同軸を幅1ピクセルに区切り,投影されたデータ,並びにデータの平均値を取得したいです.図(a)の例のように軸が全く回転していない場合, x = 3 での投影データが[8,5,1,2,9,8]で平均値が5.5, x = -2 での投影データが[4,8,8,4,2,2]で平均値が4.67のようになることは容易に理解でき,計算できます.しかし,(b)に示すように軸を任意の角度Θ[deg]だけ回転させた場合,x軸に投影されるデータの所得方法がわかりません.以上のような作業を回転角0~180[deg]まで,1[deg]間隔で行い,データ処理をしたいのです.

稚拙な説明で申し訳ありませんが,以上が行いたいデータ処理となります.また,初心者でも理解できるように,コードの説明もしていただけたら大変助かります.

お願いばかりで申し訳ありませんが,ご回答をよろしくお願いします.

〈追記〉
説明不足で申し訳ありません.図(c)を追加しています.図のx'y'座標系の場合,x' = 1での中の緑帯の領域に含まれる格子点のデータを参照するという意味です.各格子点の少しでも緑帯の領域に含まれていたら対象です.同様にx=-3での投影とは,図中の赤帯の領域に含まれる格子点のデータを参照するということです.また,xの座標値は整数値とします.(x = 0.5などでの投影は行いません.)

〈追記2〉
重ね重ね質問ばかりですいません.
回答者様のソースコードを参考にして,プログラムを作成できたのですが,以下の二点をさらに変更する必要が出てきました.

(1) 前回は「格子点の一部でも帯状領域に含まれていたら,そのx'座標上に投影する」としていましたが,図(d)のように「各格子点の中心(図中緑の点)が帯状領域に含まれていたら,そのx'座標上に投影する」というデータ処理を行えるように変更したいです.

(2) データを投影する対象となる点は,格子の一辺長さを直径とする円に含まれるものであること(図中の灰色部分は対象外となります.)

以上,2点を変更したいと考えていますが,どのように円形領域に変更し,中心座標を参照すればよいのかわかりません.
ご回答お待ちしております.

イメージ説明
イメージ説明イメージ説明

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

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

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

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

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

tiitoi

2019/03/04 06:19

回転している場合の「x軸上に投影」はあるピクセル (x, y) をどの方向に投影するのでしょうか?
fana

2019/03/04 10:55 編集

投影座標が整数ではない場合の集計方法の仕様が提示されるべきかと. (→「整数」と言うと語弊がありそう…「中途半端な座標」とでも言えば良いか)
monkey.0435

2019/03/04 23:35

説明不足で申し訳ありません. 質問に追記を行いました.ご確認よろしくお願いします.
tiitoi

2019/03/29 02:04

一旦クローズした質問で新たな質問が生じた場合は、再度 Open にするのではなく、新規に質問を立て直してください
fana

2019/03/29 04:29 編集

「〈追記2〉」に関しては,その文面だけだと (1)は中心位置のx'に基づき集計すれば良いだけの話になった(以前と比較して内容が単純化された)と見えるし, (2)は中心位置の原点からの距離で集計対象とするか否かを判定すれば良いだけの話に見えるので, 問題点が一体何なのかが私には読み取れませんでした. 別途質問する場合には,一体何が困り事なのか?という点を明確にすると良いかと思います.
monkey.0435

2019/03/29 05:07

ご指摘ありがとうございます! もう少し問題を具体的にした後,再度ご質問させていただきます. ありがとうございました.
guest

回答2

0

ベストアンサー

各データの座標を,回転した後の座標軸(x',y')の世界で読み変えたときのx'値に基づき集計すれば良い,という話かと思います.
(解りやすく言い換えれば,元のデータを -θ だけ回転したデータを(その結果のx座標に基づき)集計すれば良い.)

図内x'軸方向の単位ベクトルを元の(xとyの)世界の座標系で書けば( cosθ, sinθ ) です.
各データの(x,y)座標とこの単位ベクトルとの内積を取ればx'方向成分が得られます.


質問文の追加に対して:
各データに関して【その正方形のごく一部分であっても(質問内の図(c)の)帯に含まれていたらその帯に集計する】という条件であれば,
「格子点(正方形の四隅)のx'を求めて,そのいずれかが帯に含まれているか」で判定できるでしょう.

一般に,1つの正方形は二つの複数の帯にまたがることになるでしょうから,4隅のx'値のうちの最小値と最大値が所属する2つの帯最小値が所属する帯~最大値が所属する帯の範囲に集計すれば良いかと思います.(両者が同一の帯になる場合は1回だけ集計する,という判定は当然必要)

例)
回転角θ=30度のとき,正方形の四隅のうちx'が最小になるのは左下で最大になるのは右上.
図内で最も右上にあるデータ値が8の正方形について考えると,
左下頂点の座標は (x,y)=(2,2)
右上頂点の座標は (x,y)=(3,3)

x' = xcos(30) + ysin(30)

からそれぞれのx'値を求めると,
左下のx' ≒ 2.732
右上のx' ≒ 4.098

よって,このデータは,3つの帯{ x'=3, x'=4, x'=5 }に集計される(…でいいのかな?)

投稿2019/03/04 10:53

編集2019/03/05 01:24
fana

総合スコア11654

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

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

monkey.0435

2019/03/04 17:00

ご回答ありがとうございます. 参考にさせていただきます!
guest

0

fana さんが回答してくださった方法で実装してみました。


python

1import matplotlib.pyplot as plt 2from matplotlib.patches import Rectangle 3import numpy as np 4 5mat = np.array([[3, 4, 6, 9, 0, 8], 6 [2, 8, 5, 0, 3, 5], 7 [4, 8, 1, 0, 3, 1], 8 [0, 4, 3, 7, 1, 2], 9 [4, 2, 6, 1, 0, 9], 10 [7, 2, 1, 6, 2, 8]], dtype=float) 11angle = 10 # x 軸の回転角度 (degree) 12radius = np.array(mat.shape) // 2 # 半径 13 14def create_rotation_matrix(angle): 15 t = np.deg2rad(angle) 16 return np.array([[np.cos(t), -np.sin(t)], 17 [np.sin(t), np.cos(t)]]) 18R = create_rotation_matrix(-angle) # x 軸の回転方向とは逆の方向に回転する回転行列
# 各セルの4点の座標を作成する。 cells = [] id_ = 0 # あとでどのセルが含まれているのか確認するための識別子 (デバッグ用) for (i, j), value in np.ndenumerate(mat): # セルの左下の点 (x, y) を定義する。 x, y = j - radius[1], radius[0] - i - 1 # セルを構成する4点を作成する。 rect = np.array([[x, y], [x + 1, y], [x + 1, y + 1], [x, y + 1], [x, y]]) # セルを構成する4点を回転させる。 rect = rect.dot(R.T) cells.append((id_, rect, value)) id_ += 1

各区別 [x_i, x_{i + 1}] に含まれるセルを見つけて、その値の平均を計算する。

edges = np.arange(-radius[1], radius[1] + 1) for left, right in zip(edges, edges[1:]): values = [] for id_, rect, value in cells: if np.any((left <= rect[:, 0]) & (rect[:, 0] <= right)): values.append((id_, value)) # セルの4隅の1点でも [left, right] に含まれる場合 values = sorted(values, key=lambda x: x[0]) # 見やすいように id でソートする。 mean = np.mean([x[1] for x in values]) # 平均 print('{} <= x <= {}:\n value: {}\n mean: {}'.format( left, right, values, mean))
-3 <= x <= -2: value: [(0, 3.0), (6, 2.0), (12, 4.0), (18, 0.0), (19, 4.0), (24, 4.0), (25, 2.0), (30, 7.0), (31, 2.0)] mean: 3.111111111111111 -2 <= x <= -1: value: [(0, 3.0), (1, 4.0), (6, 2.0), (7, 8.0), (12, 4.0), (13, 8.0), (18, 0.0), (19, 4.0), (20, 3.0), (25, 2.0), (26, 6.0), (31, 2.0), (32, 1.0)] mean: 3.6153846153846154 -1 <= x <= 0: value: [(1, 4.0), (2, 6.0), (7, 8.0), (8, 5.0), (13, 8.0), (14, 1.0), (15, 0.0), (19, 4.0), (20, 3.0), (21, 7.0), (26, 6.0), (27, 1.0), (32, 1.0), (33, 6.0)] mean: 4.285714285714286 0 <= x <= 1: value: [(2, 6.0), (3, 9.0), (8, 5.0), (9, 0.0), (14, 1.0), (15, 0.0), (16, 3.0), (20, 3.0), (21, 7.0), (22, 1.0), (27, 1.0), (28, 0.0), (33, 6.0), (34, 2.0)] mean: 3.142857142857143 1 <= x <= 2: value: [(3, 9.0), (4, 0.0), (9, 0.0), (10, 3.0), (15, 0.0), (16, 3.0), (17, 1.0), (22, 1.0), (23, 2.0), (28, 0.0), (29, 9.0), (34, 2.0), (35, 8.0)] mean: 2.923076923076923 2 <= x <= 3: value: [(4, 0.0), (5, 8.0), (10, 3.0), (11, 5.0), (16, 3.0), (17, 1.0), (23, 2.0), (29, 9.0), (35, 8.0)] mean: 4.333333333333333

python

1# デバッグ用 2################################################################### 3fig, ax = plt.subplots(figsize=(6, 6)) 4 5# 各セルを描画する。 6for id_, rect, value in cells: 7 ax.plot(rect[:, 0], rect[:, 1], c='gray', alpha=0.5) # セルの枠線 8 cx, cy = (rect[0] + rect[2]) / 2 # セルの中心 9 s = '{}:{}'.format(id_, value) 10 ax.text(cx, cy, s, ha='center', va='center', rotation=-angle) # 値 11ax.autoscale(False) 12# x 軸、y 軸を引く。 13ax.axhline(), ax.axvline() 14# 垂直線を引く 15ax.vlines(edges, *ax.get_xlim(), alpha=0.5)

イメージ説明

投稿2019/03/04 07:49

編集2019/03/05 05:53
tiitoi

総合スコア21956

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

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

fana

2019/03/04 09:51

最後の絵を見た感じですが,青い線の位置と間隔が不思議な感じ…? 話的には,青線群は無回転時には四角形の中央を貫くことになるのだと思うので,回転した軸上での x'={ 0.5マス, 1.5マス, 2.5マス, ... } の位置を通ると良いのでは,と思うのですが,どうでしょうか.
tiitoi

2019/03/04 10:00

コメントありがとうございます。 おっしゃる通り、線の位置がズレていたのでコードを更新しました。
monkey.0435

2019/03/04 23:40

ご回答ありがとうございます! 質問ばかりで申し訳ないのですが,質問に追記した図のような領域で,各x'座標における格子点データを図ではなく数値として取得することは可能でしょうか?
tiitoi

2019/03/05 05:55

fana さんが回答してくださった方法でできるはずですよ。 サンプルコードを載せました。
fana

2019/03/05 07:40

-3 <= x <= -2: のように(両側が<=で)表示されていますが,無回転状態のことを考慮すると一方の境界を含まないようにしないとダメなのかも? (ところで,元々の方法の側の話も残してあっても良かったのではないでしょうか.)
monkey.0435

2019/03/06 02:05

みなさん,ご回答ありがとうございました! 今回はfanaさんのご回答をベストアンサーとさせていただきます. また何かありましたらよろしくお願いします!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問