rm记录第二阶段(一):多线程,cmake,吉大代码主函数解析(一)

在第一阶段对视觉的框架有了大致的了解,下一步就是在各大战队开源的代码上进行学习,虽然看见很多队伍都用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

上一篇:杨亦涛老师分享SEO的概念,分类,应用和职位


下一篇:python语法基础-并发编程-线程-其他