基于Opencv的计算机视觉软件很多,大家都是敏捷开发、不重新发明轮子。首先就是core模块,这里面包含了基本的类,只要用到opencv都会遇到core,比如cv::Mat,需要理解一下其结构,以便在开发过程中建立一些共识。

convertTo是Mat的数据类型转换函数。

首先,找到文档,点击Main modules,点击Core functionality,点击Basic structures,点击class Mat。

  • 函数的声明

◆ convertTo()

void convertTo( OutputArray m, int rtype, double alpha=1, double beta=0 ) const;

The method converts source pixel values to the target data type. saturate_cast<> is applied at the end to avoid possible overflows:Converts an array to another data type with optional scaling.

m(x,y)=saturate_cast<rType>(α(∗this)(x,y)+β)

Parameters

m output matrix; if it does not have a proper size or type before the operation, it is reallocated.
rtype desired output matrix type or, rather, the depth since the number of channels are the same as the input has; if rtype is negative, the output matrix will have the same type as the input.
alpha optional scale factor.
beta optional delta added to the scaled values.

实现在opencv-3.4.12\modules\core\src\convert.dispatch.cpp:

convertTo是Mat的常量成员函数,无权更改this对象的数据成员。

  • _dst, 输出Mat,可以与src相同。OutputArray另文描述。
  • _type,转出类型,只给出depth即可,如果给出完整类型,如CV_8UC3,也会根据src的channel,转出相同channel数据。即_type = CV_MAKETYPE(CV_MAT_DEPTH(_type), channels());所示操作。
  • alpha和beta,可选,默认为1,0。

关于alpha和beta的选值,我们参考opencv源码,搜索255与256,发现两种都有,但是255居多。因此,在CV_32F和V_8U之间转换,用alpha取值是255.0和1.0/255.0,(8U代表8位无符号整型,范围0-255,32F代表c++的float类型)。如果用默认的1,0,则根据 bool noScale = fabs(alpha-1) < DBL_EPSILON && fabs(beta) < DBL_EPSILON;判断是否对值转尺度

void Mat::convertTo(OutputArray _dst, int _type, double alpha, double beta) const
{CV_INSTRUMENT_REGION();/*this为空时,返回空Mat*/if( empty() ){_dst.release();return;}//如果depth和this相同且alpha、beta默认,直接输出thisbool noScale = fabs(alpha-1) < DBL_EPSILON && fabs(beta) < DBL_EPSILON;// _type为负时,返回this同深度同通道数;_type为正时,指定_type为深度,通道数同this。注意无法指定输出通道数if( _type < 0 )_type = _dst.fixedType() ? _dst.type() : type();else_type = CV_MAKETYPE(CV_MAT_DEPTH(_type), channels());//进行depth转换,首先是src、dst相同depth,此时返回srcint sdepth = depth(), ddepth = CV_MAT_DEPTH(_type);if( sdepth == ddepth && noScale ){copyTo(_dst);return;}// 分配输出dst的内存空间,size()和size的区别,size()是MatSize的括号运算符重载,返回类型是cv::Size(),只用在1、2维。// size是成员变量,类型是MatSize。Mat src = *this;if( dims <= 2 )_dst.create( size(), _type );else_dst.create( dims, size, _type );Mat dst = _dst.getMat();// 函数指针,getConvertFunc,getConvertScaleFunc具体类型转换函数BinaryFunc func = noScale ? getConvertFunc(sdepth, ddepth) : getConvertScaleFunc(sdepth, ddepth);double scale[] = {alpha, beta};int cn = channels();CV_Assert( func != 0 );if( dims <= 2 ){Size sz = getContinuousSize2D(src, dst, cn);func( src.data, src.step, 0, 0, dst.data, dst.step, sz, scale );}else{const Mat* arrays[] = {&src, &dst, 0};uchar* ptrs[2] = {};NAryMatIterator it(arrays, ptrs);Size sz((int)(it.size*cn), 1);for( size_t i = 0; i < it.nplanes; i++, ++it )func(ptrs[0], 1, 0, 0, ptrs[1], 1, sz, scale);}
}

函数指针getConvertFunc,getConvertScaleFunc定义在convert.simd.hpp,convert_scale.simd.hpp,前者是转类型,后者既转类型又转值。以getConvertScaleFunc为例,如下定义:

BinaryFunc getConvertScaleFunc(int sdepth, int ddepth)
{static BinaryFunc cvtScaleTab[][8] ={{(BinaryFunc)GET_OPTIMIZED(cvtScale8u), (BinaryFunc)GET_OPTIMIZED(cvtScale8s8u), (BinaryFunc)GET_OPTIMIZED(cvtScale16u8u),(BinaryFunc)GET_OPTIMIZED(cvtScale16s8u), (BinaryFunc)GET_OPTIMIZED(cvtScale32s8u), (BinaryFunc)GET_OPTIMIZED(cvtScale32f8u),(BinaryFunc)cvtScale64f8u, 0 //(BinaryFunc)cvtScale16f8u},{(BinaryFunc)GET_OPTIMIZED(cvtScale8u8s), (BinaryFunc)GET_OPTIMIZED(cvtScale8s), (BinaryFunc)GET_OPTIMIZED(cvtScale16u8s),(BinaryFunc)GET_OPTIMIZED(cvtScale16s8s), (BinaryFunc)GET_OPTIMIZED(cvtScale32s8s), (BinaryFunc)GET_OPTIMIZED(cvtScale32f8s),(BinaryFunc)cvtScale64f8s, 0 //(BinaryFunc)cvtScale16f8s},{(BinaryFunc)GET_OPTIMIZED(cvtScale8u16u), (BinaryFunc)GET_OPTIMIZED(cvtScale8s16u), (BinaryFunc)GET_OPTIMIZED(cvtScale16u),(BinaryFunc)GET_OPTIMIZED(cvtScale16s16u), (BinaryFunc)GET_OPTIMIZED(cvtScale32s16u), (BinaryFunc)GET_OPTIMIZED(cvtScale32f16u),(BinaryFunc)cvtScale64f16u, 0 //(BinaryFunc)cvtScale16f16u},{(BinaryFunc)GET_OPTIMIZED(cvtScale8u16s), (BinaryFunc)GET_OPTIMIZED(cvtScale8s16s), (BinaryFunc)GET_OPTIMIZED(cvtScale16u16s),(BinaryFunc)GET_OPTIMIZED(cvtScale16s), (BinaryFunc)GET_OPTIMIZED(cvtScale32s16s), (BinaryFunc)GET_OPTIMIZED(cvtScale32f16s),(BinaryFunc)cvtScale64f16s, 0 //(BinaryFunc)cvtScale16f16s},{(BinaryFunc)GET_OPTIMIZED(cvtScale8u32s), (BinaryFunc)GET_OPTIMIZED(cvtScale8s32s), (BinaryFunc)GET_OPTIMIZED(cvtScale16u32s),(BinaryFunc)GET_OPTIMIZED(cvtScale16s32s), (BinaryFunc)GET_OPTIMIZED(cvtScale32s), (BinaryFunc)GET_OPTIMIZED(cvtScale32f32s),(BinaryFunc)cvtScale64f32s, 0 //(BinaryFunc)cvtScale16f32s},{(BinaryFunc)GET_OPTIMIZED(cvtScale8u32f), (BinaryFunc)GET_OPTIMIZED(cvtScale8s32f), (BinaryFunc)GET_OPTIMIZED(cvtScale16u32f),(BinaryFunc)GET_OPTIMIZED(cvtScale16s32f), (BinaryFunc)GET_OPTIMIZED(cvtScale32s32f), (BinaryFunc)GET_OPTIMIZED(cvtScale32f),(BinaryFunc)cvtScale64f32f, 0 //(BinaryFunc)cvtScale16f32f},{(BinaryFunc)cvtScale8u64f, (BinaryFunc)cvtScale8s64f, (BinaryFunc)cvtScale16u64f,(BinaryFunc)cvtScale16s64f, (BinaryFunc)cvtScale32s64f, (BinaryFunc)cvtScale32f64f,(BinaryFunc)cvtScale64f, 0 //(BinaryFunc)cvtScale16f64f},{0, 0, 0, 0, 0, 0, 0, 0/*(BinaryFunc)cvtScale8u16f, (BinaryFunc)cvtScale8s16f, (BinaryFunc)cvtScale16u16f,(BinaryFunc)cvtScale16s16f, (BinaryFunc)cvtScale32s16f, (BinaryFunc)cvtScale32f16f,(BinaryFunc)cvtScale64f16f, (BinaryFunc)cvtScale16f*/},};return cvtScaleTab[CV_MAT_DEPTH(ddepth)][CV_MAT_DEPTH(sdepth)];
}

其中,函数指针的元素定义,以cvtScale8u16u为例,是把usigned char转为usigned short int,这两种整型范围不同,分别是0-255和0-65535,通常要乘以a=255,把相关部分摘录出来:

template<typename _Ts, typename _Td> inline void
cvt_32f( const _Ts* src, size_t sstep, _Td* dst, size_t dstep,Size size, float a, float b )
{
#if CV_SIMDv_float32 va = vx_setall_f32(a), vb = vx_setall_f32(b);const int VECSZ = v_float32::nlanes*2;
#endifsstep /= sizeof(src[0]);dstep /= sizeof(dst[0]);for( int i = 0; i < size.height; i++, src += sstep, dst += dstep ){int j = 0;
#if CV_SIMDfor( ; j < size.width; j += VECSZ ){if( j > size.width - VECSZ ){if( j == 0 || src == (_Ts*)dst )break;j = size.width - VECSZ;}v_float32 v0, v1;vx_load_pair_as(src + j, v0, v1);v0 = v_fma(v0, va, vb);v1 = v_fma(v1, va, vb);v_store_pair_as(dst + j, v0, v1);}
#endiffor( ; j < size.width; j++ )dst[j] = saturate_cast<_Td>(src[j]*a + b);}
}#define DEF_CVT_SCALE_FUNC(suffix, cvt, stype, dtype, wtype) \
static void cvtScale##suffix( const uchar* src_, size_t sstep, const uchar*, size_t, \uchar* dst_, size_t dstep, Size size, void* scale_) \
{ \const stype* src = (const stype*)src_; \dtype* dst = (dtype*)dst_; \double* scale = (double*)scale_; \cvt(src, sstep, dst, dstep, size, (wtype)scale[0], (wtype)scale[1]); \
}DEF_CVT_SCALE_FUNC(8u16u,  cvt_32f, uchar,  ushort, float)
DEF_CVT_SCALE_FUNC宏做了声明 cvtScale8u16u
DEF_CVT_SCALE_FUNC(8u16u,  cvt_32f, uchar,  ushort, float)

手动翻译一下这个宏就是

static void cvtScale8u6u( const uchar* src_, size_t sstep, const uchar*, size_t,  uchar* dst_, size_t dstep, Size size, void* scale_)
{  const uchar* src = (const uchar*)src_;  ushort* dst = (ushort*)dst_;  double* scale = (double*)scale_;  cvt_32f(src, sstep, dst, dstep, size, (float)scale[0], (float)scale[1]);
}

发现,其中用了一个比较人为的定义就是把convertTo里double类型的alpha和beta(void* scale_),降为了float,当然,考虑到最后是转为ushort,这里降位数不影响,所以用到的转换函数是cvt_32f,就是float作为中介。对于cvt_32f,函数模板,对号入座,cvt_32f( const uchar* src, size_t sstep, ushort* dst, size_t dstep, Size size, float a, float b );

最后,用到了

template<> inline ushort saturate_cast<ushort>(float v)      { int iv = cvRound(v); return saturate_cast<ushort>(iv); }
  • convertTo支持的数据类型type

从depth到type,转换计算如下:type=depth+ (channel-1)*8,

例如CV_16UC3= 2+2*8=18

#define CV_CN_SHIFT   3
#define CV_DEPTH_MAX  (1 << CV_CN_SHIFT)#define CV_8U   0
#define CV_8S   1
#define CV_16U  2
#define CV_16S  3
#define CV_32S  4
#define CV_32F  5
#define CV_64F  6
#define CV_USRTYPE1 7#define CV_MAT_DEPTH_MASK       (CV_DEPTH_MAX - 1)
#define CV_MAT_DEPTH(flags)     ((flags) & CV_MAT_DEPTH_MASK)#define CV_MAKETYPE(depth,cn) (CV_MAT_DEPTH(depth) + (((cn)-1) << CV_CN_SHIFT))#define CV_8UC1 CV_MAKETYPE(CV_8U,1)
#define CV_8UC2 CV_MAKETYPE(CV_8U,2)
#define CV_8UC3 CV_MAKETYPE(CV_8U,3)
#define CV_8UC4 CV_MAKETYPE(CV_8U,4)
#define CV_8UC(n) CV_MAKETYPE(CV_8U,(n))

Opencv3 core模块解析之convertTo相关推荐

  1. Spring的核心模块解析

    转载自 Spring的核心模块解析 Spring框架是一个轻量级的集成式开发框架,可以和任何一种框架集成在一起使用,可以说是一个大的全家桶.Spring从1.x发展到现在的5.x可以说是越来越强大,下 ...

  2. Opencores上的i2c controller core代码解析

    Opencores上的i2c controller core代码解析 一.i2c_eeprom_test.v 二.i2c_master_top.v 三.i2c_master_byte_ctrl.v 四 ...

  3. cuDNN 功能模块解析

    cuDNN 功能模块解析 Abstract 本cuDNN 8.0.4开发人员指南概述了cuDNN功能,如可自定义的数据布局.支持灵活的dimension ordering,striding,4D张量的 ...

  4. NVIDIA深度学习Tensor Core性能解析(下)

    NVIDIA深度学习Tensor Core性能解析(下) DeepBench推理测试之RNN和Sparse GEMM DeepBench的最后一项推理测试是RNN和Sparse GEMM,虽然测试中可 ...

  5. NVIDIA深度学习Tensor Core性能解析(上)

    NVIDIA深度学习Tensor Core性能解析(上) 本篇将通过多项测试来考验Volta架构,利用各种深度学习框架来了解Tensor Core的性能. 很多时候,深度学习这样的新领域会让人难以理解 ...

  6. Tensor Core技术解析(上)

    Tensor Core技术解析(上) NVIDIA在SIGGRAPH 2018上正式发布了新一代GPU架构--Turing(图灵),黄仁勋称Turing架构是自2006年CUDA GPU发明以来最大的 ...

  7. 实现一个webpack模块解析器

    最近在学习 webpack源码,由于源码比较复杂,就先梳理了一下整体流程,就参考官网的例子,手写一个最基本的 webpack 模块解析器. 代码很少,github地址:手写webpack模块解析器 整 ...

  8. python中json模块_Python使用内置json模块解析json格式数据的方法

    本文实例讲述了Python使用内置json模块解析json格式数据的方法.分享给大家供大家参考,具体如下: Python中解析json字符串非常简单,直接用内置的json模块就可以,不需要安装额外的模 ...

  9. boost::core模块实现范围枚举C++11

    boost::core模块实现范围枚举C++11 实现功能 C++实现代码 实现功能 boost::core模块实现范围枚举C++11 C++实现代码 #include <boost/core/ ...

  10. boost::core模块lightweight的测试实例

    boost::core模块lightweight的测试实例 实现功能 C++实现代码 实现功能 boost::core模块lightweight的测试实例 C++实现代码 #include <v ...

最新文章

  1. eclipse调试详解
  2. C语言基本数据结构之一(线性链表的增,删,改,查及倒序)
  3. R语言实战应用精讲50篇(十四)-R语言构建层次分析模型
  4. 面试宝典_Python.常规算法.0002.输出任意两个字符串中最长公共子串?
  5. dx postprocess
  6. [TJOI2012] 旅游(树的直径)
  7. kmp学英语必须设置
  8. poj 1236 Network of Schools (强连通分支缩点)
  9. paper 6:支持向量机系列三:Kernel —— 介绍核方法,并由此将支持向量机推广到非线性的情况。...
  10. 物联网卡行业目前存在哪些问题
  11. UDK开发环境搭建完全流程
  12. Mac快捷键大全-网络整理
  13. 快速找回Edge浏览器书签的方法
  14. 百度贴吧恶意代码分析
  15. IBM识别癌变细胞技术取得重大突破,用深度学习与神经网络重塑病理学
  16. 记录Widows10系统崩溃后安装Widows7系统的心酸历程
  17. pip使用详解/pip换源
  18. Resolve operation not in progress, we are not resuming.
  19. 【练习】苏宁易购注册界面的实现
  20. 基于天问block编译环境下ASRPRO语音芯片程序编写教程(二)语音识别,GPIO输入输出,PWM输出篇

热门文章

  1. c语言校招笔试试题,腾讯2014校园招聘C语言笔试题
  2. windos读写ext3工具_“ ext2fsd” Windows系统工具,用于读写ext2 / 3/4文件系统
  3. for linux pdf转mobi_linux PDF转换为SWF
  4. 下载蓝盒插件_bilibili哔哩哔哩下载助手
  5. CAN通信(2)——CAN通信协议层
  6. 小程序思维导图(基础图)
  7. Restsharp 与 unity3D WWW
  8. ArcGIS教程 - 8 空间数据拓扑处理
  9. Linux下编译DCMTK,ACE问题记录
  10. 面向对象方法和结构化方法比较,形式化方法的实际运用困难,及如何结合使用这三种