OpenCV加速方法-像素遍历-内存释放-运行时间计算-基本技巧

文章目录

1.查表法

LUT代表查找表(Lookup Table),它是一种用于像素值映射的技术。查找表是一个数组,其中每个元素对应于输入像素值的一个映射值。使用LUT可以有效地对图像进行像素值的转换,常用于颜色空间转换或者对特定像素值进行操作。
查表法:LUT,使用lut的方法法,远快于每个像素都计算的方法。

查表法可以很大程度的节约计算时间,优于每个像素点的重复计算,如果像素点的计算,不与周围像素相关,应采用这种方法进行计算。

2.像素遍历

openCV像素遍历常用的是三种方法:ptr指针,迭代器(iterator)以及动态地址at。

一般图像行与行之间往往存储是不连续的,但是有些图像可以是连续的,Mat提供了一个检测图像是否连续的函数isContinuous()。当图像连通时,我们就可以把图像完全展开,看成是一行进行处理。动态地址at不适合用于像素遍历,速度太慢了,比较适合随机访问的方式

cpp 复制代码
#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>

using namespace std;
using namespace cv;

void colorReduceAt(Mat& srcImage, Mat& dstImageAt, int div);
void colorReduceIterator(Mat& srcImage, Mat& dstImageIterator, int div);
void colorReducePtr(Mat& srcImage, Mat& dstImagePtr, int div);

int main()
{
    //加载lena图像
    Mat srcImage = imread("lena.jpg");

    //判断图像是否加载成功
    if(srcImage.empty())
    {
        cout << "图像加载失败!" << endl << endl;
        return -1;
    }
    else
        cout << "图像加载成功!" << endl << endl;

    imshow("srcImage",srcImage);

    //声明处理后图像变量
    Mat dstImageAt, dstImageIterator, dstImagePtr;
    dstImageAt = srcImage.clone();
    dstImageIterator = srcImage.clone();
    dstImagePtr = srcImage.clone();

    int div = 4;

    //声明时间变量
    double timeAt, timeIterator, timePtr;

    timeAt = static_cast<double>(getTickCount());
    colorReduceAt(srcImage, dstImageAt, div);
    timeAt = ((double)getTickCount() - timeAt) / getTickFrequency();
    imshow("dstImageAt",dstImageAt);
    cout << "使用at()动态地址计算耗时:" << timeAt << endl << endl;

    timeIterator = static_cast<double>(getTickCount());
    colorReduceIterator(srcImage, dstImageIterator, div);
    timeIterator = ((double)getTickCount() - timeIterator) / getTickFrequency();
    imshow("dstImageIterator",dstImageIterator);
    cout << "使用iterator迭代器耗时:" << timeIterator << endl << endl;

    timePtr = static_cast<double>(getTickCount());
    colorReducePtr(srcImage, dstImagePtr, div);
    timePtr = ((double)getTickCount() - timePtr) / getTickFrequency();
    imshow("dstImagePtr",dstImagePtr);
    cout << "使用ptr指针耗时:" << timePtr << endl;


    waitKey(0);

    return 0;
}

//使用at动态地址计算方式
void colorReduceAt(Mat& srcImage, Mat& dstImageAt, int div)
{
    int rowNumber = dstImageAt.rows;      //获取图像行数
    int colNumber = dstImageAt.cols;      //获取图像列数

    //对每个像素进行处理
    for(int i = 0; i < rowNumber; i++)
    {
        for(int j = 0; j < colNumber; j++)
        {
            dstImageAt.at<Vec3b>(i,j)[0] = dstImageAt.at<Vec3b>(i,j)[0]/div*div;    //Blue
            dstImageAt.at<Vec3b>(i,j)[1] = dstImageAt.at<Vec3b>(i,j)[1]/div*div;    //Green
            dstImageAt.at<Vec3b>(i,j)[2] = dstImageAt.at<Vec3b>(i,j)[2]/div*div;    //Red
        }
    }

}

//使用iterator迭代器方式
void colorReduceIterator(Mat& srcImage, Mat& dstImageIterator, int div)
{
    MatIterator_<Vec3b> imageIt = dstImageIterator.begin<Vec3b>();      //获取迭代器初始位置
    MatIterator_<Vec3b> imageEnd = dstImageIterator.end<Vec3b>();       //获取迭代器结束位置

    //对每个像素进行处理
    for(;imageIt != imageEnd; imageIt++)
    {
        (*imageIt)[0] = (*imageIt)[0]/div*div;      //Blue
        (*imageIt)[1] = (*imageIt)[1]/div*div;      //Green
        (*imageIt)[2] = (*imageIt)[2]/div*div;      //Red
    }
}

//使用ptr指针
void colorReducePtr(Mat& srcImage, Mat& dstImagePtr, int div)
{
    int rowNumber = dstImagePtr.rows;                           //获取图像矩阵行数
    int colNumber = dstImagePtr.cols*dstImagePtr.channels();    //三通道图像每行元素个数为列数x通道数

    for(int i = 0; i < rowNumber; i++)
    {
        uchar* pixelPtr = dstImagePtr.ptr<uchar>(i);            //获取矩阵每行首地址指针
        for(int j = 0; j < colNumber; j++)
            pixelPtr[j] = pixelPtr[j] / div * div;
    }
}

使用指针方式是最快的处理方式,而迭代器的方式相对最慢。但是使用迭代器是较为安全的访问方式。

  1. 尽可能使用opencv中提供的参数,已经优化,速度有保障
  2. 最快的方式是LUT()函数,因为opencv库通过Intel Threaded Building Blocks实现其多线程。
  3. 如果写一个简单图像的遍历程序推荐使用指针方式。
  4. 迭代器是相对来讲比较安全的访问方式,但其速度也相对较慢。
  5. 在Debug模式下,动态地址计算方法是最慢的访问方式,但是在Release模式下它有可能比iterator访问方式快

3.GPU加速

需要GPU硬件设备支持。

openCL加速:使用UMat结构代替Mat。

高性能:OpenCL的相关用法:UMat

在OpenCV3中,OCL module已经被舍弃。而是使用更易上手的Transparent API来替代 OCL module。因此只需要使用 UMat来替换Mat,而其余的代码保持不变,即可实现加速。

Mat转换成UMat可以使用Mat::copyTo(OutputArray dst),也可以使用Mat::getUMat(int access_flags)

cpp 复制代码
#include <chrono>
#include <opencv2/opencv.hpp>
#define  millisecond 1000000
#define DEBUG_PRINT(...)  printf( __VA_ARGS__); printf("\n")
#define DEBUG_TIME(time_) auto time_ =std::chrono::high_resolution_clock::now()
#define RUN_TIME(time_)  (double)(time_).count()/millisecond
using namespace std;
 
void main() {
	string image_path = "1.jpg";
	cv::Mat image1 = cv::imread(image_path);
	cv::Mat dest1;
	DEBUG_PRINT("image size:[%d,%d]", image1.cols, image1.rows);
	//Mat convert to UMat
	//cv::UMat image2= image1.getUMat(cv::ACCESS_FAST);//ACCESS_READ, ACCESS_WRITE, ACCESS_RW和ACCESS_FAST
	cv::UMat image2;
	image1.copyTo(image2);
	cv::UMat dest2;
 
	DEBUG_TIME(T0);
	cv::blur(image1, dest1, cv::Size(15, 15));
	DEBUG_TIME(T1);
	cv::blur(image2, dest2, cv::Size(15, 15));
	DEBUG_TIME(T2);
 
	//UMat convert to Mat
	cv::Mat dest3;
	dest2.copyTo(dest3);
	DEBUG_PRINT("CPU:%3.3fms", RUN_TIME(T1 - T0));
	DEBUG_PRINT("GPU:%3.3fms", RUN_TIME(T2 - T1));
}

//image size:[2000,3008]
//CPU:18.039ms
//GPU:9.623ms 

4.内存释放release

内存占用过高时,应主动释放内存。

cpp 复制代码
	Mat image  = imread("D:\\OpencvTest\\1.jpg");
	image.release();

5.计算运行时间

cpp 复制代码
using namespace cv;
 
//设置宏定义
#define TB__(A) int64 A; A = cv::getTickCount()
#define TE__(A) cout << #A << " : " << 1.E3 * double(cv::getTickCount() - A)/double(cv::getTickFrequency()) << "ms" << endl
 
 
// 使用方法:
TB__(cpu_cvt);
#pragma omp parallel for num_threads(4)
    for (int k = 0; k < REPEATES; k++)
        cv::cvtColor(cpu_src, cpu_dst, CV_BGR2Lab);
TE__(cpu_cvt);
 
相关推荐
nju_spy4 分钟前
复杂结构数据挖掘(二)关联规则挖掘 Association rule mining
人工智能·数据挖掘·关联规则挖掘·apiriori·dhp·fp-growth·高频集
刀客Doc8 分钟前
刀客doc:亚马逊广告再下一城,拿下微软DSP广告业务
大数据·人工智能·microsoft
AndrewHZ36 分钟前
【图像处理基石】GIS图像处理入门:4个核心算法与Python实现(附完整代码)
图像处理·python·算法·计算机视觉·gis·cv·地理信息系统
掘金安东尼40 分钟前
Google+禁用“一次性抓取100条搜索结果”,SEO迎来变革?
人工智能
FIN66681 小时前
射频技术领域的领航者,昂瑞微IPO即将上会审议
前端·人工智能·前端框架·信息与通信
小麦矩阵系统永久免费1 小时前
短视频矩阵系统哪个好用?2025最新评测与推荐|小麦矩阵系统
大数据·人工智能·矩阵
Mr.Lee jack1 小时前
【vLLM】源码解读:高性能大语言模型推理引擎的工程设计与实现
人工智能·语言模型·自然语言处理
IT_陈寒1 小时前
Java性能优化:这5个Spring Boot隐藏技巧让你的应用提速40%
前端·人工智能·后端
MicroTech20251 小时前
微算法科技(NASDAQ:MLGO)开发延迟和隐私感知卷积神经网络分布式推理,助力可靠人工智能系统技术
人工智能·科技·算法
喜欢吃豆1 小时前
多轮智能对话系统架构方案(可实战):从基础模型到自我优化的对话智能体,数据飞轮的重要性
人工智能·语言模型·自然语言处理·系统架构·大模型·多轮智能对话系统