毕业设计175十字路口车流模拟系统.docx
《毕业设计175十字路口车流模拟系统.docx》由会员分享,可在线阅读,更多相关《毕业设计175十字路口车流模拟系统.docx(21页珍藏版)》请在冰豆网上搜索。
毕业设计175十字路口车流模拟系统
上海交通大学计算机科学与工程系学士论文
十字路口车流模拟系统
系别
计算机科学与工程系
学科专业
计算机科学与技术
研究方向
图形图像
姓名
孙哲
导师
何援军
上海交通大学计算机科学与工程系
2004年6月
摘要
十字路口模拟涉及到图形图像处理与最优控制算法,是一项有着较强应用前景的技术。
一方面可以模拟多个十字路口的交通网,研究总体最佳控制算法;另一方面可以在游戏及虚拟现实中有所应用,如模拟城市就使用到了十字路口模拟的技术。
本项目是实现十字路口模拟的一些基本的功能,只模拟了一个十字路口,单车道,且不涉及智能最优控制算法,而只是一个比较简单的控制算法。
专注于图形图像方面的实现,如何使整个模拟系统尽可能的显得真实。
可以在基于本项目的基础上发展和完善智能最优控制算法,以及交通网,使之达到实际应用的水平。
关键词:
图像合成,移动,红绿灯控制,探测,转弯。
Abstract
Thesimulationofcrossroadsreferstoimageprocessandbestcontrolalgorithmandisatechnologywhichhasgoodpotentialityinapplication.Itcansimulateatrafficnetthatcontainsmanycrossroadstoresearchthebestcontrolalgorithm.ItalsocanbeusedingamessuchasSimCity.
Thisprojectsimulatessomebasicfunctionsofacrossroads,onlyonecrossroads,onelaneanddon’trefertobestcontrolalgorithmbutasimplealgorithm.Itismainlyabouttherealizationofimage:
howtomakewholesystemasreallyasitcan.Someonecandevelopbestcontrolalgorithmandtrafficnetbasisontheprojectinordertomakecanbeuseinapplication.
Keywords:
Integrateimages,move,controloflight,probe,turn.
Catalog
一.概述
二.功能及实现
三.测试
四.小结
五.参考书目
第一部分概述
●项目名称
十字路口车流模拟系统
●功能概述
模拟十字路口车流情况,并用一个红绿灯实现对车流的控制。
汽车在四边的道路末端随机出现,沿着既定方向移动。
在十字路口处如果是红灯,车流会停止等待灯变绿,然后再做出选择;若是绿灯会随机做出3种选择:
小转弯、大转弯或直行。
一辆轿车若检测到前方
有车会自动停下来以免撞车。
车行到路的末端会自动消失。
如此往复形成一个循环,完成对十字路口车流的模拟。
●可控参数
车速;
进入流量(进入车流随机范围),(四个方向);
●
End_7()
(696,100)
DPosition4
(660,100)
总图(PIC1)
End_5()
(960,564)
End_3()
(370,600)
End_2()
(160,302)
APosition1
(160,330)
CPosition2
(960,538)
BPosition3
(400,610)
第二部分功能及实现
●背景图像
背景图像是从模拟城市IV中截得的,十分逼真和美观。
汽车的图像与背景图像的合成,即能完成运动的十字路口模拟。
●图像合成
上图是轿车的图像,尺寸是48*31。
若直接和背景图像合成,会出现如下情况:
此时就需要消去轿车图片中白色的背景转而换成背景图片中的像素。
即所谓的精灵图像合成。
一般用GDI的BitBlt函数方法实现之,叫做光栅操作。
光栅操作一来烦琐,二来效率不是很高,所以在设计中没有采用。
设计中采用的是对内存DC直接操作的方式来合成图像的。
创建两个内存DC,一个放入背景图像,一个放入小车图像。
对小车图像进行逐点循环,若小车图像的当前像素点是白色,则背景图像的对应像素点颜色不变,否则颜色设成小车图像当前点的颜色。
如此便实现了小车图像和背景图像的无缝合成。
具体算法如下:
准备工作
创建BITMAP对象并装入位图资源
获得显示DC的指针
CDC*pDC=GetDC();
创建与显示DC兼容的内存DC:
m_pbackMemDC
m_pbackMemDC->CreateCompatibleDC(pDC);
创建与显示DC兼容的内存DC:
m_pcarMemDC_1
m_pcarMemDC[i]->CreateCompatibleDC(pDC);
backBitmap->m_pbackMemDC
m_pbackMemDC->SelectObject(&backBitmap);
carBitmap->m_pcarMemDC_1
m_pcarMemDC[i]->SelectObject(&carBitmapH);
合并算法
对m_pcarMemDC[i]进行双重循环,遍历每一像素点
Integrate_H(doublex,doubley){
for(inti=0;i<48;i++){
for(intj=0;j<31;j++){
对当前像素点取色
COLORREFcurrentColor=m_pcarMemDC[i]->GetPixel(i,j);
若颜色不是白色
if(currentColor!
=RGB(255,255,255)){
m_pbackMemDC中对应点设为car的颜色(意味着若是白色,则m_pbackMemDC中相应点颜色不变,达到了将白色底色过滤的目的)
m_pbackMemDC->SetPixel(x+i,y+j,currentColor);
}
}
}
获得显示DC的指针
CDC*pDC=GetDC();
红绿灯颜色控制
LightControl();
显示m_pbackMemDC(已被修改过,合成后的图像)
pDC->BitBlt(0,0,m_nMaxX,m_nMaxY,m_pbackMemDC,0,0,SRCCOPY);
释放显示DC
ReleaseDC(pDC);
}
采用了此算法的合成后图像如下图所示:
上述的小车图像是东西向的,南北向马路则要加载如下的小车图像:
尺寸是34*36。
合并算法基本是一样的,只是小车图像的逐点循环稍微改变一下,因为尺寸有所变化:
for(inti=0;i<34;i++){
for(intj=0;j<36;j++){
……
}
}
除此之外,还有些十字路口转弯的小车图像,加载后也只需把循环改变即可,算法的改变都相同。
●定时器
采用了定时器功能,即先设置一个定时器,然后重写OnTimer函数。
功能是每过定时器设定的时间段系统自动调用OnTimer函数一次。
程序中用到定时器的功能是为了每过固定的一段时间重画整个图像。
每下个时间段的红绿灯的状态以及小车的位置都基于上个时间段的状态而得出的。
定时器的具体功能我们将结合每一段路的run函数和红绿灯控制函数描述。
默认的时间段是100ms,时间段其实就是快播倍率,设长一点整个模拟系统就慢,设短一点整个模拟系统就快。
所以可以通过控制时间段的方式来设定快播倍率。
●小车的移动(每条马路的前半段:
1/4/6/8号马路)
在上述的图像合成中用到了Integrate_H函数,当然还有Integrate_V等图像合成函数。
这些函数都有2各参数:
doublex和doubley。
函数参数x和y定位背景图像中的一点,以此点为小车图像的左上顶点加载小车图像。
改变x和y就能改变小车的位置。
配合OnTimer函数,就可以实现小车的移动。
在PIC1中我们可以看到小车只可能从A/B/C/D四个点中的一个出现。
可以测出这些点的坐标:
A(160,330);B(400,610);C(960,538);D(660,100)。
我们定义了两个数组:
intPosition_x[20];
intPosition_y[20];
给Position_x[1]和Position_y[1]赋值:
Position_x[1]=160;
Position_y[1]=330;
如果调用Integrate_H(intPosition_x[20],intPosition_y[20]),小车将在A点显示。
由此可见(intPosition_x[i],intPosition_y[i])就是第i辆小车的位置。
所以说只要改变Position_x[i]和Position_y[i]的值就能改变小车的位置。
我们做如下的改动:
Position_x[1]+=10;
Position_y[1]+=3;
然后再调用Integrate_H(intPosition_x[20],intPosition_y[20]),小车显示的位置便在了A点的前方一点点。
我们都知道动画的原理就是把许多幅图像一幅接一幅地播放,每幅图像都较前一幅有所变化,这样连续播放起来就给人以动画的感觉。
小车移动也是如此。
以第一辆小车并且起始点为A点为例,第一段路的移动算法如下:
系统初始化时设定定时器,以100ms为时间段;
设定Position_x[1]和Position_y[1]的初始值;
Integrate_H(Position_x[1],Position_y[1]);
OnTimer中调用run_1
(1)函数;(不同路段有不同的run函数)
run_1(inti){
若还没到十字路口{
Position_x[i]+=10*speedRate;
Position_y[i]+=3*speedRate;
}
Integrate_H(Position_x[i],Position_y[i]);
}
这只是最基本的一个移动算法,真正的run函数还将添加很多功能。
在此算法中,首先在A点处显示小车,然后每过100ms,因为路是斜的视角,小车向右移动10个像素,再向下移动3个像素,即在路上向前移动了一点。
这样运行起来后,小车的移动就成了一段连续的动画,也即完成了模拟的最基本要求。
speedRate是一个可人为控制的全局变量,即车速。
初始值为1。
若设为2或更大的话,小车每个时间段就会移动更远的距离,从模拟的意义上来说,也就是车速提高了。
这就是人为控制车速的方法。
run_1函数的原型是run_1(inti),参数i代表第i辆小车因为此算法是以第一辆小车为例,所以OnTimer中调用的是run_1
(1)。
这么做的原因是每辆小车有不同的position_x和position_y,不同编号的小车调用的参数也就不一样。
因为本段讨论的是在1/4/6/8号马路上小车的移动,所以也只讨论run_1;run_4;run_6和run_8这四个函数。
算法的基本情况是一致的,只是起始点和Position_x[i]与Position_y[i]的变更算法不一样。
●红绿灯控制
一个十字路口肯定要有红绿灯控制系统,小车行驶到路口后若是绿灯应当通行,若是红灯应当等待。
红绿灯的变化还应当在图像上有所显示。
红绿灯控制也用到了定时器功能,设定的是红灯持续100个时间段,绿灯持续100个时间段,依次往复。
设置全局变量redH和greenH。
redH==1表示东西向马路为红灯,greenH==1表示东西向马路为绿灯。
初始设定为redH=1;greenH=0。
另外设置全局变量Light,初始值为0,每调用OnTimer一次即每过100ms,Light自加一,加到100后设定redH=0,greenH=1即东西向马路为绿灯;加到200后Light回置到0,redH=1,greenH=0即东西向马路为红灯,如此反复。
红绿灯的图像控制即当redH和greenH变化的时候在图像上进行改动,因为背景图像是东西向马路为绿灯,南北向马路为红灯;所以到时间只需将表示东西向的绿灯设为红色,表示南北向的红灯设为绿色即可。
因为每次调用OnTimer内存DC都会重画,所以若是东西向为绿灯则无须改动。
图像控制可以对内存DC进行setPixel操作。
红绿灯控制算法如下:
定义全局变量Light,初始值为0;
每过一时间段调用控制函数LightControl一次;
LightControl(void){
Light++;
if(Light>100&&Light<200){
redH=1;
greenH=0;
内存DC图像修改,将表示东西向的绿灯改成红灯;
内存DC图像修改,将表示南北向的红灯改成绿灯;
}
if(Light==201){
Light回置为0;
greenH=1;
redH=0;
}
}
值得注意的是每过一时间段调用控制函数LightControl一次是在哪里调用。
OnTimer可以,run函数中可以,IntegrateH和IntegrateV也可以。
因为他们都是每过一时间段被执行一次。
下面两幅图演示了红绿灯控制算法的执行情况。
●随机选定直走/小转/大转
小车行驶到十字路口,如果是绿灯,需要进行随机选择直走还是小转或是大转。
定义数组Choice[20]每辆小车对应Choice[i]。
Choice[i]==1:
直走
Choice[i]==2:
小转
Choice[i]==3:
大转
随机算法如下:
random(inti){
srand(time(0));
intresult=1+rand()%999;
Choice[i]=1+result%3;
}
届时可以通过Choice[i]的值选择小车的路线。
●小车的移动(每条马路的后半段:
2/3/5/7号马路)
过了十字路口后,小车将会调用run_2或run_3或run_5或run_7函数,完成后半段马路的行驶,然后消失,接着选择一个起始点重新开始。
后半段马路的run函数十分简单,可以说只需改变Position_x[i]和Position_y[i]就可以了。
以run_5为例,算法如下:
run_5(inti){
Position_x[i]+=10*speedRate;
Position_y[i]+=3*speedRate;
Integrate_H(Position_x[i],Position_y[i]);
//Positioni循环
End_5();
}
在小车行驶到道路末尾时,需要调用End函数以使小车选择一个起始点重新开始行驶。
2/3/5/7号马路有着不同的End函数,但基本算法是一样的,即当小车到了道路末端后,Position_x[i]和Position_y[i]改变到A,B,B,D四个起始点中的一个。
另外利用一个已有的全局数组Choice[20]表示小车的状态,当Choice[i]==0时,表示小车重新开始行驶,应调用前半段马路的run函数。
以End_5为例:
End_5(inti){
if(Position_x[i]>960){
Position_x[i]=160;
Position_y[i]=330;
Choice[i]=0;
}
}
如此便实现了小车的循环。
●小车的转弯
小车在十字路口会有2种转弯方式:
小转弯和大转弯。
四个出口共计8种转弯方式,分别对应8个转弯函数。
但算法的本质都是相同的,即调用一系列图像,完毕后再调用进入路段对应的run函数。
转弯函数很简单,和移动时的run函数原理一样,都是调用一系列的图像合成函数使小车在屏幕上显示出动画的转弯效果。
转弯时重要的一点是防止撞车,这在下面探测中会详细叙述。
●探测
人在开车时都会注意四面八方以免造成事故,此模拟系统也是。
若不对小车加以限制,难免会造成撞车的情况,所以需要给每辆小车装备一个探测装置。
探测装置的功能很简单,就是探测前方一定距离内是否有车辆,如果有的话,就停下来,等到前方车辆行驶了再启动。
探测装置在两个地方有用,一是等红灯时,后面的汽车应当停在前面汽车的后面而不是撞上去;还有在十字路口中间更是需要,否则会一团乱麻。
探测装置原理很简单。
因为Position_x[i]和Position_y[i]设定了小车的位置,所以只要比较当前小车的位置和其他小车的位置便可得出结论。
因为共有4个方向,所以有四个探测函数,当然算法本质都是一样的。
算法简要描述:
当前小车Position_x[i]和Position_y[i]
上图是以西->东马路为例。
如上图,我们知道当前小车Position_x[i]和Position_y[i]和马路的斜率,便可以虚拟出图中虚线矩形。
很容易理解,在进行Position_x和Position_y循环的时候,如果有某一对Position_x和Position_y在虚线矩形范围内,说明前面有车。
虚线矩形的范围很容易确定。
小车bitmap的尺寸是48*31,则虚线矩形的顶点坐标为:
A(Position_x[i]+48,Position_y[i]+15);
B(Position_x[i]+96,Position_y[i]+15);
C(Position_x[i]+96,Position_y[i]+46);
D(Position_x[i]+48,Position_y[i]+46)。
十字路口处的探测要复杂些,我们把十字路口分成4大块,如下图。
因为小转弯总要经过A、B、C、D中的一个,而大转弯要经过其中的两个。
总体原则就是小转弯要检测器要经过的方形中是否有车辆,而大转弯则要检测两次。
小车若从1号路段转到3号路段,便要检测方形区域C中是否有车辆;而小车若从1号路段转到7号路段,则需先检测C中是否有车辆,若没有进入C,然后再检测B中是否有车辆,若没有则进入B,然后就进入了7号路段。
值得注意的是,在有很多小车等着过十字路口的时候,我们必须解决一个优先级的问题。
优先级的设定是这样的:
小转弯>直行>大转弯。
例如2辆小车,小车a要从1号路段转到7号路段,小车b要从6号路段转到7号路段。
因为小转弯的优先级大于大转弯,所以a先进入C,但不能进入B,要等b车从区域B中驶出进入路段7后才能进入区域B,随后也进入路段7。
利用上述的优先级便可以实现十字路口的防止撞车控制。
因为小车在转弯的时候不使用Position_x[i]和Position_y[i]来表示位置,所以设置全局变量boolbeA,beB,beC,beD;若是某个区域内有车,则相应的变量设为false,没有车时为true。
例如A区域内有车,beA的值设为false。
这样可以通过这四个变量实现探测,控制转弯。
●多辆小车
当我们实现了一辆小车后,实现多辆小车就是很简单的事情了。
●run函数的最终版本
上文所述的run函数只是实现了最简单的移动功能,一个完整的run函数还应当整合探测功能与路口处等待或是选择功能。
完整的run函数算法如下,以run_1为例:
run_1(inti){
//探测前方是否有车
intbeCar=Probe_15(Position_x[i],Position_y[i]);
//如果有车,停止行驶
if(beCar==0){
Position_x[i]+=0;
Position_y[i]+=0;
}
//如果车在路口且是红灯,停止行驶
if(redH==1&&Position_x[i]>=420&&Position_x[i]<425){
Position_x[i]+=0;
Position_y[i]+=0;
}
//没到路口,正常行驶
elseif(Position_x[i]<420){
Position_x[i]+=10*speedRate;
Position_y[i]+=3*speedRate;
}
//在路口且是绿灯,选择路线
elseif(greenH==1&&Position_x[i]>=420&&Position_x[i]<425){
//调用转向选择函数
intchoice=random_1();
//直走
if(choice==1)
choice_1=1;
//小转
elseif(choice==2)
choice_1=2;
//大转
elseif(choice==3)
choice_1=3;
}
//画图
Integrate_H(Position_x[i],Position_y[i]);
}
第三部分测试
完成整个编码后,我们需要测试整个系统。
程序运行后,一切正常。
小车从A、B、C、D四个位置随机出现,按设定的车速行驶。
在十字路口若是红灯则停下来等待,后面的车会停在前面的车后面而不会发生撞车。
绿灯时小车会随机直行或小转或大转。
在十字路口处的小车严格遵守优先级——小转弯>直行>大转弯,井然有序,不会发生撞车。
通过十字路口后每辆小车继续后半段的旅程,直到道路末端,消失,然后重新开始。
调整快播倍率,可以看到整个系统像快镜头或慢镜头似的在运行;调整车速,发现小车行驶速度加快或减慢。
一切符合要求。
第四部分小结
总的来说,程序运行的结果基本达到了预先的设想,一些基本的功能都有所实现。
通过此次项目的开发,使我掌握了一些图像方面的基本技术。
不足的是红绿灯控制算法还没有智能化,不过只要对程序加以改进,就可以实现更加复杂的算法,或是模拟多个十字路口的交通网。
虽然我只是掌握了一些皮毛,但是我相信模拟技术是一门很有前途的技术,我希望今后能有机会在这方面深入研究。
第五部分参考资料
[1]R.Agrawal,T.Imielinski,andA.Swami.Miningassociationrulesbetweensetsofitemsinlargedatabases.InProc.oftheACMSIGMODConferenceonManagementofData,pages207–216,1993.
[2]R.Agrawal,H.Mannila,R.Srikant,H.Toivonen,andA.I.Verkamo.Fastdiscoveryofassociationrules.InAdvancesinKnowledgeDiscoveryandDataMining,pages307–328,1996.
[3]R.AgrawalandR.Srikant.Fastalgorithmsformininga