C++多线程图像处理

6 篇文章 0 订阅

初衷

最近有个图像处理模块,流程简单,实现冗杂;在同事指导下,开始接触多线程处理。

先前有做过线程,也稍微接触GPU处理,但是这种整齐划一的多线程处理,还是最近才拉开帷幕,并且:一发不可收

笔者接触的项目对实时性要求很高,同时,处理图像尺寸比较大,怎么说呢,
尺寸(640*22)*512,就是拼接全景图尺寸大概级别。

这种大数据量的处理,即使简单的访问像素,都需要7208960次,虽然计算机具有良好的高频处理特性,但是倘或能够将处理时间打折,那应该是件很了不起的事情。

处理案例

最近接触一个算法,名为:基于时空结构张量的运动检测,具体原理和使用场景自行百度。

主要处理流程包括:

  • 1、获取原始灰度图的空间梯度,即水平方向和垂直方向梯度图;
  • 2、获取时间梯度图,即帧差图;
  • 3、三张图对应像素计算,涉及相乘、平方、相加,在原文中,为求矩阵的迹;
  • 4、邻域卷积,获得小范围内的迹,通过和阈值比较,从而判定为运动前景还是稳定背景,实现孤立区域、运动区域的分割。

思路

在笔者接触的图像中,宽度远大于高度,因此在做图像拆分小的单元块时,选择保持高度不变,而在宽度方向拆分;由于并不清楚以后运行是四核还是八核,因此统一开启四个线程。

所以基本思路如下:

  • 1、确定每个线程块处理的列项起始和终止坐标点;
  • 2、编写核心处理部分,处理部分除了ID,差异不会太大;
  • 3、开启线程,调用线程处理模块。

实现代码

这里分享一部分代码:

线程处理核心部分如下,该部分主要做卷积:

	/**
	* @brief 时空结构张量的计算写进线程模块
	* @brief 部分参数写进类成员,在这边就不做分享具体含义了
	* @param *idThread - 入参,线程处理的id,据此计算当前索引起始点
	* @param *radius - 入参,邻域半径
	* @return 
	*/
	
int CTENSOR::tensorImageThread(int idThread,int radius,int thresh)
{
	int indexStart = idThread*m_iWidthThread;

	int jStart = 0;
	int jEnd = 0;

	if (idThread == 0)
	{
		jStart = indexStart + radius;
		jEnd = indexStart + m_iWidthThread;
	}
	else if (idThread == 3)
	{
		jStart = indexStart;
		jEnd = indexStart + m_iWidthThread - radius;
	}
	else
	{
		jStart = indexStart;
		jEnd = indexStart + m_iWidthThread;
	}

	int indexRow = 0;
	int indexCol = 0;

	for (int i = radius; i < m_iRow - radius; i++)
	{
		for (int j = jStart; j < jEnd; j++)
		{
			float kernelSum = 0;

			for (int kernelRow = -radius; kernelRow < radius; kernelRow++)
			{
				for (int kernelCol = -radius; kernelCol < radius; kernelCol++)
				{
					indexRow = i + kernelRow;
					indexCol = j + kernelCol;
					kernelSum = kernelSum + m_mulSumImage.at<float>(indexRow, indexCol);
				}
			}

			if (kernelSum >= thresh)
			{
				tensoredImage.at<uchar>(i, j) = 255;
			}
		}
	}
	return 0;
}

在以上代码中,特别愿意分享的是,
由于卷积操作,在边界处索引和内部空间会有差别;稍不留神就会引发内存访问越界的风险;同时考虑空间连续,也不能做内部数据的舍弃
所以可以参考我所采用的,提前设置列向开始和结束的id。

线程调用部分如下:


auto F1 = std::async(&CTENSOR::tensorImageThread, this, 0, 3, thresh);	
auto F2 = std::async(&CTENSOR::tensorImageThread, this, 1, 3, thresh);
auto F3 = std::async(&CTENSOR::tensorImageThread, this, 2, 3, thresh);
auto F4 = std::async(&CTENSOR::tensorImageThread, this, 3, 3, thresh);

auto result1 = F1.get();
auto result2 = F2.get();
auto result3 = F3.get();
auto result4 = F4.get();

至于处理速度,怎么说呢?
没加线程之前0.6秒;开启该部分线程后,0.2秒。
当然其他部分也做了些许优化;
但就图像处理这个小模块而言,速度理论提升四倍。

路漫漫其修远矣~

  • 5
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值