0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

座標の回転

Last updated at Posted at 2020-12-10

座標の回転

基本的な考え方

中心から放射状に線を引いて基本的な回転の仕方を演習します
線の長さ x cos(角度)したものが回転後の横座標です
線の長さ x sin(角度)したものが回転後の縦座標です
算出した座標に中心座標を加算して表示位置を調整します。

放射状に線を引いてみる

import math
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
import PIL.Image
import PIL.ImageDraw
import random

def create_image(w, h):
    im = PIL.Image.new("RGB", (w, h), (0, 0, 0))
    return im
WIDTH = 300
HEIGHT = 200
img = create_image(WIDTH, HEIGHT)
draw = PIL.ImageDraw.Draw(img)

# π を32分割してラジアンの配列で扱う
splitN = 32
radArr = []
for n in range(splitN):
    rad = -math.pi + (n / splitN * math.pi * 2)
    radArr.append(rad)

print(radArr)
# ラジアンの配列を8分割して内容を確認する
for i in range(0, len(radArr), int(len(radArr) / 8)):
    print("radArr[{}]={}".format(i, radArr[i]))
CENTER_X = WIDTH / 2
CENTER_Y = HEIGHT / 2
LENGTH = 10
for rad in radArr:
    x1 = CENTER_X
    y1 = CENTER_Y
    x2 = x1 + math.cos(rad) * LENGTH
    y2 = y1 + math.sin(rad) * LENGTH
    draw.line((x1, y1, x2, y2), fill=(255, 255, 255), width=1)
    LENGTH += 3 # 角度が変わる毎に長さを加算して角度の増える回転向きを確認しやすくしている

imgnp = np.array(img.convert('1')).astype(int)
plt.imshow(imgnp)
plt.show()

出力結果

[-3.141592653589793, -2.945243112740431, -2.748893571891069, -2.552544031041707, -2.356194490192345, -2.1598449493429825, -1.9634954084936207, -1.7671458676442586, -1.5707963267948966, -1.3744467859455345, -1.1780972450961724, -0.9817477042468106, -0.7853981633974483, -0.589048622548086, -0.39269908169872414, -0.1963495408493623, 0.0, 0.1963495408493623, 0.39269908169872414, 0.589048622548086, 0.7853981633974483, 0.9817477042468106, 1.178097245096172, 1.3744467859455343, 1.5707963267948966, 1.7671458676442588, 1.9634954084936211, 2.1598449493429825, 2.356194490192345, 2.552544031041707, 2.7488935718910685, 2.945243112740431]
radArr[0]=-3.141592653589793
radArr[4]=-2.356194490192345
radArr[8]=-1.5707963267948966
radArr[12]=-0.7853981633974483
radArr[16]=0.0
radArr[20]=0.7853981633974483
radArr[24]=1.5707963267948966
radArr[28]=2.356194490192345

放射状の線.PNG

角度が一段階変わる毎に線の長さを伸ばしてラジアンの値と見た目の角度をわかりやすくしています

適当な図形(複数の線)を回転させてみる - サンプル作り

random.seed(0)
coord1 = (
    int(random.uniform(0, WIDTH)),
    int(random.uniform(0, HEIGHT)),
    int(random.uniform(0, WIDTH)),
    int(random.uniform(0, HEIGHT)),
)
coord2 = (
    int(random.uniform(0, WIDTH)),
    int(random.uniform(0, HEIGHT)),
    int(random.uniform(0, WIDTH)),
    int(random.uniform(0, HEIGHT)),
)
coord3 = (
    int(random.uniform(0, WIDTH)),
    int(random.uniform(0, HEIGHT)),
    int(random.uniform(0, WIDTH)),
    int(random.uniform(0, HEIGHT)),
)
img = create_image(WIDTH, HEIGHT)
draw = PIL.ImageDraw.Draw(img)
draw.line(coord1, fill=(255, 255, 255), width=1)
draw.line(coord2, fill=(255, 255, 255), width=1)
draw.line(coord3, fill=(255, 255, 255), width=1)
imgnp = np.array(img.convert('1')).astype(int)
plt.imshow(imgnp, cmap='binary', interpolation='nearest')
plt.show()

回転対称サンプル画像.PNG

作った図形を回転させる

# 座標回転する機能を関数化しておく
def rotateCoordinate(centerX, centerY, x, y, rad):
    origRad = math.atan2(centerY - y, centerX - x) # 原点から座標の角度を出しておく(現在の角度)
    rad = origRad + rad # 現在の角度に新しい角度を加算する
    if rad > math.pi:
        rad = rad - math.pi * 2
    distance = math.sqrt((x - centerX) ** 2 + (y - centerY) ** 2)
    newX = centerX + math.cos(rad) * distance
    newY = centerY + math.sin(rad) * distance
    return newX, newY

# 対角線の幅を算出
diagonalWidth = math.ceil(math.sqrt(WIDTH ** 2 + HEIGHT ** 2))
print("diagonalWidth", diagonalWidth)
NEW_CENTER_X = int(diagonalWidth / 2)
NEW_CENTER_Y = int(diagonalWidth / 2)
#画像幅が変わるため中心に寄せるための補正値を算出
CENTER_X_DIFF = NEW_CENTER_X - CENTER_X
CENTER_Y_DIFF = NEW_CENTER_Y - CENTER_Y
img = create_image(diagonalWidth, diagonalWidth)
draw = PIL.ImageDraw.Draw(img)

rad = radArr[23]
for coord in [coord1, coord2, coord3]:
    x1, y1 = rotateCoordinate(CENTER_X, CENTER_Y, coord[0], coord[1], rad)
    x2, y2 = rotateCoordinate(CENTER_X, CENTER_Y, coord[2], coord[3], rad)
    x1 += CENTER_X_DIFF
    y1 += CENTER_Y_DIFF
    x2 += CENTER_X_DIFF
    y2 += CENTER_Y_DIFF
    print((x1, y1, x2, y2))
    draw.line((x1, y1, x2, y2), fill=(255, 255, 255), width=1)

imgnp = np.array(img.convert('1')).astype(int)
plt.figure(dpi=100)
plt.imshow(imgnp, cmap='binary', interpolation='nearest')
plt.show()

出力結果

diagonalWidth 361
(209.9257461329035, 69.0295096956447, 136.62368898862877, 213.09827250846783)
(159.79902342588701, 180.95945059911287, 124.18591141249983, 104.43686404637057)
(197.2532870625807, 184.72483709096778, 156.19898071403233, 60.344195790805884)

サンプル画像_回転後.PNG

回転後にはみ出ないように元画像サイズの対角線を縦横の長さにした新しい画像素体を準備しそこに描画します。
新しい幅に対して中心がずれるため CENTER_X_DIFF, CENTER_Y_DIFF 変数にて座標の補正を行います。

以上です

0
1
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?