分析opencv的图像输入\出基本框架

本文深入分析了OpenCV如何通过图像的读取引擎解析不同格式的图像文件,介绍了从读取文件头信息到调用解码引擎的过程,涉及到Ptr模板类、BaseImageDecoder和BaseImageEncoder等关键组件。通过实例解析了BMP位图的读取流程,揭示了OpenCV在处理图像输入输出中的核心机制。
摘要由CSDN通过智能技术生成
文章转载请注明作者和出处,谢谢支持!

opencv其实是使用第三方库来对输入和输出图像格式进行解析,那么这个过程是怎么实现的?本着追根溯源的hack精神,让我们一起探索一番,首先看一下一般的图像处理过程:

一个典型的计算机视觉算法,应该包含以下一些步骤:
(1)数据获取(对OpenCV来说,就是图片);
(2)预处理;
(3)特征提取;
(4)特征选择;
(5)分类器设计与训练;
(6)分类判别;
而OpenCV对这六个部分,分别提供了API(这些API是相互独立的,但是共享一个图像基本数据结构)。其实其他的信号系统为基础的处理库也差不多是这个形式。
opencv中使用了图像的读取引擎来实现对不同输入图像文件的解析获得数据区以及图像的基本信息等,以读入图像文件为例,opencv使用文件读入操作将硬盘上的文件读入内存,然后判断文件头中的前几个字节信息来确定读入的文件是否是图像和该图像的类型,然后调用相关的图像解码引擎来对图像文件解析,获取长宽,颜色信息等内容,具体的流程是:
源代码位于:C:\opencv_vs2008\2.3.1\modules\highgui\src
1.C:\opencv_vs2008\2.3.1\modules\highgui\src\loadsave.cpp这个文件提供了基本的读入和写出函数的实现:
读入函数:
Matimread( conststring& filename,int flags )
{
Matimg;
imread_(filename, flags,LOAD_MAT, &img );
returnimg;
}
写出函数:
boolimwrite( conststring& filename,InputArray _img, constvector<int>&params )
{
Matimg = _img.getMat();
returnimwrite_(filename,img, params,false);
}
其中的
imread_(filename, flags,LOAD_MAT, &img );
imwrite_(filename,img, params, false);
是其实现的具体函数,使用了ImageDecoderImageEncoder引擎来解析和存储图像文件。
2.C:\opencv_vs2008\2.3.1\modules\highgui\src\grfmt_base.hpp和C:\opencv_vs2008\2.3.1\modules\highgui\src\grfmt_base.cpp
实现了虚基类ImageDecoderImageEncoder,在这个类中统一调用需要的图像文件解码器:
在这个类中使用了智能指针:
typedefPtr<BaseImageEncoder>ImageEncoder;
typedefPtr<BaseImageDecoder>ImageDecoder;
分析找出了Ptr的出处:c:\opencv_vs2008\2.3.1\include\opencv2\core\core.hpp的1223行
如下:
generic_type ref-counting pointer class for C/C++ objects
/*!
Smart pointer to dynamically allocated objects.
This is template pointer-wrapping class that stores the associated reference counter along with the
object pointer. The class is similar to std::smart_ptr<> from the recent addons to the C++ standard,
but is shorter to write :) and self-contained (i.e. does add any dependency on the compiler or an external library).
Basically, you can use "Ptr<MyObjectType> ptr" (or faster "const Ptr<MyObjectType>& ptr" for read-only access)
everywhere instead of "MyObjectType* ptr", where MyObjectType is some C structure or a C++ class.
To make it all work, you need to specialize Ptr<>::delete_obj(), like:
\code
template<> void Ptr<MyObjectType>::delete_obj() { call_destructor_func(obj); }
\endcode
\note{if MyObjectType is a C++ class with a destructor, you do not need to specialize delete_obj(),
since the default implementation calls "delete obj;"}
\note{Another good property of the class is that the operations on the reference counter are atomic,
i.e. it is safe to use the class in multi-threaded applications}
*/
template<typename_Tp> classCV_EXPORTS Ptr
{
public:
//! empty constructor
Ptr();
//! take ownership of the pointer. The associated reference counter is allocated and set to 1
Ptr(_Tp*_obj);
//! calls release()
~Ptr();
//! copy constructor. Copies the members and calls addref()
Ptr(constPtr& ptr);
//! copy operator. Calls ptr.addref() and release() before copying the members
Ptr&operator = (constPtr& ptr);
//! increments the reference counter
voidaddref();
//! decrements the reference counter. If it reaches 0, delete_obj() is called
voidrelease();
//! deletes the object. Override if needed
voiddelete_obj();
//! returns true iff obj==NULL
boolempty() const;
//! helper operators making "Ptr<T> ptr" use very similar to "T* ptr".
_Tp*operator -> ();
const_Tp* operator -> ()const;
operator_Tp* ();
operatorconst _Tp*()const;
protected:
_Tp*obj; //< the object pointer.
int*refcount; //< the associated reference counter
};
知道了openCV2.0以后使用了安全指针(也叫智能指针)Ptr template。据说这个是参考了 C++0x Boost 库的相关技术。
简单地说,就是加了个指针引用数(refcount)和一些方便调用的操作符重装(operator ->;())。值得注意的是,Ptr template 对指针指向的对象有一个要求,就是可以用 delete 操作土符来释放内存。你可能就想到 IplImage 就不满足这个要求了,这怎么办?可以使用模板特化(template specialization)重载 Ptr<Iplimage>::delete_obj() 函数:
template<> inline void Ptr<IplImage>::delete_obj()
{ cvReleaseImage(&obj); }
PS: 考虑到多线程时,CV2.0中的一些基本操作(如加法运算CV_ADD)都写成了函数或宏,保证互斥资源访问安全,看源代码时可注意下。
到这个时候就知道了ImageEncoderImageDecoder 就是纯虚基类的智能指针模板了,而且
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值