opencv画火车沿轨道运行-课程作业

写本次博客的目的主要是记录自己的成果,有什么不足欢迎指教。

四个函数,一个循环

一、 轨道函数

#定义轨道函数
def func_2(x):
    if x>0 and x<=50:
        y = 400
    elif x>50 and x<=250:
        y = math.ceil((400**2-(x-50)**2)**0.5)
    elif x>250 and x<=350:
        y = math.floor(-((3**0.5)*x)/3+850*(3**0.5)/3)
    elif x>350 and x<=550:
        y = math.floor(-(400**2-(x-550)**2)**0.5+1100*(3**0.5)/3)
    else:
        y = math.floor(1100*(3**0.5)/3-400)
    return y

#定义轨道函数,另一种表现形式
def func_0(x):
    interval0 = 1 if x>0 and x<=50 else 0
    interval1 = 1 if x>50 and x<250 else 0
    interval2 = 1 if x == 250 else 0
    interval3 = 1 if x>250 and x<=450 else 0
    interval4 = 1 if x>450 and x<=500 else 0
    #y = 500*interval0 + 400*interval1 + 300*interval2 + 200*interval3 + 100*interval4
    y =500*interval0 + ((200**2-(x-50)**2)**0.5+300)*interval1 +300*interval2 + (-(200**2-(x-450)**2)**0.5+250)*interval3 + 50*interval4
    return y

二、定义可转弯小车的方法

#定义一个画可转弯小车的方法
def draw(canvas,result):
    result=np.array(result)
    x = result[0]
    y = result[1]
    angle = result[2]
    height = result[3]
    width = result[4]

    angle_Pi = -angle*math.pi/180.0 #转化为弧度
    cosA = math.cos(angle_Pi)
    sinA = math.sin(angle_Pi)

    x1 = x-0.5*width
    y1 = y-0.5*height
    
    x0 = x+0.5*width
    y0 = y1
    
    x2 = x1
    y2 = y+0.5*height

    x3=x0
    y3=y2

    x0n = math.floor((x0 - x)*cosA - (y0 - y)*sinA + x)
    y0n = math.floor((x0 - x)*sinA + (y0 - y)*cosA + y)
    
    x1n = math.floor((x1 - x)*cosA - (y1 - y)*sinA + x)
    y1n = math.floor((x1 - x)*sinA + (y1 - y)*cosA + y)

    x2n = math.floor((x2 - x)*cosA - (y2 - y)*sinA + x)
    y2n = math.floor((x2 - x)*sinA + (y2 - y)*cosA + y)

    x3n = math.floor((x3 - x)*cosA - (y3 - y)*sinA + x)
    y3n = math.floor((x3 - x)*sinA + (y3 - y)*cosA + y)

    cv2.line(canvas,(x0n, y0n),(x1n, y1n), (255, 0, 0))
    cv2.line(canvas,(x1n, y1n),(x2n, y2n), (255, 0, 0))
    cv2.line(canvas,(x2n, y2n),(x3n, y3n), (255, 0, 0))
    cv2.line(canvas,(x0n, y0n),(x3n, y3n), (255, 0, 0))

可以把小车看出一个矩形,小车在轨道上运行时,是需要不断转弯的。由于当时用opencv画的,不知道哪种方法可以直接画旋转矩形(后面知道一种方法可以不断框四个点的最小矩形,也能实现),因此必须自己定义一个。
此处写函数的思路是借鉴大佬的方法写的,稍微改了一下,使它与我的代码更加兼容。

参考 https://blog.csdn.net/u013948010/article/details/78318894

三、定义角度函数

def func_angle(x):
    if x >0 and x<=50:
        ang = 0
    elif x>50 and x<=250:
        ang = -math.floor(math.atan(((400**2-(x-50)**2)**0.5-(400**2-(x-1-50)**2)**0.5))*180/math.pi)
    elif x>=250 and x<=350:
        ang = 30
    elif x>350 and x<=550:
        ang = -math.floor(math.atan((-(400**2-(x-550)**2)**0.5+1100*(3**0.5)/3)-(-(400**2-(x-1-550)**2)**0.5+1100*(3**0.5)/3))*180/math.pi)
    else:
        ang = 0
    return ang

目的使小车在沿轨道运行的过程中能不断的改变角度。

四、定义约束项

def lim(distance):#约束项
    x = 0
    for i in range(8,830):
        if (power_3-i)**2 + (func_2(power_3)-func_2(i))**2 <= (distance+1)**2 and (power_3-i)**2 + (func_2(power_3)-func_2(i))**2 >= (distance-1)**2:
            if i < power_3 and i >= power_3 - 11:
                x = i
    return x

定义这个函数的目的就是使两个小车之间的连杆距离保持不变。

五、一个循环

while True:
    power_4 = power_5-8 #34
    power_3 = power_4-4 #30
    power_2 = lim(10) #20
    power_1 = power_2-4 #16
    power_0 = power_1-8 #8
    power_6 = power_2-8 #12
    power_7 = power_5-4 #38
#建立一个背景画布
    canvas = np.ones((600,800,3),dtype = 'uint8') #dtype选择 uint8 是为了方便显示图像(0-255)
    canvas = canvas*255
#画一条红色直线
    red = (0,0,255) #opencv 里面是BGR顺序,不同于常见的RGB顺序
    cv2.line(canvas,(0,400),(50,400),red)
#画圆
    black = (0,0,0)
    (center0_x,center0_y) = (50,0)
    cv2.ellipse(canvas,(center0_x,center0_y),(400,400),0,60,90,black)
#画直线
    cv2.line(canvas,(250,math.floor(200*(3**0.5))),(350,math.floor(500*(3**0.5)/3)),red)
#画圆
    cv2.ellipse(canvas,(550,math.floor(1100*(3**0.5)/3)),(400,400),0,240,270,black)
#画直线
    cv2.line(canvas,(550,math.floor(1100*(3**0.5)/3)-400),(650,math.floor(1100*(3**0.5)/3)-400),red)
    g = (0,255,0)
    b_g = (255,255,0)
#画移动的圆心
    cv2.circle(canvas,(power_0,func_2(power_0)),1,g,-1)
    cv2.circle(canvas,(power_1,func_2(power_1)),1,g,-1)
    cv2.circle(canvas,(power_2,func_2(power_2)),1,g,-1)
    cv2.circle(canvas,(power_3,func_2(power_3)),1,g,-1)
    cv2.circle(canvas,(power_4,func_2(power_4)),1,g,-1)
    cv2.circle(canvas,(power_5,func_2(power_5)),1,g,-1)
#画移动的杆
    cv2.line(canvas,(power_2,func_2(power_2)),(power_3,func_2(power_3)),b_g,2)
#画移动的矩形
    draw(canvas,(power_6,func_2(power_6),func_angle(power_6),10,20))
    draw(canvas,(power_7,func_2(power_7),func_angle(power_7),10,20))
    cv2.imshow('train_game',canvas)
    power_5 += 1
    key = cv2.waitKey(40)
    if key == ord('1'):
        break
cv2.destroyAllWindows()
#cv2.imwrite('C:\\users\\lenovo\\csdn_dl\\test.png',canvas)

这一部分利用opencv自带的包,通过不断的调用函数,将坐标点导入画弧、直线等方法中。
power_0 power_1 … power_5 代表小车的车轮以及车钩。
power_6 power_7 代表小车的中心。
需要注意的是,opencv中画图的方法需要一个整型,因此函数算出来的坐标都是经过不断向下取整。最后实现起来并不是特别平滑。

以下附上总代码

#导入相关的包
import numpy as np
import cv2
import math
power_5 = 42

#定义坐标点函数
def func_2(x):
    if x>0 and x<=50:
        y = 400
    elif x>50 and x<=250:
        y = math.ceil((400**2-(x-50)**2)**0.5)
    elif x>250 and x<=350:
        y = math.floor(-((3**0.5)*x)/3+850*(3**0.5)/3)
    elif x>350 and x<=550:
        y = math.floor(-(400**2-(x-550)**2)**0.5+1100*(3**0.5)/3)
    else:
        y = math.floor(1100*(3**0.5)/3-400)
    return y

#定义坐标点函数
def func_0(x):
    interval0 = 1 if x>0 and x<=50 else 0
    interval1 = 1 if x>50 and x<250 else 0
    interval2 = 1 if x == 250 else 0
    interval3 = 1 if x>250 and x<=450 else 0
    interval4 = 1 if x>450 and x<=500 else 0
    #y = 500*interval0 + 400*interval1 + 300*interval2 + 200*interval3 + 100*interval4
    y =500*interval0 + ((200**2-(x-50)**2)**0.5+300)*interval1 +300*interval2 + (-(200**2-(x-450)**2)**0.5+250)*interval3 + 50*interval4
    return y

#定义一个画可旋转矩形的方法
def draw(canvas,result):
    result=np.array(result)
    x = result[0]
    y = result[1]
    angle = result[2]
    height = result[3]
    width = result[4]

    angle_Pi = -angle*math.pi/180.0 #转化为弧度
    cosA = math.cos(angle_Pi)
    sinA = math.sin(angle_Pi)

    x1 = x-0.5*width
    y1 = y-0.5*height
    
    x0 = x+0.5*width
    y0 = y1
    
    x2 = x1
    y2 = y+0.5*height

    x3=x0
    y3=y2

    x0n = math.floor((x0 - x)*cosA - (y0 - y)*sinA + x)
    y0n = math.floor((x0 - x)*sinA + (y0 - y)*cosA + y)
    
    x1n = math.floor((x1 - x)*cosA - (y1 - y)*sinA + x)
    y1n = math.floor((x1 - x)*sinA + (y1 - y)*cosA + y)

    x2n = math.floor((x2 - x)*cosA - (y2 - y)*sinA + x)
    y2n = math.floor((x2 - x)*sinA + (y2 - y)*cosA + y)

    x3n = math.floor((x3 - x)*cosA - (y3 - y)*sinA + x)
    y3n = math.floor((x3 - x)*sinA + (y3 - y)*cosA + y)

    cv2.line(canvas,(x0n, y0n),(x1n, y1n), (255, 0, 0))
    cv2.line(canvas,(x1n, y1n),(x2n, y2n), (255, 0, 0))
    cv2.line(canvas,(x2n, y2n),(x3n, y3n), (255, 0, 0))
    cv2.line(canvas,(x0n, y0n),(x3n, y3n), (255, 0, 0))

#定义角度
def func_angle(x):
    if x >0 and x<=50:
        ang = 0
    elif x>50 and x<=250:
        ang = -math.floor(math.atan(((400**2-(x-50)**2)**0.5-(400**2-(x-1-50)**2)**0.5))*180/math.pi)
    elif x>=250 and x<=350:
        ang = 30
    elif x>350 and x<=550:
        ang = -math.floor(math.atan((-(400**2-(x-550)**2)**0.5+1100*(3**0.5)/3)-(-(400**2-(x-1-550)**2)**0.5+1100*(3**0.5)/3))*180/math.pi)
    else:
        ang = 0
    return ang

def lim(distance):#约束项
    x = 0
    for i in range(8,830):
        if (power_3-i)**2 + (func_2(power_3)-func_2(i))**2 <= (distance+1)**2 and (power_3-i)**2 + (func_2(power_3)-func_2(i))**2 >= (distance-1)**2:
            if i < power_3 and i >= power_3 - 11:
                x = i
    return x

while True:
    power_4 = power_5-8 #34
    power_3 = power_4-4 #30
    power_2 = lim(10) #20
    power_1 = power_2-4 #16
    power_0 = power_1-8 #8
    power_6 = power_2-8 #12
    power_7 = power_5-4 #38
#建立一个背景画布
    canvas = np.ones((600,800,3),dtype = 'uint8') #dtype选择 uint8 是为了方便显示图像(0-255)
    canvas = canvas*255
#画一条红色直线
    red = (0,0,255) #opencv 里面是BGR顺序,不同于常见的RGB顺序
    cv2.line(canvas,(0,400),(50,400),red)
#画圆
    black = (0,0,0)
    (center0_x,center0_y) = (50,0)
    cv2.ellipse(canvas,(center0_x,center0_y),(400,400),0,60,90,black)
#画直线
    cv2.line(canvas,(250,math.floor(200*(3**0.5))),(350,math.floor(500*(3**0.5)/3)),red)
#画圆
    cv2.ellipse(canvas,(550,math.floor(1100*(3**0.5)/3)),(400,400),0,240,270,black)
#画直线
    cv2.line(canvas,(550,math.floor(1100*(3**0.5)/3)-400),(650,math.floor(1100*(3**0.5)/3)-400),red)
    g = (0,255,0)
    b_g = (255,255,0)
#画移动的圆心
    cv2.circle(canvas,(power_0,func_2(power_0)),1,g,-1)
    cv2.circle(canvas,(power_1,func_2(power_1)),1,g,-1)
    cv2.circle(canvas,(power_2,func_2(power_2)),1,g,-1)
    cv2.circle(canvas,(power_3,func_2(power_3)),1,g,-1)
    cv2.circle(canvas,(power_4,func_2(power_4)),1,g,-1)
    cv2.circle(canvas,(power_5,func_2(power_5)),1,g,-1)
#画移动的杆
    cv2.line(canvas,(power_2,func_2(power_2)),(power_3,func_2(power_3)),b_g,2)
#画移动的矩形
    draw(canvas,(power_6,func_2(power_6),func_angle(power_6),10,20))
    draw(canvas,(power_7,func_2(power_7),func_angle(power_7),10,20))
    cv2.imshow('train_game',canvas)
    power_5 += 1
    key = cv2.waitKey(40)
    if key == ord('1'):
        break
cv2.destroyAllWindows()
#cv2.imwrite('C:\\users\\lenovo\\csdn_dl\\test.png',canvas)

以下效果图

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值