【翻译】Seeing With OpenCV - Part 1: Introduction to OpenCV

本文翻译自Robin Hewitt的《Seeing With OpenCV - A Five-Part Series》。

正如标题所表达的那样,通过连载的五篇文章,我们将通过step by step的方式,实现一个人脸识别的程序,即从原始图片中检测脸部,并通过某种算法从样本库中筛选近似的肖像加以匹配,这是相当有用&有趣的应用。

这是本系列的第一章,主要介绍OpenCV及其一些简单用法。

[size=x-large]1、OpenCV简介[/size]
OpenCV是一款免费、开源、使用C&C++编写的计算机视觉库,可以从[url]http://sourceforge.net/projects/opencvlibrary[/url]
下载获得。

Intel在1999年发布了OpenCV的第一个版本,当时它需要Intel的图形处理包。现在,这个限制已经被去除,你可以像使用任何一个标准库一样使用OpenCV。

OpenCV被设计为跨平台,同时支持Windows、Linux以及MacOSX。有一个例外,CVCAM(负责摄像头处理)被设计为平台相关,这点后面会讨论到。

[size=x-large]2、特点[/size]
OpenCV具有强大的图形处理功能,庞大的API可能会让初学者产生畏惧感。因此,作为初学者,你只需要了解其中最常用的部分。

[size=medium][i]通用计算机视觉以及图形处理算法(中、低层API)[/i][/size]
使用这些接口,无需复杂的编写图像算法就可以实现一些常用的图像处理功能,包括边缘&直线&角的检测、椭圆拟合、多分辨率的图形金字塔算法、模板匹配,各种变换(傅里叶、离散余弦、距离)等等。

[size=medium][i]高层计算机视觉模块[/i][/size]
OpenCV包含了许多高层的功能,例如脸部检测&识别&跟踪等

[size=medium][i]人工智能与机器学习方法[/i][/size]
计算机视觉的问题往往会涉及到一些机器学习以及人工智能的方法,这些都被包装在OpenCV的机器学习包里面

[size=medium][i]图像采样与视角变换[/i][/size]
OpenCV提供了图像子区域提取、随机采样、图形缩放、包装、旋转以及透视变换等功能

[size=medium][i]二值化图像的创建和处理[/i][/size]
OpenCV提供的二值化图像的创建和分析功能,在监控、形状检测以及物件计数等领域往往很有用

[size=medium][i]3D计算与处理[/i][/size]
这些方法可以用于3D建模和定位,以及摄像机的多视角处理

[size=medium][i]用于图像处理、计算机视觉的数学库[/i][/size]
OpenCV提供了大量常用的数学运算库,包括线性代数、统计学以及几何运算等等

[size=medium][i]作图[/i][/size]
这些接口可以使你很方便地再图片上写字或者作画。可以通过它实现一些简单的水印功能,或者辅助其它更高阶的功能,例如在进行物体识别的同时,可以使用该接口标记检测出来的位置和区域。

[size=medium][i]GUI[/i][/size]
OpenCV封装了许多跨平台的GUI接口作为API,你可以实现自己的应用,操作键盘、鼠标、滑块等控件。

[size=medium][i]数据结构与算法[/i][/size]
使用这些接口,你可以有效地存储、查询、保存和操作一些常用的数据结构,比如链表、几何、树、图等

[size=medium][i]数据持久化[/i][/size]
这些接口提供了将数据保存到本地以便日后读取的功能

下图展示了OpenCV的一些应用场景,包括脸部识别、轮廓检测以及边缘检测。

[img]http://dl.iteye.com/upload/attachment/465062/bc22eb11-285a-3f08-b375-a41a0087c46c.png[/img]

[size=x-large]3、模块结构[/size]
OpenCV包含以下几个模块:

CXCORE包含了一些基本的数据类型的定义。例如,一些常见的图、点、矩形等数据结构定义在cxtypes.h中。CXCORE同时也包含含线性代数和统计等模块,以及持久化函数、错误句柄处理、以及画图等功能。

CV包含了图像处理以及摄像机校正、几何计算等方法。

CVAUX包含了一些实验型的方法,比如脸部识别等

ML主要是一些机器学习的方法

HighGUI包含了一些基本的IO操作以及一些跨平台的界面调用接口

CVCAM包含了一些视频处理的接口,使得你不必亲自去使用DirectX

[size=x-large]4、OpenCV编程基础[/size]
[size=medium][i]关于头文件与库文件的引用[/i][/size]
本文所介绍的大部分程序都需要引用cv.h和highgui.h。脸部识别的程序还需要添加cvaux.h。这些头文件自身引用了其余的大多数其它头文件。

你的连接器也需要添加cxcore.lib、cv.lib以及highgui.lib。对于脸部识别的程序,还需要添加cvaux.lib,它们都在OpenCV的lib目录下。

[size=medium][i]图片的读写[/i][/size]
下面的实例代码说明了如何读取图片文件,并采用不同的压缩格式(jpg -> png)保存为另一个文件。

#include <stdio.h>

int main(int argc, char** argv)
{
IplImage * pInpImg = 0;

// Load an image from file
pInpImg = cvLoadImage("my_image.jpg", CV_LOAD_IMAGE_UNCHANGED);
if(!pInpImg)
{
fprintf(stderr, "failed to load input image\n");
return -1;
}

// Write the image to a file with a different name,
// using a different image format -- .png instead of .jpg
if( !cvSaveImage("my_image_copy.png", pInpImg) )
{
fprintf(stderr, "failed to write image file\n");
}

// Remember to free image memory after using it!
cvReleaseImage(&pInpImg);

return 0;
}


当读取图片时,仅需要调用cvLoadImage方法,并且传递给他文件名作为参数即可(如第十四行所述)。OpenCV支持常见的大多数的图片格式,包括JPEG、PNG和BMP(目前还不支持GIF)。你无须关心图片具体是按照何种格式压缩保存的,cvLoadImage会在读取图片头文件信息的时候决定采用哪一种格式的解码器。

可以通过cvSaveImage方法将内存中的图片保存为文件。保存文件时,采用何种压缩格式,是由传入的文件的扩展名决定的。比如,传入参数为"XXX.png",就以PNG的格式来存储。

在调用cvLoadImage之后,使用完图片资源之后务必记得调用cvReleaseImage来释放内存。

cvLoadImage与cvSaveImage都被封装在HighGUI模块中。

[size=medium][i]色彩空间的转换[/i][/size]
下面的例子说明了如何将一幅图片转化为灰度图。OpenCV内置了许多色彩空间模型方便自由地转换,包括RGB、HSV、YCrCb已经CIELAB等等。如果你对色彩模型感兴趣,推荐看SERVO Magazine的《The World of Color》。

// ConvertToGray.c
// Example showing how to convert an image from color
// to grayscale

#include "stdio.h"
#include "string.h"
#include "cv.h"
#include "highgui.h"

int main(int argc, char** argv)
{
IplImage * pRGBImg = 0;
IplImage * pGrayImg = 0;

// Load the RGB image from file
pRGBImg = cvLoadImage("my_image.jpg", CV_LOAD_IMAGE_UNCHANGED);
if(!pRGBImg)
{
fprintf(stderr, "failed to load input image\n");
return -1;
}

// Allocate the grayscale image
pGrayImg = cvCreateImage
( cvSize(pRGBImg->width, pRGBImg->height), pRGBImg->depth, 1 );

// Convert it to grayscale
cvCvtColor(pRGBImg, pGrayImg, CV_RGB2GRAY);

// Write the grayscale image to a file
if( !cvSaveImage("my_image_gray.jpg", pGrayImg) )
{
fprintf(stderr, "failed to write image file\n");
}

// Free image memory
cvReleaseImage(&pRGBImg);
cvReleaseImage(&pGrayImg);

return 0;
}

注意,具体执行色彩转换的函数——cvCvtColor,其参数列表包含两个图片指针类型,第一个参数,pRGBImg,代表源图像。第二个参数,pGrayImg,代表目标图像。

注意25行,我们使用cvCreateImage创建了一个与原始图像相同尺寸,但为初始化像素的数据结构,这类操作在今后的OpenCV编程中会很常见。

[size=medium][i]OpenCV图片的数据结构[/i][/size]

OpenCV使用标准的C语言结构体来。其中,IPL是Image Processing Library的缩写。IplImage是在CXCOR中定义的,除了原始的像素数据之外,它还定义了一些元数据(描述字段),统一称为图片的“头文件”。它包括:

[list]
[*]width —— 图片宽度,以像素为单位
[*]height —— 图片高度,以像素为单位
[*]depth —— 图片位深,即每通道每像素所包含的位的数目。比如,depth为IPL_DEPTH_8U,则表示单个通道的每个像素为8位无符号类型,即0-255
[*]nChannels —— 通道数量,一般为1-4. 每个通道包含一种像素数据类型。比如RGB图像包含三个通道,因为每个像素都存储了红、绿、蓝三种颜色信息;而灰度图像只包含一个通道,即像素的亮度。
[/list]
[size=medium][i]操作像素值[/i][/size]
事实上,使用OpenCV的大部分应用,都不需要去直接操作原始的像素数据,比如脸部检测、追踪、识别等;它们只需要使用图像指针以及其它的一些高层的数据结构。OpenCV的许多函数封装了像素级别的计算。尽管如此,你还是会有直接操作原始像素数据的场景,比如当你需要自己写一些图形算法的时候。下面介绍两种操作像素的方法:

[i]1、简单的像素操作[/i]
最简单的读取单个像素的方法时采用cvGet2D方法:

该函数具有三个参数:一个指向数据容器的指针(CVArr*)以及代表了位置坐标(第几行第几列)的数组。数据容器可以使IplImage结构体。最顶上一行的像素的row=0,最低部一行的row=height-1。

cvGet2D返回一个C结构体,CvScalar,其定义如下:
typedef struct CvScalar
{
double val[4];
}
CvScalar;


每个通道的像素值被保存在val[i]中。对于灰度图像,val[0]代表了像素的亮度值,而其它三个值则被设为0,。对于三通道的BGR图片,blue=val[0],green=val[1],red=val[2]。

另一个函数,cvSet2D方法允许你修改像素值,它的定义如下:
void cvSet2D(CvArr*, int row, int col, CvScalar);


[i]2、快速的像素操作[/i]
尽管vGet2D()以及cvSet2D()十分方便使用,但是对于批量存取大量像素点来说,它们的性能很糟糕。此种情况下,你需要直接从原生的数据缓存,即IplImage.imageData中读取像素值。

缓存中的图像数据以一维数组的形式存放,以行优先的顺序,即:先顺序存放第一行的所有数据,再存放第二行的所有数据,以此类推。

出于性能考虑,所有的像素数据都经过对齐,并且在需要的时候补0。IplImage的第二个字段,IplImage.widthStep,代表相邻两行数据之间的bit数,也就是说,第i行的数据指针指向
IplImage.imageData + i*IplImage.widthStep处。

IplImage.imageData被定义为char*类型,因此必要时你需要转换数据类型,比如,通常来说,你的图像数据是unsigned bytes,你在使用它时往往需要将其转化为unsigned char*。

如果你在操作的是位深等于8的灰度图像,可以通过如下方式操作pixel[row][col]:
pixel[row][col] =
(uchar*)(pImg->imageData + row*pImg->widthStep + col);


最后,如果遇到图片的位深大于8bit的情况(比如,IPL_DEPTH_32S),你需要将其转化为多字节的数据类型,并且将其width step乘以字节数作为其实际的位深(比如,对于IPL_DEPTH_32S来说,你需要将buffer转化为int*,并且将使用4倍的width step。)。尽管如此,实际情况下,很少会遇到需要直接操作多字节像素值的场景。

[size=x-large]5、下一章预告[/size]
在Part 2,我将会介绍如何使用OpenCV来实现脸部检测,并且详细讲解其背后的算法,感谢你的阅读。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
报错:2023-07-12 05:36:51,389: *************************************************** 2023-07-12 05:39:07,664: Error running WSGI application 2023-07-12 05:39:07,667: ModuleNotFoundError: No module named 'flask' 2023-07-12 05:39:07,667: File "/var/www/chengyg_pythonanywhere_com_wsgi.py", line 16, in <module> 2023-07-12 05:39:07,667: from app import app as application # noqa 2023-07-12 05:39:07,667: 2023-07-12 05:39:07,667: File "/home/ChengYg/big_screen-master/app.py", line 8, in <module> 2023-07-12 05:39:07,667: from flask import Flask, render_template 2023-07-12 05:39:07,667: *************************************************** 2023-07-12 05:39:07,668: If you're seeing an import error and don't know why, 2023-07-12 05:39:07,668: we have a dedicated help page to help you debug: 2023-07-12 05:39:07,668: https://help.pythonanywhere.com/pages/DebuggingImportError/ 2023-07-12 05:39:07,668: *************************************************** 2023-07-12 05:39:15,977: Error running WSGI application 2023-07-12 05:39:15,978: ModuleNotFoundError: No module named 'flask' 2023-07-12 05:39:15,979: File "/var/www/chengyg_pythonanywhere_com_wsgi.py", line 16, in <module> 2023-07-12 05:39:15,979: from app import app as application # noqa 2023-07-12 05:39:15,979: 2023-07-12 05:39:15,979: File "/home/ChengYg/big_screen-master/app.py", line 8, in <module> 2023-07-12 05:39:15,979: from flask import Flask, render_template 2023-07-12 05:39:15,980: *************************************************** 2023-07-12 05:39:15,980: If you're seeing an import error and don't know why, 2023-07-12 05:39:15,980: we have a dedicated help page to help you debug: 2023-07-12 05:39:15,980: https://help.pythonanywhere.com/pages/DebuggingImportError/ 2023-07-12 05:39:15,980: ***************************************************
07-14
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值