OpenCV使用pthread实现多线程加速处理图像

【尊重原创,转载请注明出处】https://blog.csdn.net/guyuealian/article/details/81912704


目录

OpenCV使用pthread实现多线程加速处理图像

1.pthread多线程加速

2.自己封装的多线程cvThread类


    POSIX线程(POSIX threads),简称Pthreads,是线程的POSIX标准。Pthread是由POSIX提出的一套通用的线程库,在linux平台下,它被广泛的支持,而在windows平台下,需要下载pthreads-w32库。之所以选择Pthreads库作为多线程处理库,是因此Android NDK开发时,可以使用pthread在C++中实现多线程处理,这样,可以方便OpenCV的图像加速处理和算法的移植。

pthreads-w32在Windows的配置方法,可参考:

https://blog.csdn.net/qianchenglenger/article/details/16907821

pthreads-w32-2-9-1:https://download.csdn.net/download/guyuealian/10623897

其他版本的地址:ftp://sourceware.org/pub/pthreads-win32

关于pthread的用法,可参考这个PDF:

https://download.csdn.net/download/qq_21792169/9380962


1.pthread多线程加速

下面是使用多线程(3个子线程)实现OpenCV图像加速的的方法,基本思路就是:先将图像分块,比如分成3块,每块使用一个子线程进行处理,处理完后再合并成一块图像,这样就实现了OpenCV多线程加速图像处理的方法。

// pthreadDemo.cpp : 定义控制台应用程序的入口点。
//#include <stdio.h>
#include <pthread.h>
#include <assert.h>
#include <string>
#include <opencv2/opencv.hpp>
using namespace std;
#define THREAD_NUMS 3/*paramThread用于传递线程需要的参数值*/
struct paramThread
{int w;int h;uchar * data;
};/********************************************************
*   @brief       : 多线程处理函数
*   @param  args : 多线程传入的参数
*   @return      : void
********************************************************/
void * threadProcess(void* args) {pthread_t myid = pthread_self();paramThread *para = (paramThread *)args;int w = para->w;int h = para->h;cv::Mat image(h,w,CV_8UC3,(uchar *)para->data);//cv::cvtColor(image, image, cv::COLOR_BGR2RGB);cv::blur(image, image,cv::Size(7,7), cv::Point(-1, -1), cv::BORDER_REPLICATE);//printf("thread id = %d, w=%d, h=%d\n", myid, w,h);//cv::imshow("image", image); cv::waitKey(2000);pthread_exit(NULL);return NULL;
}/********************************************************
*   @brief       : 实现图像分割,
*   @param  num  :  分割个数
*   @param  type : 0:垂直分割(推荐),1:水平分割(不推荐)
*   @return      : vector<cv::Mat>
*   PS:使用水平分割时(type=1),处理完后必须调用catImage进行拼接,
*   使用垂直分割时(type=0),可以不进行catImage,因为是对原图进行操作的
********************************************************/
vector<cv::Mat> splitImage(cv::Mat image, int num,int type) {int rows = image.rows;int cols = image.cols;vector<cv::Mat> v;if (type == 0) {//垂直分割for (size_t i = 0; i < num; i++) {int star = rows / num*i;int end = rows / num*(i + 1);if (i == num - 1) {end = rows;}//cv::Mat b = image.rowRange(star, end);v.push_back(image.rowRange(star, end));}}else if (type == 1) {//水平分割for (size_t i = 0; i < num; i++){int star = cols / num*i;int end = cols / num*(i + 1);if (i == num - 1) {end = cols;}//cv::Mat b = image.colRange(star, end);/*解决水平分割的Bug:必须clone()*/v.push_back(image.colRange(star, end).clone());}}return  v;
}/********************************************************
*   @brief       : 实现图像拼接,
*   @param  v    :
*   @param  type : 0:垂直拼接,1:水平拼接
*   @return      : Mat
********************************************************/
cv::Mat catImage(vector<cv::Mat> v, int type) {cv::Mat dest= v.at(0);for (size_t i = 1; i < v.size(); i++){if (type == 0)//垂直拼接{cv::vconcat(dest, v.at(i), dest);}else if (type == 1)//水平拼接{cv::hconcat(dest, v.at(i), dest);}}return dest;
}int main() {string path = "D:\\imageEnhance\\images\\test.jpg";cv::Mat src = cv::imread(path);printf("image size =  w=%d, h=%d\n", src.cols, src.rows);cv::Mat image1 = src.clone();cv::Mat image2 = src.clone();cv::imshow("src", src); cv::waitKey(30);double T0 = static_cast<double>(cv::getTickCount());/*不使用多线程图像处理*/cv::blur(image1, image1, cv::Size(7, 7));double T1 = static_cast<double>(cv::getTickCount());/*使用多线程图像处理*/int type = 0;vector<cv::Mat> v = splitImage(image2, THREAD_NUMS, type);paramThread args[THREAD_NUMS];pthread_t pt[THREAD_NUMS];    //创建THREAD_NUMS个子线程for (size_t i = 0; i < THREAD_NUMS; i++){args[i].h = v.at(i).rows;args[i].w = v.at(i).cols;args[i].data = v.at(i).data;pthread_create(&pt[i], NULL, &threadProcess, (void *)(&args[i]));}/*等待全部子线程处理完毕*/for (size_t i = 0; i < THREAD_NUMS; i++){pthread_join(pt[i], NULL);}cv::Mat dest = catImage(v, type);double T2 = static_cast<double>(cv::getTickCount());printf("       run times = %3.3fms\n", (T1 - T0)*1000 / cv::getTickFrequency());printf("Thread run times = %3.3fms\n,", (T2 - T1)*1000 / cv::getTickFrequency());cv::imshow("dest", dest); cv::waitKey(30);cv::imshow("image2", image2); cv::waitKey(30);cv::waitKey(0);return 0;
}


可以看到,对于一张3000*1877的大图片,使用3个线程并行处理会比单线程处理快了将近4倍的速度。但比较尴尬的是,由于使用了图像分块处理,进行图像blur模糊时,边界会出现不规则的像素,这时拼接在一起,会导致图像拼接的边缘出现横条的现象,见下面的模糊图。

一种决解的方法就是,可以在图像分割时,根据kernel size的大小的适当padding像素,处理完再cutting这些padding的像素,这部分我还没有实现,有兴趣的可以搞搞哈。

    这种使用pthread实现多线程图像处理加速方法,比较适合算法过程跟边界处理无关的情况,如RGB转BGR,Gamma变换这些图像处理操作。


2.自己封装的多线程cvThread类

为了方面以后调用,这里封装了一个cvThread类:

    cvThread.h:

#pragma once
#include <stdio.h>
#include <pthread.h>
#include <assert.h>
#include <string>
#include <opencv2/opencv.hpp>
using namespace std;class cvThread
{
public:cvThread();~cvThread();/*paramThread用于传递线程需要的参数值*/struct paramThread{int w;int h;uchar * data;};/*********************************************************   @brief       : 多线程要处理的图像操作*    @param  args : 多线程传入的参数*   @return      : void********************************************************/static void * cvThreadBlur(void* args);/*********************************************************  @brief        : 多线程处理函数*   @param  image : 输入/输出Mat图像*    @param  type  : 分割类型0:垂直分割(推荐),1:水平分割(不推荐)* @param  thread_num : 多线程个数*    @return      : void********************************************************/void  cvThreadProcess(cv::Mat &image, const int type, const int thread_num);void  cvThreadProcess(cv::Mat &image);/*********************************************************   @brief       : 实现图像分割,* @param  num  :  分割个数*  @param  type : 0:垂直分割(推荐),1:水平分割(不推荐)*  @return      : vector<cv::Mat>*   PS:使用水平分割时(type=1),处理完后必须调用catImage进行拼接,*   使用垂直分割时(type=0),可以不进行catImage,因为是对原图进行操作的********************************************************/vector<cv::Mat> splitImage(cv::Mat image, int num, int type);/*********************************************************   @brief       : 实现图像拼接,* @param  v    :*    @param  type : 0:垂直拼接,1:水平拼接* @return      : Mat********************************************************/cv::Mat catImage(vector<cv::Mat> v, int type);
};

    cvThread.cpp:

#include "cvThread.h"cvThread::cvThread()
{
}cvThread::~cvThread()
{
}
/********************************************************
*   @brief       : 多线程处理函数
*   @param  args : 多线程传入的参数
*   @return      : void
********************************************************/
void * cvThread::cvThreadBlur(void* args) {pthread_t myid = pthread_self();paramThread *para = (paramThread *)args;int w = para->w;int h = para->h;cv::Mat image(h, w, CV_8UC3, (uchar *)para->data);/***************************************************//*这里实现多线程要处理的图像操作*/cv::blur(image, image, cv::Size(7, 7), cv::Point(-1, -1), cv::BORDER_REPLICATE);/***************************************************/pthread_exit(NULL);return NULL;
}#define THREAD_NUMS 4
void  cvThread::cvThreadProcess(cv::Mat &image) {/*使用多线程图像处理*/int type = 0;vector<cv::Mat> v = splitImage(image, THREAD_NUMS, type);paramThread args[THREAD_NUMS];pthread_t pt[THREAD_NUMS];    //创建thread_num个子线程for (size_t i = 0; i < THREAD_NUMS; i++){args[i].h = v.at(i).rows;args[i].w = v.at(i).cols;args[i].data = v.at(i).data;pthread_create(&pt[i], NULL, &cvThreadBlur, (void *)(&args[i]));}/*等待全部子线程处理完毕*/for (size_t i = 0; i < THREAD_NUMS; i++){pthread_join(pt[i], NULL);}cv::Mat dest = catImage(v, type);
}void  cvThread::cvThreadProcess(cv::Mat &image,const int type=0,const int thread_num=4) {/*使用多线程图像处理*/vector<cv::Mat> v = splitImage(image, thread_num, type);paramThread *args = new paramThread[thread_num];pthread_t *pt = new pthread_t[thread_num];    //创建thread_num个子线程for (size_t i = 0; i < thread_num; i++){args[i].h = v.at(i).rows;args[i].w = v.at(i).cols;args[i].data = v.at(i).data;pthread_create(&pt[i], NULL, &cvThreadBlur, (void *)(&args[i]));}/*等待全部子线程处理完毕*/for (size_t i = 0; i < thread_num; i++){pthread_join(pt[i], NULL);}/*PS:使用水平分割时(type = 1),处理完后必须调用catImage进行拼接,使用垂直分割时(type = 0),可以不进行catImage,因为是对原图进行操作的*/if (type==1){image = catImage(v, type);}delete []args;delete []pt;
}
/********************************************************
*   @brief       : 实现图像分割,
*   @param  num  :  分割个数
*   @param  type : 0:垂直分割(推荐),1:水平分割(不推荐)
*   @return      : vector<cv::Mat>
*   PS:使用水平分割时(type=1),处理完后必须调用catImage进行拼接,
*   使用垂直分割时(type=0),可以不进行catImage,因为是对原图进行操作的
********************************************************/
vector<cv::Mat> cvThread::splitImage(cv::Mat image, int num, int type) {int rows = image.rows;int cols = image.cols;vector<cv::Mat> v;if (type == 0) {//垂直分割for (size_t i = 0; i < num; i++) {int star = rows / num*i;int end = rows / num*(i + 1);if (i == num - 1) {end = rows;}//cv::Mat b = image.rowRange(star, end);v.push_back(image.rowRange(star, end));}}else if (type == 1) {//水平分割for (size_t i = 0; i < num; i++) {int star = cols / num*i;int end = cols / num*(i + 1);if (i == num - 1) {end = cols;}//cv::Mat b = image.colRange(star, end);/*解决水平分割的Bug:必须clone()*/v.push_back(image.colRange(star, end).clone());}}return  v;
}/********************************************************
*   @brief       : 实现图像拼接,
*   @param  v    :
*   @param  type : 0:垂直拼接,1:水平拼接
*   @return      : Mat
********************************************************/
cv::Mat cvThread::catImage(vector<cv::Mat> v, int type) {cv::Mat dest = v.at(0);for (size_t i = 1; i < v.size(); i++){if (type == 0)//垂直拼接{cv::vconcat(dest, v.at(i), dest);}else if (type == 1)//水平拼接{cv::hconcat(dest, v.at(i), dest);}}return dest;
}

    测试方法main.cpp:

#include <stdio.h>
#include <pthread.h>
#include <assert.h>
#include <string>
#include <opencv2/opencv.hpp>
#include "cvThread.h"
using namespace std;
int main() {string path = "D:\\imageEnhance\\images\\8-1.jpg";cv::Mat src = cv::imread(path);printf("image size =  w=%d, h=%d\n", src.cols, src.rows);cv::Mat image1 = src.clone();cv::Mat image2 = src.clone();cv::imshow("src", src); cv::waitKey(30);double T0 = static_cast<double>(cv::getTickCount());/*不使用多线程图像处理*/cv::blur(image1, image1, cv::Size(7, 7));double T1 = static_cast<double>(cv::getTickCount());/*使用多线程图像处理*/cvThread cvth;cvth.cvThreadProcess(image2,0,4);double T2 = static_cast<double>(cv::getTickCount());printf("       run times = %3.3fms\n", (T1 - T0)*1000 / cv::getTickFrequency());printf("Thread run times = %3.3fms\n,", (T2 - T1)*1000 / cv::getTickFrequency());cv::imshow("image1", image1); cv::waitKey(30);cv::imshow("image2", image2); cv::waitKey(30);cv::waitKey(0);return 0;
}

OpenCV使用pthread实现多线程加速处理图像(C++)相关推荐

  1. 使用Python,OpenCV和Scikit-Image检测低对比度图像

    使用Python,OpenCV和Scikit-Image检测低对比度图像 1. 效果图 2. 原理 3. 源码 参考 这篇博客将介绍如何使用Python,OpenCV和Scikit-Image检测低对 ...

  2. OpenCV 【二十】给图像添加边界

    目录 1原理 2 代码 3 运行结果 1原理 前一节我们学习了图像的卷积操作.一个很自然的问题是如何处理卷积边缘.当卷积点在图像边界时会发生什么,如何处理这个问题? 大多数用到卷积操作的OpenCV函 ...

  3. 快速指南:使用OpenCV预处理神经网络中的面部图像

    点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 本期将介绍脸部检测.眼睛检测:图像拉直.裁剪.调整大小.归一化等内 ...

  4. 【OpenCV 4开发详解】图像修复

    本文首发于"小白学视觉"微信公众号,欢迎关注公众号 本文作者为小白,版权归人民邮电出版社发行所有,禁止转载,侵权必究! 经过几个月的努力,小白终于完成了市面上第一本OpenCV 4 ...

  5. 【OpenCV 4开发详解】图像二值化

    本文首发于"小白学视觉"微信公众号,欢迎关注公众号 本文作者为小白,版权归人民邮电出版社发行所有,禁止转载,侵权必究! 经过几个月的努力,小白终于完成了市面上第一本OpenCV 4 ...

  6. 【OpenCV 4开发详解】图像膨胀

    本文首发于"小白学视觉"微信公众号,欢迎关注公众号 本文作者为小白,版权归人民邮电出版社发行所有,禁止转载,侵权必究! 经过几个月的努力,小白终于完成了市面上第一本OpenCV 4 ...

  7. 【OpenCV 4开发详解】图像腐蚀

    本文首发于"小白学视觉"微信公众号,欢迎关注公众号 本文作者为小白,版权归人民邮电出版社发行所有,禁止转载,侵权必究! 经过几个月的努力,小白终于完成了市面上第一本OpenCV 4 ...

  8. 【OpenCV 4开发详解】图像距离变换

    本文首发于"小白学视觉"微信公众号,欢迎关注公众号 本文作者为小白,版权归人民邮电出版社发行所有,禁止转载,侵权必究! 经过几个月的努力,小白终于完成了市面上第一本OpenCV 4 ...

  9. 【OpenCV 4开发详解】图像连通域分析

    本文首发于"小白学视觉"微信公众号,欢迎关注公众号 本文作者为小白,版权归人民邮电出版社发行所有,禁止转载,侵权必究! 经过几个月的努力,小白终于完成了市面上第一本OpenCV 4 ...

最新文章

  1. JAVA抽象类和接口的区别【附经典分析用例Door】
  2. Keras—ModelCheckpoint
  3. 带你认识清华标杆课教师 | 卓晴:自带BGM的硬核“技术流”教师
  4. UIApplication shared application用法总结
  5. 飞桨第六课 2020.4.5
  6. pythonpip安装与使用_Python pip 安装使用与问题
  7. 判断DataRow中某列是否为空的方法
  8. 化学版2048,你玩过吗?内含游戏链接
  9. cs精英游戏python代码_python面向对象-cs游戏示例
  10. 曾遭闪电贷攻击的Origin将重新推出稳定币OUSD
  11. mysql基础-数据库连接、创建、删除、选择等基本操作详解(一)
  12. 胡寿松《自动控制原理》第7版笔记和课后习题答案
  13. DM6437烧写总结
  14. The fundamentals of millimeter wave radar sensors——毫米波雷达传感器基本原理
  15. android手机是vivo吗,为什么最流畅的安卓手机竟然是VIVO和OPPO?
  16. 很搞笑,今天才弄清楚什么是二级域名和三级域名的区别
  17. 【报告】德勤管理咨询2019年境内外TMT标杆企业高管薪酬与激励调研报告
  18. 为什么RSA公钥每次加密得到的结果都不一样?
  19. A - Seat Occupation
  20. 人社部已发布3个批次38个新职业!热门“风向标”来了,快跟上

热门文章

  1. JQuery弹出层,点击按钮后弹出遮罩层,有关闭按钮
  2. 洛谷P2016战略游戏
  3. iview 使用笔记
  4. NET快速信息化系统开发框架 V3.2 - “用户管理”主界面使用多表头展示、增加打印功能...
  5. 【第一季】CH07_FPGA_RunLED创建VIVADO工程实验
  6. 针对不同浏览器的css
  7. 2010中国杭州电子信息博览会通讯报道
  8. Python OpenCV人脸识别案例
  9. ubuntu12.4上安装minigui3.0.12
  10. Redis大乱探------哨兵(二)