在第一阶段对视觉的框架有了大致的了解,下一步就是在各大战队开源的代码上进行学习,虽然看见很多队伍都用qt但是我这边不会用,还是在vs code上写吧
然后先学习一下多线程:
多线程
1.定义
先说一下进程:
进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。在早期面向进程设计的计算机结构中,进程是程序的基本执行实体;在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的实体。
简单来说就是:程序执行产生进程,然后进程中又有线程。
并发:cpu会在极短的时间内作用于几个进程,在人看在是同时发生的,单核
并行:同时发生,多核
同步:阻止同时发生,类似锁
异步:事件的独立性
多线程优势:提高效率,模块化
2.线程的操作
线程id:
标识符:pthread_t XXX
获取线程id:pthread_self()
创造线程:
pthread_created()
参数1:线程id,
参数2:属性
参数3:回调函数
参数4:回调函数的参数
成功返回0
线程回收
pthread_join()
参数1:对象
参数2:二级指针接受返回值
这里如果该线程没有结束的话就会堵塞这个线程
线程结束
pthread _exit()
参数可以通过上面join那个获得
3.其他
线程中通信
线程都可以访问全局变量,但是多个线程访问数据的时候需要同步和互斥机制
同步
多个任务按一定顺序完成一个事情
信号量
其值代表资源的数量
初始化,p(申请资源)与v(释放资源)操作
初始化:sem_init()
参数:1.sem_t *sem 定义对象取地址 2.0 表示线程 3. 初值
成功返回0
p操作::sem_wait(sem_t *sem)
v操作:sem_post(sem_t *sem )
互斥量
就是对一个要访问的数据上锁,然后当线程访问到这个数据的时候就会阻塞。
初始化:pthread_mutex_init(pthread_mutex_t XX,NULL)
摧毁:thread_mutex_destroy()
条件变量
表示如果互斥量被锁住后仍无法完成任务,那么就要释放互斥量让其他线程工作
初始化:pthread_cond_init(pthread_cond_t XX,NULL)
摧毁:thread_cond_destroy()
Cmake
然后学习一下cmake的细节:
aux_source_directory(./ DIR_SRCS)
add_executable(demo ${DIR_SRCS})
这个我开始学的时候没想过,但现在一看确实很有用,第一行就是将该目录下的所有原文件打包 放到一个变量里,第二行把这个变量作为依赖,这样就不用一个个去手写了
还有一个工程就是不会只有一个makelists.txt文件的,要后写底层的
aux_source_directory(./ DIR_LIB_SRCS)
add_library(Mylib STATIC ${DIR_LIB_SRCS}) 这个是将通过依赖项生成静态库给底层使用 ,然后这个里面写这两个就可以了,底层的需要写的 多点,版本,项目
然后需要在项目中加入子目录:
add_subdirectory(./mylib)
添加链接库(在顶层生成的)
target_link_libraries(demo Mylib)
然后总结一下:就是先写顶层的cmakelists.txt,要生成的静态库文件,然后书写顶层的cmakelists.txt文件,要加入子目录和链接库,表明版本和项目,生成的文件
然后说下标准的工程是什么样的:
有src:放置源文件,build:放置编译文件,bin:放置生成文件
这里有个添加头文件路径:include_directories($(PROJECT_SOURCE_DIR)/mylib) 那个表示根目录
打算先借鉴一下吉大的代码,他们说准确率达到了98%。。。那来吧。
最集成的是有三个文件,放到了main文件夹下,然后有两个线程的话就是要有函数,这里是将线程单独出来了,我也不是很理解,那么我就将他们和成一个里去。但是可能有点长。相机获取那个我没有加,因为我没有相机,然后一步步说下这些代码:
pthread_t thread1;
pthread_t thread2;
// muti-threads control variables
pthread_mutex_t Globalmutex; // threads conflict due to image-updating
pthread_cond_t GlobalCondCV; // threads conflict due to image-updating
bool imageReadable = false; // threads conflict due to image-updating
Mat src = Mat::zeros(600,800,CV_8UC3); // Transfering buffer
int main(int argc, char** argv)
{
//For MutiTHread
XInitThreads();
//Init mutex
pthread_mutex_init(&Globalmutex,NULL);
//Init cond
pthread_cond_init(&GlobalCondCV,NULL);
//Create thread 1 -- image acquisition thread
//pthread_create(&thread1,NULL,imageUpdatingThread,NULL);
//Create thread 2 -- armor Detection thread
pthread_create(&thread2,NULL,armorDetectingThread,NULL);
//Wait for children thread
//pthread_join(thread1,NULL);
pthread_join(thread2,NULL);
pthread_mutex_destroy(&Globalmutex);
return 0;
}
这里先定义了两个线程对象,然后定了互斥量和条件变量,然后看主函数的内容,第一行我也不太清楚,然后两布为初始化,然后创建线程,里面有个回调函数我们一会看,
然后那个函数是为了等待上一个线程结束,最后释放互斥量,下一步说说这个回调函数。
//import armor detector
ArmorDetector detector;
//import angle solver
AngleSolver angleSolver;
int targetNum = 2;
Color ENEMYCOLOR = BLUE;
bool bRun = true;
double fps;
void* armorDetectingThread(void* PARAM)
{
//Set armor detector prop
detector.loadSVM("/home/mountain/Git/JLURoboVision/General/123svm.xml");
//Set angle solver prop
angleSolver.setCameraParam("/home/mountain/Git/JLURoboVision/General/camera_params.xml", 1);
angleSolver.setArmorSize(SMALL_ARMOR,135,125);
angleSolver.setArmorSize(BIG_ARMOR,230,127);
angleSolver.setBulletSpeed(15000);
usleep(1000000);
double t,t1;
do
{
// FPS
t = getTickCount();
detector.setEnemyColor(ENEMYCOLOR); //here set enemy color
//consumer gets image
pthread_mutex_lock(&Globalmutex);
while (!imageReadable) {
pthread_cond_wait(&GlobalCondCV,&Globalmutex);
}
detector.setImg(src);
imageReadable = false;
pthread_mutex_unlock(&Globalmutex);
//装甲板检测识别子核心集成函数
detector.run(src);
//给角度解算传目标装甲板值的实例
double yaw=0,pitch=0,distance=0;
Point2f centerPoint;
if(detector.isFoundArmor())
{
vector<Point2f> contourPoints;
ArmorType type;
detector.getTargetInfo(contourPoints, centerPoint, type);
angleSolver.getAngle(contourPoints,centerPoint,SMALL_ARMOR,yaw,pitch,distance);
}
//串口在此获取信息 yaw pitch distance,同时设定目标装甲板数字
Serial(yaw,pitch,true,detector.isFoundArmor());
//操作手用,实时设置目标装甲板数字
detector.setTargetNum(targetNum);
//FPS
t1=(getTickCount()-t)/getTickFrequency();
printf("Armor Detecting FPS: %f\n",1/t1);
if(detector.isFoundArmor()){
printf("Found Target! Center(%d,%d)\n",centerPoint.x,centerPoint.y);
cout<<"Yaw: "<<yaw<<"Pitch: "<<pitch<<"Distance: "<<distance<<endl;
}
#ifdef DEBUG_MODE
//********************** DEGUG **********************//
//装甲板检测识别调试参数是否输出
//param:
// 1.showSrcImg_ON, 是否展示原图
// 2.bool showSrcBinary_ON, 是否展示二值图
// 3.bool showLights_ON, 是否展示灯条图
// 4.bool showArmors_ON, 是否展示装甲板图
// 5.bool textLights_ON, 是否输出灯条信息
// 6.bool textArmors_ON, 是否输出装甲板信息
// 7.bool textScores_ON 是否输出打击度信息
// 1 2 3 4 5 6 7
detector.showDebugInfo(1, 1, 1, 1, 0, 0, 0);
if(detector.isFoundArmor())
{
//角度解算调试参数是否输出
//param:
// 1.showCurrentResult, 是否展示当前解算结果
// 2.bool showTVec, 是否展示目标坐标
// 3.bool showP4P, 是否展示P4P算法计算结果
// 4.bool showPinHole, 是否展示PinHole算法计算结果
// 5.bool showCompensation, 是否输出补偿结果
// 6.bool showCameraParams 是否输出相机参数
// 1 2 3 4 5 6
angleSolver.showDebugInfo(1, 0, 0, 0, 0, 0);
}
char chKey = waitKey(1);
switch (chKey) {
case '1':
targetNum = 1;
break;
case '2':
targetNum = 2;
break;
case '3':
targetNum = 3;
break;
case 'b':
case 'B':
ENEMYCOLOR = BLUE;
break;
case 'r':
case 'R':
ENEMYCOLOR = RED;
break;
case 'q':
case 'Q':
case 27:
bRun = false;
break;
default:
break;
}
#endif
} while (bRun);
}
这个里面涉及的事就多了,一步步看吧:
哎这里它定义了2个类的对象,可以先看(二)(三)在来看这里的东西!
参考:https://github.com/QunShanHe/JLURoboVision#%E8%BF%90%E8%A1%8C%E5%B9%B3%E5%8F%B0%E6%90%AD%E5%BB%BA