python实现判断一个点是否在任意形状区域之射线交点法
import cv2 as cv
import numpy as np
# 全局变量
points = [] # 存储绘制的点
drawing = False # 记录当前是否正在绘制
def mouse_callback(event, x, y, flags, param):
global points, drawing
if event == cv.EVENT_LBUTTONDOWN:
drawing = True
points = [(x, y)] # 清空之前的点,开始新绘制
elif event == cv.EVENT_MOUSEMOVE:
if drawing:
points.append((x, y))
elif event == cv.EVENT_LBUTTONUP:
drawing = False
points.append((x, y)) # 结束绘制,包含最后一个点
def catmull_rom_spline(points, num_points=100):
""" 使用Catmull-Rom样条生成平滑曲线 """
if len(points) < 4:
return np.array(points)
t = np.linspace(0, 1, num_points)
curve = []
for i in range(1, len(points) - 2):
p0, p1, p2, p3 = points[i-1:i+3]
for j in t:
x = 0.5 * ((2*p1[0]) + (-p0[0] + p2[0])*j +
(2*p0[0] - 5*p1[0] + 4*p2[0] - p3[0])*j*j +
(-p0[0] + 3*p1[0] - 3*p2[0] + p3[0])*j*j*j)
y = 0.5 * ((2*p1[1]) + (-p0[1] + p2[1])*j +
(2*p0[1] - 5*p1[1] + 4*p2[1] - p3[1])*j*j +
(-p0[1] + 3*p1[1] - 3*p2[1] + p3[1])*j*j*j)
curve.append((x, y))
return np.array(curve)
def is_point_in_curve(point, curve_points):
""" 使用射线交点法判断点是否在曲线内 """
x, y = point
num_points = len(curve_points)
inside = False
x1, y1 = curve_points[0]
for i in range(num_points + 1):
x2, y2 = curve_points[i % num_points]
if y > min(y1, y2):
if y <= max(y1, y2):
if x <= max(x1, x2):
if y1 != y2:
xints = (y - y1) * (x2 - x1) / (y2 - y1) + x1
if x1 == x2 or x <= xints:
inside = not inside
x1, y1 = x2, y2
return inside
def main():
global points
cv.namedWindow("Draw Curve")
cv.setMouseCallback("Draw Curve", mouse_callback)
while True:
img = np.ones((600, 800, 3), dtype=np.uint8) * 255 # 创建白色背景
if len(points) > 1:
# 生成平滑曲线
curve_points = catmull_rom_spline(points)
# 将曲线转为多边形,用于填充
curve_points = np.array(curve_points, np.int32)
curve_points = curve_points.reshape((-1, 1, 2))
# 绘制曲线
cv.polylines(img, [curve_points], isClosed=True, color=(0, 0, 255), thickness=2)
# 填充曲线内部区域
mask = np.zeros_like(img) # 创建一个黑色背景的掩码
cv.fillPoly(mask, [curve_points], color=(255, 0, 0)) # 蓝色填充
img = cv.addWeighted(img, 1, mask, 0.5, 0) # 0.5 透明度合成
for pt in points:
cv.circle(img, pt, 5, (0, 0, 255), -1)
# 显示图像
cv.imshow("Draw Curve", img)
# 检测按键
key = cv.waitKey(1) & 0xFF
if key == ord('q'):
break
elif key == ord('c'):
# 设定测试点位置
test_point = (300, 300) # 示例测试点
if len(points) > 1:
curve_points = catmull_rom_spline(points)
is_inside = is_point_in_curve(test_point, curve_points)
print(f"点 {test_point} 在曲线内: {is_inside}")
cv.destroyAllWindows()
if __name__ == "__main__":
main()