学习OpenCV(3)了解OpenCV的数据类型-3

  • Post author:
  • Post category:其他

目录

工具函数

cv::alignPtr()

cv::alignSize()

cv::allocate()

cv::deallocate()

cv::fastAtan2()

cv::cubeRoot()

cv::CV_Assert() & cv::CV_DbgAsser()

cv::error()

cv::CV_Error() & cv::CV_Error_()

cv::fastFree()

cv::fastMalloc()

cv::format()

cv::getCPUTickCount()

cv::getNumThreads()

cv::getOptimalDFTSize()

cv::getThreadNum()

cv::getTickCount()

cv::getTickFrequency()

cv::setNumThreads()

cv::setUseOptimized()

cv::useOptimized()

cvIsInf()

cvIsNaN()

cvRound()

cvCeil()

cvFloor()

练习


工具函数

OpenCV提供一些专用功能,可用于更有效地处理计算机视觉应用中普遍出现的数学和其他问题。它们被称为工具函数。工具函数包含数学操作、测试、错误生产、内存与线程处理、优化及其他的工具。

工具函数和系统函数:

函数名称 描述
cv::alignPtr() 对齐指针到给定字节数
cv::alignSize() 将缓冲区大小与给定的字节数对齐
cv::allocate() 分配一个C风格的数组对象
cv::cubeRoot() 计算一个数的立方根
cv::CV_Assert() 如果给出的条件不为真,则抛出异常
cv::deallocate() 释放一个C风格的数组对象
cv::error() 指示错误并抛出异常
cv::fastAtan2() 向量的二维角度的计算
cv::fastFree() 释放一个内存缓冲区
cv::fastMalloc() 分配一个对齐的内存缓冲区
cv::format() 以sprintf类型格式创建一个STL字符串
cv::getCPUTickCount() 从内部CPU计时器获得tick计数
cv::getNumThreads() 获得当前OpenCV使用的线程数
cv::getOptimalDFTSize() 计算要传递给cv::DFT()的数组的最适宜大小
cv::getThreadNum() 获得当前线程的索引
cv::getTickCount() 获得系统的tick计数
cv::getTickFrequency() 获得每秒的tick数
cv::setNumThreads() 设定OpenCV使用的线程数
cv::setUseOptimized() 开启或关闭优化代码(SSE2等)
cv::useOptimized() 指示代码优化的启用
CV_Error() 构造cv:Exception(从固定的字符串)并抛出异常的一个宏
CV_Error_() 构造cv:Exception(从格式化的字符串)并抛出异常的一个宏
cvIsInf() 判断一个浮点数x是否无穷
cvIsNaN() 判断一个浮点数x是否不是一个数
cvRound() 判断一个浮点数x到最近的整数
cvCeil() 近似一个浮点数x到不小于x的最近的整数(向上取整)
cvFloor() 近似一个浮点数x到不大于x的最近的整数(向下取整)

cv::alignPtr()

template<typename _Tp >
static _Tp* cv::alignPtr(
    _Tp *ptr,
	int n = (int)sizeof(_Tp) 
)

参数:
	ptr 需要对齐的指针
	n 必须是2的幂的对齐大小。
函数返回值为对齐后的指针地址

将指针与指定的字节数对齐。该函数返回与输入指针相同类型的对齐指针:

(_Tp*)(((size_t)ptr + n-1) & -n)

在某些架构上,只有能被指定数(如4,16)整除的内存地址才能够被访问,否则程序会crash,或者出现错误的结果,或者数据的访问变慢。

opencv2.0以上版本很多指针都是被对齐过的,使指针地址能够被16整除。opencv中的内存一般是通过malloc分配,不能保证都是都能被16整除,此时需要截断,CV2.0在 malloc 是多申请一个指针的空间,这个指针指向 malloc 得到的真实内存地址,只在 free 时使用它。

对于指向任意地址的一个指针,OpenCV中可以使用cv::alignPtr()函数将其位移到后面最近的一个能整除n的地址,其中n必须是一个2的幂。

关于 &-n:n是2的幂,其二进制也就只有一个1,比如n默认为16的时候为00010000,取负数得到111110000,效果是对于2k ,得到一个低k为0,其他位为1的数,拿这个数(-n)和别的数做与操作,等于把别的数的低k位截没了。这样得到的数必然是2k 的倍数(低k位为0的数必然是2k 的倍数)。这一效果仅对n=2^k成立。

cv::alignSize()

static size_t cv::alignSize(
	size_t sz,
    int n = sizeof(T)
);
参数:
    sz:要对齐的缓冲区大小。
    n:必须是2的幂的对齐大小

将缓冲区的大小与指定的字节数对齐。

该函数返回大于或等于sz且可被n整除的最小数:(计算此缓冲区应该的大小,以便包含大小为n个整数的对象)

(s + n – 1) & -n

cv::allocate()

template<class T>
T* cv::allocate(
	size_t sz;		//数组大小,n * sizeof(T)
);

该函数与数组形式的new相似,都分配了含n个T类型对象的C风格数组,为每个对象调用默认构造函数并返回指向数组中第一个对象的指针。

示例: void cv::AutoBuffer<_Tp, fixed_size>::allocate(size_t size);

分配大小为 size 的新缓冲区。如果size 足够小,则使用栈分配的缓冲区。

template<typename _Tp, size_t fixed_size=4096/sizeof(_Tp)+8> 
class CV_EXPORTS AutoBuffer
{
public:
    typedef _Tp value_type;
    enum { buffer_padding = (int)((16 + sizeof(_Tp) - 1)/sizeof(_Tp)) };
 
    //! the default contructor
    AutoBuffer();
    //! constructor taking the real buffer size
    AutoBuffer(size_t _size);
    //! destructor. calls deallocate()
    ~AutoBuffer();
 
    //! allocates the new buffer of size _size. if the _size is small enough, stack-allocated buffer is used
    void allocate(size_t _size);
    //! deallocates the buffer if it was dynamically allocated
    void deallocate();
    //! returns pointer to the real buffer, stack-allocated or head-allocated
    operator _Tp* ();
    //! returns read-only pointer to the real buffer, stack-allocated or head-allocated
    operator const _Tp* () const;
 
protected:
    //! pointer to the real buffer, can point to buf if the buffer is small enough
    _Tp* ptr;
    //! size of the real buffer
    size_t size;
    //! pre-allocated buffer
    _Tp buf[fixed_size+buffer_padding];
};

cv::AutoBuffer<int> b;
b[0] = 1;
cout << b.size() << endl;

cv::deallocate()

template<T>
void cv::deallocate(
	T* ptr,			//需要释放的buffer指针
    size_t sz		//buffer的大小,n * sizeof(T)
);

cv::deallocate()函数与数组形式的delete相似,都释放含有n个T类型对象的C风格数组,为每个对象调用析构函数。

cv::deallocate()用于释放由cv::allocate()分配的对象,元素n必须与分配的n一致。

cv::fastAtan2()

float cv::fastAtan2(
	float y,	//向量的y坐标
    float x		//向量的x坐标
);

以度为单位计算二维向量的角度,函数fastAtan2 计算输入2D矢量的全范围角度,角度从0-360°不等,精度约为0.3°。

cv::cubeRoot()

float cv::cubeRoot(
	float x
);
double cv::cubeRoot(
	double x
);

这个函数计算变量x的立方根,负数值的x也能正确处理,返回负值。

cv::CV_Assert() & cv::CV_DbgAsser()

#define CV_Assert(expr)
do { 
    if(!!(expr)) ; 
    else 
        cv::error( cv::Error::StsAssert, #expr, CV_Func, __FILE__, __LINE__ ); 
} while(0)

CV_Assert()是一个宏,它会测试传递给它的表达式,如果表达式为false,它将抛出异常。

CV_DbgAsser()只可用于Debug模式。

cv::error()

void cv::error(
	const cv::Exception &ex
);

这个函数大多数是由CV_ERROR() 和CV_ERROR_()调用的,这些宏带着在异常中展示的信息,为你打包好,然后传递最终的异常结果给cv::error();

cv::CV_Error() & cv::CV_Error_()

//example
CV_Error(ecode, estring);
CV_Error_(ecode, fmt, ...);

cv::CV_Error() 宏允许传递一个错误代码ecode和一个固定C风格的字符串estring,然后将其打包进cv::Exception,进而传递给cv::error()进行处理。

如果需要在运行过程中构建消息,那么使用宏CV_Error_,允许传递一个错误码ecode,和一个sprintf()风格的字符串后面紧跟着各种变量参数,就是sprintf()所需要的。

cv::fastFree()

void cv::fastFree(
	void *ptr
);

释放由cv::fastMalloc() 分配的内存。

cv::fastMalloc()

void* cv::fastMalloc(
	size_t size 		//需要分配的buffer大小
);

cv::fastMalloc()工作机制与 malloc()类似,但它会进行内存对齐。这意味着如果传递的缓存区大小超过16比特,返回的缓冲区会被对齐到16比特的边界。

cv::format()

string cv::format(
	const char* fmt,	//格式化字符串
    ...					//vargs, 类似sprintf()
);

这个函数本质上与标准库中的sprintf()相同,它不需要从访问者获得一个字符缓存区,而是构建一个STL字符并返回它。它对Exception()构造函数格式化错误信息很有用。

cv::getCPUTickCount()

int64 cv::getCPUTickCount(void);

这个函数返回CPU的ticks数量,包括但不限于x86架构。

这个函数对于初始化随机数生成器这样的任务很适用。

cv::getNumThreads()

int cv::getNumThreads(void);

返回当前OpenCV适用的线程数。

cv::getOptimalDFTSize()

int cv::getOptimalDFTSize(int n);  

cv::getOptimalDFTSize()的一般输入为图片的实际大小,并返回应给传递给cv::dft()的数组大小。

cv::getThreadNum()

int cv::getThreadNum(void);

如果OpenCV库编译时,添加了OpenMP支持,则返回当前执行的线程的索引(从零开始)。

cv::getTickCount()

long int cv::getTickCount(void); 

该函数返回了与一些体系结构相关的时间的tick计数。

每个tick时间可以用cv::getTickFrequency()计算。

该函数比cv::getCPUTickCount()应用更广,它不会受线程跑在那个核或CPU降频等底层问题的影响。

cv::getTickFrequency()

double cv::getTickFrequency(void);		//返回每秒的滴答数。

该函数返回每秒的滴答数。

为了计算某些事件发生的时间,只需要在函数调用前后调用cv::getTickCount(),两个时间相减并除以cv::getTickFrequency()的返回值即可。

double t = (double)getTickCount();
// do something ...
t = ((double)getTickCount() - t)/getTickFrequency();

cv::setNumThreads()

void cv::setNumThreads(int nthreads);	//设置OpenCV可以使用线程的数目

当OpenCV编译时加入了OpenMP的支持,这个函数可以设定OpenMP区域使用的线程数。

如果nthreads为0,则线程数量被重新定为默认值。

cv::setUseOptimized()

void cv::setUseOptimized(bool on_off);

默认情况下,优化例程是启用的,除非你在安装时禁用它。可以使用cv::setUseOptimized()在任何时候开启和关闭这些优化。

对优化用法的全局标志的测试是在opencv库函数中相对较高的级别上完成的。这表示在任何其他的例程(或函数)运行的时候,都不应该调用cv::setUseOptimized()。

cv::useOptimized()

bool cv::useOptimized(void);
返回值:
    true:优化在当前是开启的
    false:优化是关闭的

在任何时候,都可以使用cv::useOptimized()来检查优化的全局标记的状态。

cvIsInf()

int cvIsInf(double x);

如果x是 正负无穷, 则cvIsInf()返回值是1, 否则返回0.

cvIsNaN()

int cvIsNaN(double x);

如果x不是一个数,cvIsNaN()返回1,否则返回0.

cvRound()

int cvRound(double x);

给定一个浮点数x,cvRound()计算与x最近的整数。如果输入值超出32位整型表示的范围,结果就是undefined(未定义)

cvCeil()

int cvCeil(
	float x
);

给定一个浮点数x, cvCeil()计算不小于x的最小整数(向上取整)。如果输入超出了32位整数的表示范围,则结果返回未定义(undefined)。

cvFloor()

int cvFloor(
	float x
);

给定一个浮点数x, cvCeil()计算不大于x的最小整数(向下取整)。如果输入超出了32位整数的表示范围,则结果返回未定义(undefined)。

练习

  1. 找到并打开cxtyes.h,通读并找到很多转换帮助函数。

a. 选择一个负的浮点数

b. 计算它的绝对值,近似,向上取整,向下取整

c. 产生一些随机数

d. 生成一个浮点数的cv::Point2f, 把它转换成整型的cv::Point,把cv::Point 转换成cv::Point2f.

int main()
{
	srand(time(NULL));

	float a = -3.14;
	cout << "绝对值:" << cv::abs(a) << ". 近似:" << cvRound(a) << ". 向上取整:" << cvCeil(a) << ". 向下取整:"
		<< cvFloor(a) << endl;

	//cv::RNG rng(rand());
	//int x1 = (int)rng % 1000;

	//cout << x1 << endl;

	//cv::Point2f p1(rng.uniform(0.0, 1000.0), rng.uniform(0.0, 1000.0));
	//cout << p1 << endl;

	//cv::Point p2 = (cv::Point)p1;
	//cout << p2 << endl;


	CvPoint point1 = cvPoint(50, 50);
    cout << "(" << point.x << ", " << point.y << ")" <<endl;
	CvPoint2D32f pointf1 = cvPointTo32f(point1);
	cout << "(" << pointf1.x << ", " << pointf1.y << ")" <<endl;

	CvPoint2D32f pointf2 = cvPoint2D32f(50.9876, 50.3565);
	cout << "(" << pointf2.x << ", " << pointf2.y << ")" <<endl;
	CvPoint point2 = cvPointFrom32f(pointf2);
	cout << "(" << point2.x << ", " << point2.y << ")" <<endl;

	return EXIT_SUCCESS;
}

2. 紧凑型矩阵和向量类

a.用cv::Mat33f 和 cv::Vec3f 对象,对应生成一个3 * 3 的矩阵和3行的向量

b.可以直接把他们两个相乘吗?如果不行,为什么?

int main()
{
	cv::RNG rng(0);
	cv::Matx33f m33(rng.uniform(0.0, 100.0), rng.uniform(0.0, 100.0), rng.uniform(0.0, 100.0), 
					rng.uniform(0.0, 100.0), rng.uniform(0.0, 100.0), rng.uniform(0.0, 100.0), 
					rng.uniform(0.0, 100.0), rng.uniform(0.0, 100.0), rng.uniform(0.0, 100.0));

	cv::Vec3f v3(rng.uniform(0.0, 100.0), rng.uniform(0.0, 100.0), rng.uniform(0.0, 100.0));

	cout << m33 << endl;
	cout << v3 << endl;

	cout << m33 * v3 << endl;

	return EXIT_SUCCESS;
}

版权声明:本文为ma1499060246原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。