OpenCV的resize函数优化

OpenCV的resize函数优化背景在使用 OpenCV 做图像处理的时候 最常见的问题是 c 版本性能不足 以 resize 函数为例来说明 将 size 为 864 1323 3 的函数缩小一半 Matimg0 gettimeofday amp t4 NULL cv resize source img0 cv Size cols out rows out gettimeofday amp

背景

在使用OpenCV做图像处理的时候,最常见的问题是c++版本性能不足,以resize函数为例来说明,将size为[864,1323,3]的函数缩小一半:

Mat img0; gettimeofday(&t4, NULL); cv::resize(source, img0, cv::Size(cols_out,rows_out)); gettimeofday(&t5, NULL); time = 1000*(t5.tv_sec - t4.tv_sec) + (double)(t5.tv_usec - t4.tv_usec)/1000; printf("frank cv::resize = %lf\n", time); output: frank cv::resize = 13.(ms) on Macmini(2.6 GHz Intel Core i5) 

需要13ms才能完成这个操作,对于一半应用的实时性要求,要再33ms内处理一帧,超过1/3的时间花在resize上,是非常不合理的。

优化1

针对上面这种1/2大小的resize,可以这样来思考,既然我已经知道输出mat的长宽是输入mat的一半,那么输出mat的每个像素值都是从原图的4个像素得到的一个映射,事实上OpenCV也是用类似的技巧,从原图的点映射到输出图像的像素点,这个映射可以是Nearest Neiborhood,也可以是双线性插值、平均、取左上角等等。对于一般自然图像,我们可以直接使用NN映射来获得输出图像的点。

使用上面的方法:

 double time = 0.0; gettimeofday(&t1, NULL); Mat half_img = resizeByHalf(source, &leftTopInt4); int wh = half_img.cols; int hh = half_img.rows; printf("half_img = %d, %d\n", hh, wh); gettimeofday(&t2, NULL); time = 1000*(t2.tv_sec - t1.tv_sec) + (double)(t2.tv_usec - t1.tv_usec)/1000; printf("frank resizeByHalf = %lf\n", time); output:frank resizeByHalf = 10. 

时间相比OpenCV的版本,缩小了3ms

优化2 进一步借鉴最邻近算法

如果我们不是resize到1/2等特定的长宽,而且任意尺寸呢?上面的方法就不能直接使用,但是这个思想是可以借鉴的,我们可以进一步将最临近算法发挥的更好,对outuput的每个点,先根据长宽比计算其在原图中最邻近的像素点,然后直接根据最邻近的思想,直接拷贝Channel个字节作为输出图像:

Mat new_img = Mat(rows_out, cols_out, CV_8UC3); resizeByNN(source.data, new_img.data, source.rows, source.cols, source.channels(), new_img.rows, new_img.cols); gettimeofday(&t4, NULL); time = 1000*(t4.tv_sec - t3.tv_sec) + (double)(t4.tv_usec - t3.tv_usec)/1000; printf("frank resizeByNN = %lf\n", time); output: frank resizeByNN = 6. 

时间已经缩小到原先的一半!

优化3

还有一个杀招,待日后更新。。。。

上面两个函数的源码

resizeByHalf

uchar maxInt4(uchar x0, uchar x1, uchar x2, uchar x3){ uchar t0 = (x0 >= x1) ? x0 : x1; uchar t1 = (x2 >= x3) ? x2 : x3; return (t0 >= t1) ? t0 : t1; } uchar meanInt4(uchar x0, uchar x1, uchar x2, uchar x3){ float t = (x0 + x1 + x2 + x3)/4.0; return uchar(round(t)); //四舍五入 } uchar leftTopInt4(uchar x0, uchar x1, uchar x2, uchar x3){ return x0; } Mat resizeByHalf(Mat input, uchar (*pfun)(uchar x0, uchar x1, uchar x2, uchar x3)){ Mat output; int h_in = input.rows; int w_in = input.cols; int c = input.channels(); int h_out = h_in/2; int w_out = w_in/2; output.create(h_out, w_out, CV_8UC(c)); uchar *data_source = input.data; uchar *data_half = output.data; int bpl_source = w_in*3; int bpl_half = w_out*3; for (int i = 0; i < h_out; i++) { for (int j = 0; j < w_out; j++) { uchar *sr = data_source + i*2*bpl_source + j*2*c; uchar *hr = data_half + i*bpl_half + j*c; for (int k = 0; k < c; k++) { *(hr+k) = pfun(*(sr+k), *(sr+k+c), *(sr+k+bpl_source), *(sr+k+c+bpl_source)); } } } return output; } 

resizeByNN

void resizeByNN(uchar *input, uchar *output, int height_in, int width_in, int channels, int height_out, int width_out){ uchar *data_source = input; uchar *data_half = output; int bpl_source = width_in*3; int bpl_dst = width_out*3; int pos = 0; int sep = 0; uchar *sr = nullptr; uchar *hr = nullptr; float step = 0.0; float step_x = float(width_in)/float(width_out); float step_y = float(height_in)/float(height_out); for (int i = 0; i < height_out; i++) { for (int j = 0; j < width_out; j++) { sep = int(step_y*i); step = int(j*step_x); sr = data_source + sep*bpl_source; hr = data_half + i*bpl_dst +j*channels; pos = step*channels; memcpy(hr, sr+pos, channels); } } return; } 

多谢阅读!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/214578.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月18日 下午3:55
下一篇 2026年3月18日 下午3:56


相关推荐

  • pycharm自定义快捷键设置输入默认文本_pycharm快捷键大全图

    pycharm自定义快捷键设置输入默认文本_pycharm快捷键大全图之前在eclipse上有许多快捷键用的顺手了,最近写python在pycharm上怎么设置自定义的快捷键呢?编辑器右上角点击File-选择Setting-选择Keymap-双击EditorActions即可自定义快捷键

    2022年8月28日
    6
  • CRC校验算法详解「建议收藏」

    CRC校验算法详解「建议收藏」CRC(CyclicRedundancyCheck)循环冗余校验是常用的数据校验方法,讲CRC算法的文章很多,之所以还要写这篇,是想换一个方法介绍CRC算法,希望能让大家更容易理解CRC算法。先

    2022年8月2日
    15
  • Python画图显示中文

    Python画图显示中文matplotlib作图时默认设置下为英文,无法显示中文,只需要添加下面两行代码即可plt.rcParams[‘font.sans-serif’]=[‘SimHei’]plt.rcParams[‘axes.unicode_minus’]=FalseExampleimportmatplotlib.pyplotaspltfromnumpy.randomimportmul…

    2022年6月1日
    39
  • webpack(7)webpack使用vue配置「建议收藏」

    webpack(7)webpack使用vue配置「建议收藏」前言如果我们想在webpack中使用vue,就需要在webpack中配置vue配置vue首先,我们需要在项目中安装vue,安装命令如下:npminstallvue–save安装完成后

    2022年8月7日
    10
  • Linux安装JDK

    Linux安装JDKLinux安装JDK

    2022年4月22日
    40
  • 相机标定——张正友棋盘格标定法

    相机标定——张正友棋盘格标定法目录为什么需要相机标定?相机标定可以做什么?相机标定后可以得到什么?什么情况下需要借助相机标定的方法?相机标定的原理实现相机标定的方法 为什么需要相机标定? 一个是由于每个镜头的在生产和组装过程中的畸变程度各不相同,通过相机标定可以校正这种镜头畸变,生成矫正后的图像——矫正透镜畸变; 另一个是根据标定后的到的相机参数建立相机成像几何模型,由获得的图像重构…

    2022年5月8日
    317

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号