图像拼接实现见:
OpenCV源码系列|图像拼接1
OpenCV源码系列|图像拼接2
耗时在调用函数:
Mat pano; Ptr stitcher = Stitcher::create(mode); Stitcher::Status status = stitcher->stitch(imgs, pano)
能否将这一步放进线程池里进行加速呢?
1. 测试函数:
#include "t.h"#include #include #include #include #include #include #include #include"opencv2/imgproc/imgproc.hpp"#include "opencv2/imgcodecs.hpp"#include "opencv2/stitching.hpp"#include "omp.h"using namespace cv;using namespace std;Mat img=imread("./1.png");//线程池初始化void threadpool_init(threadpool_t *pool, int threads);//往线程池中加入任务void threadpool_add_task(threadpool_t *pool, void *(*run)(void *arg), void *arg);//摧毁线程池void threadpool_destroy(threadpool_t *pool);bool divide_images = false;Stitcher::Mode mode = Stitcher::PANORAMA;vector imgs;string result_name = "result.jpg";void printUsage(char** argv);int parseCmdArgs(int argc, char** argv);//任意添加自己的代码实现void* mytask(void *arg){ clock_t start,end; start=clock(); Mat pano; Ptr stitcher = Stitcher::create(mode); Stitcher::Status status = stitcher->stitch(imgs, pano); if (status != Stitcher::OK) { cout << "Can't stitch images, error code = " << int(status) << endl; exit(0); } imwrite(result_name, pano); cout << "stitching completed successfully\n" << result_name << " saved!"; free(arg); end=clock(); cout<<"图像拼接时间: "<double)(end-start)/CLOCKS_PER_SEC<< return NULL;}//测试代码int main(int argc, char* argv[]){ clock_t start,end; start=clock(); int retval = parseCmdArgs(argc, argv); if (retval) return EXIT_FAILURE; threadpool_t pool; //初始化线程池,最多三个线程 threadpool_init(&pool, 10); // int i; //创建十个任务 //for(i=0; i < 10; i++) // { int *arg = new int((sizeof(int))); *arg = 0; threadpool_add_task(&pool, mytask, arg); // } threadpool_destroy(&pool); end=clock(); cout<<"多线程运行时间: "<double)(end-start)/CLOCKS_PER_SEC<< return EXIT_SUCCESS; //return 0;}void printUsage(char** argv){ cout << "Images stitcher.\n\n" << "Usage :\n" << argv[0] <<" [Flags] img1 img2 [...imgN]\n\n" "Flags:\n" " --d3\n" " internally creates three chunks of each image to increase stitching success\n" " --mode (panorama|scans)\n" " Determines configuration of stitcher. The default is 'panorama',\n" " mode suitable for creating photo panoramas. Option 'scans' is suitable\n" " for stitching materials under affine transformation, such as scans.\n" " --output \n" " The default is 'result.jpg'.\n\n" "Example usage :\n" << argv[0] << " --d3 --try_use_gpu yes --mode scans img1.jpg img2.jpg\n";}int parseCmdArgs(int argc, char** argv){ clock_t start,end; start=clock(); if (argc == 1) { printUsage(argv); return EXIT_FAILURE; } for (int i = 1; i < argc; ++i) { //查看帮助 if (string(argv[i]) == "--help" || string(argv[i]) == "/?") { printUsage(argv); return EXIT_FAILURE; } //在像素较大时候,开启这个模式 else if (string(argv[i]) == "--d3") { divide_images = true; } else if (string(argv[i]) == "--output") { result_name = argv[i + 1]; i++; } else if (string(argv[i]) == "--mode") { //仅仅是重叠度高的可用 if (string(argv[i + 1]) == "panorama") mode = Stitcher::PANORAMA; //实际测试 scans 模式比 panorama 适用范围更为广泛 else if (string(argv[i + 1]) == "scans") mode = Stitcher::SCANS; else { cout << "Bad --mode flag value\n"; return EXIT_FAILURE; } i++; } else { //终端读取一系列图片 Mat img = imread(argv[i]); if (img.empty()) { cout << "Can't read image '" << argv[i] << "'\n"; return EXIT_FAILURE; } //对图片进行裁剪 if (divide_images) { Rect rect(0, 0, img.cols / 2, img.rows); imgs.push_back(img(rect).clone()); rect.x = img.cols / 3; imgs.push_back(img(rect).clone()); rect.x = img.cols / 2; imgs.push_back(img(rect).clone()); } else imgs.push_back(img); } } end=clock(); cout<<"图像读取时间: "<double)(end-start)/CLOCKS_PER_SEC<< return EXIT_SUCCESS;}
线程池对应的定义与实现
2. c.h
#ifndef _CONDITION_H_#define _CONDITION_H_#include //封装一个互斥量和条件变量作为状态typedef struct condition{ pthread_mutex_t pmutex; pthread_cond_t pcond;}condition_t;//对状态的操作函数int condition_init(condition_t *cond);int condition_lock(condition_t *cond);int condition_unlock(condition_t *cond);int condition_wait(condition_t *cond);int condition_timedwait(condition_t *cond, const struct timespec *abstime);int condition_signal(condition_t* cond);int condition_broadcast(condition_t *cond);int condition_destroy(condition_t *cond);#endif
3. c.cpp
#include "c.h"//初始化int condition_init(condition_t *cond){ int status; if((status = pthread_mutex_init(&cond->pmutex, NULL))) return status; if((status = pthread_cond_init(&cond->pcond, NULL))) return status; return 0;}//加锁int condition_lock(condition_t *cond){ return pthread_mutex_lock(&cond->pmutex);}//解锁int condition_unlock(condition_t *cond){ return pthread_mutex_unlock(&cond->pmutex);}//等待int condition_wait(condition_t *cond){ return pthread_cond_wait(&cond->pcond, &cond->pmutex);}//固定时间等待int condition_timedwait(condition_t *cond, const struct timespec *abstime){ return pthread_cond_timedwait(&cond->pcond, &cond->pmutex, abstime);}//唤醒一个睡眠线程int condition_signal(condition_t* cond){ return pthread_cond_signal(&cond->pcond);}//唤醒所有睡眠线程int condition_broadcast(condition_t *cond){ return pthread_cond_broadcast(&cond->pcond);}//释放int condition_destroy(condition_t *cond){ int status; if((status = pthread_mutex_destroy(&cond->pmutex))) return status; if((status = pthread_cond_destroy(&cond->pcond))) return status; return 0;}
4. t.h
#ifndef _THREAD_POOL_H_#define _THREAD_POOL_H_//线程池头文件#include "c.h"//封装线程池中的对象需要执行的任务对象typedef struct task{ void *(*run)(void *args); //函数指针,需要执行的任务 void *arg; //参数 struct task *next; //任务队列中下一个任务}task_t;//下面是线程池结构体typedef struct threadpool{ condition_t ready; //状态量 task_t *first; //任务队列中第一个任务 task_t *last; //任务队列中最后一个任务 int counter; //线程池中已有线程数 int idle; //线程池中kongxi线程数 int max_threads; //线程池最大线程数 int quit; //是否退出标志}threadpool_t;//线程池初始化void threadpool_init(threadpool_t *pool, int threads);//往线程池中加入任务void threadpool_add_task(threadpool_t *pool, void *(*run)(void *arg), void *arg);//摧毁线程池void threadpool_destroy(threadpool_t *pool);#endif
5. t.cpp
#include "t.h"#include #include #include #include #include //创建的线程执行void *thread_routine(void *arg){ struct timespec abstime; int timeout; printf("thread %d is starting\n", (int)pthread_self()); threadpool_t *pool = (threadpool_t *)arg; while(1) { timeout = 0; //访问线程池之前需要加锁 condition_lock(&pool->ready); //空闲 pool->idle++; //等待队列有任务到来 或者 收到线程池销毁通知 while(pool->first == NULL && !pool->quit) { //否则线程阻塞等待 printf("thread %d is waiting\n", (int)pthread_self()); //获取从当前时间,并加上等待时间, 设置进程的超时睡眠时间 clock_gettime(CLOCK_REALTIME, &abstime); abstime.tv_sec += 2; int status; status = condition_timedwait(&pool->ready, &abstime); //该函数会解锁,允许其他线程访问,当被唤醒时,加锁 if(status == ETIMEDOUT) { printf("thread %d wait timed out\n", (int)pthread_self()); timeout = 1; break; } } pool->idle--; if(pool->first != NULL) { //取出等待队列最前的任务,移除任务,并执行任务 task_t *t = pool->first; pool->first = t->next; //由于任务执行需要消耗时间,先解锁让其他线程访问线程池 condition_unlock(&pool->ready); //执行任务 t->run(t->arg); //执行完任务释放内存 free(t); //重新加锁 condition_lock(&pool->ready); } //退出线程池 if(pool->quit && pool->first == NULL) { pool->counter--;//当前工作的线程数-1 //若线程池中没有线程,通知等待线程(主线程)全部任务已经完成 if(pool->counter == 0) { condition_signal(&pool->ready); } condition_unlock(&pool->ready); break; } //超时,跳出销毁线程 if(timeout == 1) { pool->counter--;//当前工作的线程数-1 condition_unlock(&pool->ready); break; } condition_unlock(&pool->ready); } printf("thread %d is exiting\n", (int)pthread_self()); return NULL;}//线程池初始化void threadpool_init(threadpool_t *pool, int threads){ condition_init(&pool->ready); pool->first = NULL; pool->last =NULL; pool->counter =0; pool->idle =0; pool->max_threads = threads; pool->quit =0;}//增加一个任务到线程池void threadpool_add_task(threadpool_t *pool, void *(*run)(void *arg), void *arg){ //产生一个新的任务 task_t *newtask = (task_t *)malloc(sizeof(task_t)); newtask->run = run; newtask->arg = arg; newtask->next=NULL;//新加的任务放在队列尾端 //线程池的状态被多个线程共享,操作前需要加锁 condition_lock(&pool->ready); if(pool->first == NULL)//第一个任务加入 { pool->first = newtask; } else { pool->last->next = newtask; } pool->last = newtask; //队列尾指向新加入的线程 //线程池中有线程空闲,唤醒 if(pool->idle > 0) { condition_signal(&pool->ready); } //当前线程池中线程个数没有达到设定的最大值,创建一个新的线性 else if(pool->counter < pool->max_threads) { pthread_t tid; pthread_create(&tid, NULL, thread_routine, pool); pool->counter++; } //结束,访问 condition_unlock(&pool->ready);}//线程池销毁void threadpool_destroy(threadpool_t *pool){ //如果已经调用销毁,直接返回 if(pool->quit) { return; } //加锁 condition_lock(&pool->ready); //设置销毁标记为1 pool->quit = 1; //线程池中线程个数大于0 if(pool->counter > 0) { //对于等待的线程,发送信号唤醒 if(pool->idle > 0) { condition_broadcast(&pool->ready); } //正在执行任务的线程,等待他们结束任务 while(pool->counter) { condition_wait(&pool->ready); } } condition_unlock(&pool->ready); condition_destroy(&pool->ready);}
6. 显示: