一个openMP编程处理图像的示例
一个openMP编程处理图像的示例:
从硬盘读入两幅图像,对这两幅图像分别提取特征点,特征点匹配,最后将图像与匹配特征点画出来。理解该例子需要一些图像处理的基本知识,我不在此详细介绍。另外,编译该例需要opencv,我用的版本是2.3.1,关于opencv的安装与配置也不在此介绍。我们首先来看传统串行编程的方式。

1 #include "opencv2/highgui/highgui.hpp"
2 #include "opencv2/features2d/features2d.hpp"
3 #include <iostream>
4 #include <omp.h>
5 int main( ){
6 cv::SurfFeatureDetector detector( 400 );
7 cv::SurfDescriptorExtractor extractor;
8 cv::BruteForceMatcher<cv::L2<float> > matcher;
9 std::vector< cv::DMatch > matches;
10 cv::Mat im0,im1;
11 std::vector<cv::KeyPoint> keypoints0,keypoints1;
12 cv::Mat descriptors0, descriptors1;
13 double t1 = omp_get_wtime( );
14 //先处理第一幅图像
15 im0 = cv::imread("rgb0.jpg", CV_LOAD_IMAGE_GRAYSCALE );
16 detector.detect( im0, keypoints0);
17 extractor.compute( im0,keypoints0,descriptors0);
18 std::cout<<"find "<<keypoints0.size()<<"keypoints in im0"<<std::endl;
19 //再处理第二幅图像
20 im1 = cv::imread("rgb1.jpg", CV_LOAD_IMAGE_GRAYSCALE );
21 detector.detect( im1, keypoints1);
22 extractor.compute( im1,keypoints1,descriptors1);
23 std::cout<<"find "<<keypoints1.size()<<"keypoints in im1"<<std::endl;
24 double t2 = omp_get_wtime( );
25 std::cout<<"time: "<<t2-t1<<std::endl;
26 matcher.match( descriptors0, descriptors1, matches );
27 cv::Mat img_matches;
28 cv::drawMatches( im0, keypoints0, im1, keypoints1, matches, img_matches );
29 cv::namedWindow("Matches",CV_WINDOW_AUTOSIZE);
30 cv::imshow( "Matches", img_matches );
31 cv::waitKey(0);
32 return 1;
33 }

很明显,读入图像,提取特征点与特征描述子这部分可以改为并行执行,修改如下:

1 #include "opencv2/highgui/highgui.hpp"
2 #include "opencv2/features2d/features2d.hpp"
3 #include <iostream>
4 #include <vector>
5 #include <omp.h>
6 int main( ){
7 int imNum = 2;
8 std::vector<cv::Mat> imVec(imNum);
9 std::vector<std::vector<cv::KeyPoint>>keypointVec(imNum);
10 std::vector<cv::Mat> descriptorsVec(imNum);
11 cv::SurfFeatureDetector detector( 400 ); cv::SurfDescriptorExtractor extractor;
12 cv::BruteForceMatcher<cv::L2<float> > matcher;
13 std::vector< cv::DMatch > matches;
14 char filename[100];
15 double t1 = omp_get_wtime( );
16 #pragma omp parallel for
17 for (int i=0;i<imNum;i++){
18 sprintf(filename,"rgb%d.jpg",i);
19 imVec[i] = cv::imread( filename, CV_LOAD_IMAGE_GRAYSCALE );
20 detector.detect( imVec[i], keypointVec[i] );
21 extractor.compute( imVec[i],keypointVec[i],descriptorsVec[i]);
22 std::cout<<"find "<<keypointVec[i].size()<<"keypoints in im"<<i<<std::endl;
23 }
24 double t2 = omp_get_wtime( );
25 std::cout<<"time: "<<t2-t1<<std::endl;
26 matcher.match( descriptorsVec[0], descriptorsVec[1], matches );
27 cv::Mat img_matches;
28 cv::drawMatches( imVec[0], keypointVec[0], imVec[1], keypointVec[1], matches, img_matches );
29 cv::namedWindow("Matches",CV_WINDOW_AUTOSIZE);
30 cv::imshow( "Matches", img_matches );
31 cv::waitKey(0);
32 return 1;
33 }

两种执行方式做比较,时间为:2.343秒v.s. 1.2441秒
在上面代码中,为了改成适合#pragma omp parallel for执行的方式,我们用了STL的vector来分别存放两幅图像、特征点与特征描述子,但在某些情况下,变量可能不适合放在vector里,此时应该怎么办呢?这就要用到openMP的另一个工具,section,代码如下:

1 #include "opencv2/highgui/highgui.hpp"
2 #include "opencv2/features2d/features2d.hpp"
3 #include <iostream>
4 #include <omp.h>
5 int main( ){
6 cv::SurfFeatureDetector detector( 400 ); cv::SurfDescriptorExtractor extractor;
7 cv::BruteForceMatcher<cv::L2<float> > matcher;
8 std::vector< cv::DMatch > matches;
9 cv::Mat im0,im1;
10 std::vector<cv::KeyPoint> keypoints0,keypoints1;
11 cv::Mat descriptors0, descriptors1;
12 double t1 = omp_get_wtime( );
13 #pragma omp parallel sections
14 {
15 #pragma omp section
16 {
17 std::cout<<"processing im0"<<std::endl;
18 im0 = cv::imread("rgb0.jpg", CV_LOAD_IMAGE_GRAYSCALE );
19 detector.detect( im0, keypoints0);
20 extractor.compute( im0,keypoints0,descriptors0);
21 std::cout<<"find "<<keypoints0.size()<<"keypoints in im0"<<std::endl;
22 }
23 #pragma omp section
24 {
25 std::cout<<"processing im1"<<std::endl;
26 im1 = cv::imread("rgb1.jpg", CV_LOAD_IMAGE_GRAYSCALE );
27 detector.detect( im1, keypoints1);
28 extractor.compute( im1,keypoints1,descriptors1);
29 std::cout<<"find "<<keypoints1.size()<<"keypoints in im1"<<std::endl;
30 }
31 }
32 double t2 = omp_get_wtime( );
33 std::cout<<"time: "<<t2-t1<<std::endl;
34 matcher.match( descriptors0, descriptors1, matches );
35 cv::Mat img_matches;
36 cv::drawMatches( im0, keypoints0, im1, keypoints1, matches, img_matches );
37 cv::namedWindow("Matches",CV_WINDOW_AUTOSIZE);
38 cv::imshow( "Matches", img_matches );
39 cv::waitKey(0);
40 return 1;
41 }

上面代码中,我们首先用#pragma omp parallel sections将要并行执行的内容括起来,在它里面,用了两个#pragma omp section,每个里面执行了图像读取、特征点与特征描述子提取。将其简化为伪代码形式即为:

1 #pragma omp parallel sections
2 {
3 #pragma omp section
4 {
5 function1();
6 }
7 #pragma omp section
8 {
9 function2();
10 }
11 }

意思是:parallel sections里面的内容要并行执行,具体分工上,每个线程执行其中的一个section,如果section数大于线程数,那么就等某线程执行完它的section后,再继续执行剩下的section。在时间上,这种方式与人为用vector构造for循环的方式差不多,但无疑该种方式更方便,而且在单核机器上或没有开启openMP的编译器上,该种方式不需任何改动即可正确编译,并按照单核串行方式执行。
以上分享了这两天关于openMP的一点学习体会,其中难免有错误,欢迎指正。另外的一点疑问是,看到各种openMP教程里经常用到private,shared等来修饰变量,这些修饰符的意义和作用我大致明白,但在我上面所有例子中,不加这些修饰符似乎并不影响运行结果,不知道这里面有哪些讲究。
在写上文的过程中,参考了包括以下两个网址在内的多个地方的资源,不再一 一列出,在此一并表示感谢。
一个openMP编程处理图像的示例的更多相关文章
- openMP编程(上篇)之指令和锁
openMP简介 openMP是一个编译器指令和库函数的集合,主要是为共享式存储计算机上的并行程序设计使用的. 当计算机升级到多核时,程序中创建的线程数量需要随CPU核数变化,如在CPU核数超过线程数 ...
- openMP编程(上篇)之并行程序设计
openMP简介 openMP是一个编译器指令和库函数的集合,主要是为共享式存储计算机上的并行程序设计使用的. 当计算机升级到多核时,程序中创建的线程数量需要随CPU核数变化,如在CPU核数超过线程数 ...
- cesium编程中级(一)添加示例到Sandcastle
cesium编程中级(一)添加示例到Sandcastle 添加示例到Sandcastle在cesium编程入门(七)3D Tiles,模型旋转中提到过,这里是一份完整的说明 创建例子 开启node服务 ...
- 推荐一个算法编程学习中文社区-51NOD【算法分级,支持多语言,可在线编译】
最近偶尔发现一个算法编程学习的论坛,刚开始有点好奇,也只是注册了一下.最近有时间好好研究了一下,的确非常赞,所以推荐给大家.功能和介绍看下面介绍吧.首页的标题很给劲,很纯粹的Coding社区....虽 ...
- 【转】手把手教你把Vim改装成一个IDE编程环境(图文)
手把手教你把Vim改装成一个IDE编程环境(图文) By: 吴垠 Date: 2007-09-07 Version: 0.5 Email: lazy.fox.wu#gmail.com Homepage ...
- openMP编程(下篇)之数据私有与任务调度
title: openMP编程(下篇)之数据处理子句与任务调度 tags: ["openMP"] notebook: 分布式程序_Linux --- openMP并行编程中数据的共 ...
- OpenMP编程总结表
本文对OpenMP 2.0的全部语法——Macro(宏定义).Environment Variables(环境变量).Data Types(数据类型).Compiler Directives(编译指导 ...
- 从一个简单的Java单例示例谈谈并发
一个简单的单例示例 单例模式可能是大家经常接触和使用的一个设计模式,你可能会这么写 public class UnsafeLazyInitiallization { private static Un ...
- 从一个简单的Java单例示例谈谈并发 JMM JUC
原文: http://www.open-open.com/lib/view/open1462871898428.html 一个简单的单例示例 单例模式可能是大家经常接触和使用的一个设计模式,你可能会这 ...
随机推荐
- Vim配置持续记录
1. 家目录创建.vimrc文件 set nu # 设置行号 set tabstop=4 # tab制表符缩进 set autoindent # 自动缩进 set showmatch # 括号匹 ...
- java的几种对象(PO,VO,DAO,BO,POJO)解释 (转)
java的几种对象(PO,VO,DAO,BO,POJO)解释 一.PO:persistant object 持久对象,可以看成是与数据库中的表相映射的java对象.最简单的PO就是对应数据库中某个表中 ...
- Docker学习总结(16)——当当网Docker应用实践
随着Docker成为当下热门的容器技术,各大公司以及中小团队都开始选择Docker来进行应用部署,从原有部署方式迁移到Docker方式过程中难免会遇到各种问题,本次分享主要介绍当当网个性化推荐组应用D ...
- (33)Spring Boot 监控和管理生产环境【从零开始学Spring Boot】
[本文章是否对你有用以及是否有好的建议,请留言] spring-boot-actuator模块提供了一个监控和管理生产环境的模块,可以使用http.jmx.ssh.telnet等拉管理和监控应用.审计 ...
- 0709MySQL 数据库性能优化之表结构优化
转自http://isky000.com/database/mysql-perfornamce-tuning-schema MySQL 数据库性能优化之缓存参数优化 MySQL数据库性能优化之硬件瓶颈 ...
- codevs——T1043 方格取数
http://codevs.cn/problem/1043/ 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题解 查看运行结果 题目描述 De ...
- OSX: 安装打印机的有用命令行
事实上非常easy.就是有用lpadmin命令,以下给出一个样例: printername="YOUR_PRINTER_NAME" location="LOCATION ...
- HTTP基本认证(Basic Authentication)的JAVA演示样例
大家在登录站点的时候.大部分时候是通过一个表单提交登录信息.可是有时候浏览器会弹出一个登录验证的对话框.例如以下图,这就是使用HTTP基本认证.以下来看看一看这个认证的工作过程:第一步: clien ...
- 多个线程运行结束之后主线程再执行CountDownLatch
多个线程运行结束之后主线程再执行CountDownLatch 学习了:http://blog.csdn.net/lvyuanj/article/details/50737123 这个要膜拜一下! h ...
- [Javascript Crocks] Flatten Nested Maybes with `chain`
Sometimes, we run into situations where we end up with a Maybe within the context of another Maybe. ...