前言
OpenCV作为一个机器视觉的库,对机器视觉的应用程序开发者或者机器视觉的SDK开发者而言,了解OpenCV是十分有必要的。读者可以通过OpenCV官方使用在线文档了解OpenCV的函数。如果你需要搭建相关环境,可参照笔者的另一篇文章Win10系统下搭建OpenCV环境。
准备好后,可以在vs的工程下看到OpenCV的源码,类似于这样
读取图像源码介绍
这里通过介绍imread函数和GaussianBlur函数,简单说明下OpenCV的源码
imread函数是十分常用的,能够用于读取多种图片,其源码可以在module模块下的opencv_imgcodecs的src下
Mat imread( const String& filename, int flags )
{
CV_TRACE_FUNCTION();
/// create the basic container
Mat img;
/// load the data
imread_( filename, flags, img );
/// optionally rotate the data if EXIF' orientation flag says so
if( !img.empty() && (flags & IMREAD_IGNORE_ORIENTATION) == 0 && flags != IMREAD_UNCHANGED )
{
ApplyExifOrientation(filename, img);
}
/// return a reference to the data
return img;
}
imread是一个用于图片读取的函数,但OpenCV的开发者在其中倾注的心血却不容小觑。一方面OpenCV会加入大量的类似于__FILE__和__LINE__之类的宏名以帮助调试;另一方面,OpenCV为读者添加了多种图片的格式的读取方案。但如果你需要用到一些特殊的图片格式,例如医学领域常用的dcm图,那你就很可能需要自己动手来实现,不过OpenCV的Mat数据结构也是很好的图像处理工具,要知道,例如Qt的QImage以及Halcon的图像都是有做大小限制的,而Mat是支持大图的。
通过在线文章,则能够很好的了解函数的功能
值得注意的是,OpenCV的imread默认读取采图,flags = -1,表示格式不变,0表示以黑白图读取。
OpenCV的优化
以高斯滤波函数为例,可以看到OpenCV的开发者做的许多优化
void GaussianBlur(InputArray _src, OutputArray _dst, Size ksize,
double sigma1, double sigma2,
int borderType)
{
CV_INSTRUMENT_REGION();
int type = _src.type();
Size size = _src.size();
_dst.create( size, type );
if( (borderType & ~BORDER_ISOLATED) != BORDER_CONSTANT &&
((borderType & BORDER_ISOLATED) != 0 || !_src.getMat().isSubmatrix()) )
{
if( size.height == 1 )
ksize.height = 1;
if( size.width == 1 )
ksize.width = 1;
}
if( ksize.width == 1 && ksize.height == 1 )
{
_src.copyTo(_dst);
return;
}
bool useOpenCL = (ocl::isOpenCLActivated() && _dst.isUMat() && _src.dims() <= 2 &&
((ksize.width == 3 && ksize.height == 3) ||
(ksize.width == 5 && ksize.height == 5)) &&
_src.rows() > ksize.height && _src.cols() > ksize.width);
CV_UNUSED(useOpenCL);
int sdepth = CV_MAT_DEPTH(type), cn = CV_MAT_CN(type);
Mat kx, ky;
createGaussianKernels(kx, ky, type, ksize, sigma1, sigma2);
CV_OCL_RUN(useOpenCL, ocl_GaussianBlur_8UC1(_src, _dst, ksize, CV_MAT_DEPTH(type), kx, ky, borderType));
CV_OCL_RUN(_dst.isUMat() && _src.dims() <= 2 && (size_t)_src.rows() > kx.total() && (size_t)_src.cols() > kx.total(),
ocl_sepFilter2D(_src, _dst, sdepth, kx, ky, Point(-1, -1), 0, borderType))
Mat src = _src.getMat();
Mat dst = _dst.getMat();
Point ofs;
Size wsz(src.cols, src.rows);
if(!(borderType & BORDER_ISOLATED))
src.locateROI( wsz, ofs );
CALL_HAL(gaussianBlur, cv_hal_gaussianBlur, src.ptr(), src.step, dst.ptr(), dst.step, src.cols, src.rows, sdepth, cn,
ofs.x, ofs.y, wsz.width - src.cols - ofs.x, wsz.height - src.rows - ofs.y, ksize.width, ksize.height,
sigma1, sigma2, borderType&~BORDER_ISOLATED);
CV_OVX_RUN(true,
openvx_gaussianBlur(src, dst, ksize, sigma1, sigma2, borderType))
CV_IPP_RUN_FAST(ipp_GaussianBlur(src, dst, ksize, sigma1, sigma2, borderType));
if(sdepth == CV_8U && ((borderType & BORDER_ISOLATED) || !_src.getMat().isSubmatrix()))
{
std::vector<ufixedpoint16> fkx, fky;
createGaussianKernels(fkx, fky, type, ksize, sigma1, sigma2);
if (src.data == dst.data)
src = src.clone();
CV_CPU_DISPATCH(GaussianBlurFixedPoint, (src, dst, (const uint16_t*)&fkx[0], (int)fkx.size(), (const uint16_t*)&fky[0], (int)fky.size(), borderType),
CV_CPU_DISPATCH_MODES_ALL);
return;
}
sepFilter2D(src, dst, sdepth, kx, ky, Point(-1, -1), 0, borderType);
}
通过高斯滤波的源码,我们可以发现,opencv中有对代码做一些加速的操作,比如IPP等。笔者比较青睐的Cuda加速方式,在OpenCV的源码中也能找到许多实例。
关于机器视觉库
OpenCV是使用广泛的机器视觉库,但有一些视觉库在算法优化上走得比OpenCV更靠前,比如Halcon和matlab的mVision等。OpenCV最大的好处是开源且应用广泛,很多培训机构一股脑的推销他们的高价OpenCV课程,这些课程动辄上万,这是一种不负责任的行为。
关于学习OpenCV
对于Cpp功底不是那么好的同学(写过一定代码,完整读过三本以上的cpp书籍),建议使用Python学习OpenCV。Python伊甸园的OpenCV处理图像会是一个不错的入门课程;CPP版本的OpenCV其核心的数据结构是Mat,而python版本的OpenCV其核心是numpy,同样,也为您准备好了相应的numpy课程。如果你的Python功底也不是很好的话,那么可以考虑这份Python入门课程。
作者说
如有错误之处,欢迎批评指正。如果你认为咨询我是有必要的,我的邮箱是[email protected];如果你认为打赏我是有必要的,我的支付宝账号是[email protected]。