taizu61zx
@taizu61zx (は たい)

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

PythonのCV2で二つの円を結ぶ

解決したいこと

Pythonのcv2で図形を描画しようとしています
下記の図にある通り円Aと円Bがあるとします。
その二つの円を青の斜線で引いてある図形で結びたいと思っています。このように、2つの円を結んで描画するためにはどのようにすればよいでしょうか。
image.png

発生している問題・エラー

エラーメッセージが出るわけではないのですが、どんなに修正を繰り返してもズレてしまします。

該当するソースコード

p = (5,3)
r = 3
a = (5,3)
b = (1,1)
vec = b - a
rad = np.arctan2(vec[0], vec[1]) #角度
deg = np.rad2deg(rad) #ラジアン → 度
# 角度θ[°]
theta = deg
# degree → rad に変換
rad = np.deg2rad(theta)
# 移動量を算出
rsinθ = r * np.sin(rad)
rcosθ = r * np.cos(rad)
# 円周上の座標
t = np.array([p[0] + rcosθ, p[1] + rsinθ])
t = t.tolist()
# 角度θ[°]
 theta = deg -180
# degree → rad に変換
rad = np.deg2rad(theta)
# 移動量を算出
rsinθ = r * np.sin(rad)
rcosθ = r * np.cos(rad)
# 円周上の座標
t2 = np.array([p[0] + rcosθ, p[1] + rsinθ])
t2 = t2.tolist()

p = (1,1)
r = 1
vec = a - b
rad = np.arctan2(vec[0], vec[1]) #角度
¥deg = np.rad2deg(rad) #ラジアン → 度
# 角度θ[°]
theta = deg
# degree → rad に変換
rad = np.deg2rad(theta)
# 移動量を算出
rsinθ = r * np.sin(rad)
rcosθ = r * np.cos(rad)
# 円周上の座標
t3 = np.array([p[0] + rcosθ, p[1] + rsinθ])
t3 = t3.tolist()
# 角度θ[°]
theta = deg -180
# degree → rad に変換
rad = np.deg2rad(theta)
# 移動量を算出
rsinθ = r * np.sin(rad)
rcosθ = r * np.cos(rad)
# 円周上の座標
t4 = np.array([p[0] + rcosθ, p[1] + rsinθ])
t4 = t4.tolist()
points = np.array([(math.floor(t[0]), math.floor(t[1])), (math.floor(t2[0]), math.floor(t2[1])), (math.floor(t3[0]), math.floor(t3[1])), (math.floor(t4[0]), math.floor(t4[1]))])
cv2.fillConvexPoly(img, points, (255, 255, 0))

自分で試したこと

幾度と修正を行い、試行を繰り返しましたが、一人での解決には限界を感じました。
是非みなさんの知恵をお借りしたく質問させていただきました。

0

2Answer

おそらくですが、
np.arctan2は第一引数がyで第二引数がxです。
np.arctan2(vec[0], vec[1])

t = np.array([p[0] + rcosθ, p[1] + rsinθ])
ここが対応していない気がします。

あとは変数名はrではなくr1とかr_Aとか書いてもらえると解読しやすいです。

1Like

参考画像では、「二つの円の中心を結ぶ直線に対して直交する線」と「それぞれの円」が交わる点を結んでいます。
しかし、これでは以下の画像のようにポリゴンが円の内側になってしまう状況が発生します。
test.png

質問者さんの意図をくみ取ると、以下の画像のように共通外接線で結ぶのが良いのではないかと思います。

test.png

以下、ソースコードです。

import cv2
import math
import numpy as np

def getNodalPoints(C1, C2, func):
    (x1, y1), _ = C1
    (x2, y2), _ = C2

    theta = math.atan2(y2 - y1, x2 - x1)
    alpha = func(C1, C2)

    points = []
    sw = 1
    for (x, y), r in (C1, C2):
        for sign in (1.0, -1.0):
            dx = r * math.cos(theta + sw * sign * alpha)
            dy = r * math.sin(theta + sw * sign * alpha)
            points.append((math.floor(x + dx), math.floor(y + dy)))
        sw = -1
    return np.array(points)

def forVertical(C1, C2):
    return 0.5 * np.pi

def forExternal(C1, C2):
    (x1, y1), r1 = C1
    (x2, y2), r2 = C2
    return math.acos((r1 - r2) / math.sqrt((x2 - x1)**2 + (y2 - y1)**2))

# 設定
C1 = ((400, 300), 150)
C2 = ((200, 450), 50)
color = (0, 0, 0)

# テスト用画像
height, width = 640, 640
img = np.full((height, width, 3), 255, np.uint8)

# 円の描画
cv2.circle(img, C1[0], C1[1], color)
cv2.circle(img, C2[0], C2[1], color)

# ポリゴンの節点を取得
points = getNodalPoints(C1, C2, forVertical)
# points = getNodalPoints(C1, C2, forExternal)

# ポリゴンの描画
cv2.fillConvexPoly(img, points, color)

# 画像の保存
cv2.imwrite("test.png", img)
1Like

Your answer might help someone💌