利用 OpenCV 识别图片中图形的轮廓
Windows 环境下 OpenCV, Cygwin, Eclipse 开发环境搭建与开发实例
Open CV 简介
OpenCV 是基于 BSD (Berkeley Software Distribution,伯克利软件套件)的开源的非商业盈利的计算机视觉和机器学习软件库,用来促进视觉的商业应用发展。它可以跨平台运行在 Windows,Android,Maemo,FreeBSD,OpenBSD,iOS,Linux 和 Mac OS 操作系统上。
OpenCV 主要由 C++语言编写,但是提供了 Python、Ruby、MATLAB 等编程语言的接口,实现了图像处理和计算机视觉方面的很多通用算法。使用者可以在 SourceForge 获得官方版本,或者从 SVN 获得开发版本。
本文从 OpenCV 的整体架构开始介绍,逐步深入介绍 Cygwin 的安装和配置、在 Eclipse 环境中 Cygwin 与 OpenCV 的集成以及安装配置中常见的问题和解决方案。最后用实际案例展示 OpenCV 如何忽略图片中的背景,识别出图形的轮廓。
搭建 OpenCV 开发环境
前提条件
- Windows 10
- Java 8.0
- OpenCV 最新版
- Eclipse CDT 4.1.6
- Cygwin 3.1.7
关系图及流程图
开发环境的关系图与流程图如下图所示。
图 1. 关系图
图 2. 流程图
Cygwin 安装
- 首先打开 Cygwin 官网 ,点击链接 setup-x86_64.exe(64 位)或 setup-x86.exe(32 位)下载安装程序并保存在本地。(不要保存在 c:\cygwin64,该目录将作为安装目录),然后运行安装程序 setup-x86_64.exe。
- 安装方式选择 Install from Internet,这种安装方式会保存安装程序供以后复用。
- 安装路径通常都使用默认的 c:\cygwin64,使用对象也选择默认值 All Users,选择一个路径存放安装程序,如 C:\Download,如果没有使用代理服务器,选择 Direct Connection,最后选择距离最近的网址作为下载源进行安装。
Cygwin 中 OpenCV 的安装与配置
在 Cygwin 安装过程中,可以搜索“libopencv-devel” 和“libopencv2.4”,选择最新版来安装 OpenCV。
图 3. Cygwin Setup
搜索 gcc 并安装下图所示的包做为 C++编译器。
图 4. gcc
搜索“cmake“,选择 Devel 下的 cmake 最新版,来安装 cmake 作为 C++的编译工具。
图 5. cmake
搜索 X11 目录下的“xinit”, “xorg-server”, “xorg-x11-fonts-XXXXX”的最新版,来安装用于 OpenCV 项目图形显示的 Xserver。
图 6. Xserver
最后完成安装即可。
Eclipse 中 Cygwin 与 OpenCV 的集成
从 Eclipse 官网下载并安装 Eclipse IDE for C/C++ Developers 202009。安装完成后运行 eclipse.exe 文件启动 eclispe。新建一个 C++项目(如果是第一次使用 eclipse 请新建一个 workspace)。点击 File > New > C++ Project,在 workspace 中创建 C++Project。
图 7. 创建项目
在 C++ Project 弹出页面,输入 Project name。选择“Empty Project”和“CygwinGCC”,其他选择按照默认选项,点击“Finish”按钮。
图 8. 选择编译器
使用 OpenCV 添加一个源文件:
- 右键点击已创建的 project,点击 New > Folder 。
图 9. 创建文件夹
- 在 Source File 弹框中为源文件命名,完成创建含有一个空的 .cpp 文件的项目。
图 10. 创建源文件
在 cpp 文件中写入简单的显示图片的代码,如下:
#include <opencv2/opencv.hpp>
using namespace cv;
int main( int argc, char** argv )
{
Mat image;
image = imread( argv[1], 1 );
if( argc != 2 || !image.data )
{
printf( "No image data \n" );
return -1;
}
namedWindow( "Display Image", WINDOW_AUTOSIZE );
imshow( "Display Image", image );
waitKey(0);
return 0;
}
最后在 C++ Linker 处添加库以及库搜索路径。右键 Displayimage 项目,选择“Property”,在 properties 弹出框中选择 C/C++ Build > Settings, 在 setting 界面选择 Cygwin C++ Linker > Libraries,在 Librariessearch path 中输入 OpenCV 的文件位置/lib 和/usr/lib。在 Libraries 中输入文件库,所需文件库如下图所示。
图 11. 添加 lib
接下来在 C/C++ Build > Tool Chain Editor > Current builder 中选择 CDT internal Builder,点击“Apply”按钮。
图 12. 配置编译器和 Linker
下一步配置项目。右键 Displayimage,选择 Run As > Run Configurations… ,在弹出的 Run Configurations panel 中展开 C/C++ Application > DisplayImage Debug,如下图所示。
图 13. 配置应用
选择 Arguments menu 输入图片途径和图片名称。在 Environment menu 增加 DISPLAY variable,如下图。
图 14. 配置应用参数
配置完成后运行 Project -> Build Project 对项目进行编译。
图 15. Build Info
点击 C:\cygwin64\bin\XWin.exe 运行 Cygwin 程序,再点击界面上部的 Run button,程序运行结果如下图所示。
图 16. 运行结果
利用 OpenCV 识别图片中图形的轮廓
下面用一个例子介绍 OpenCV 图片处理的几个功能。图片中一般会包含多个图形,如果我们用图片处理的方法获得图形的轮廓,那么对后期人工智能训练模型会比较有帮助。所以,我们介绍如何用 OpenCV 来识别图片中多个图形的轮廓,并画出图形的轮廓,以及包含这个轮廓的最小圆形。
请打开此 链接 查看源代码。
第一步,读入图片,调用 cvtColor 方法将彩色图片转成灰度图,再调用 blur 方法对图片做平滑处理,目的是减少噪音。平滑处理需要一个滤波器,缺省情况下使用的是线性滤波器,本例未设置滤波器类型,所以使用缺省滤波器。blur 方法的第三个参数 Size(3,3)是指滤波器的大小。平滑处理后,图片存放到目标图片 img_gray 中。
Mat img;
Mat img_gray;
img = imread( argv[1], IMREAD_COLOR );
cvtColor( img, img_gray, COLOR_BGR2GRAY );
blur( img_gray, img_gray, Size(3,3) );
第二步,threshold 方法是把灰度图变成黑白图。threshold 方法支持多种 threshold type,本例用到的 type 是 THRESH_BINARY。对于这种 type,大于阈值 thresh 的像素值设置为 255,小于阈值 thresh 的像素值设置为 0。目标图片存放到 img_gray 中。
threshold( img_gray, img_gray, thresh, 255, THRESH_BINARY );
第三步,获取图片中图形的轮廓。我们先定义两个向量,向量 contours 用来保存所有的轮廓,向量 hierarchy 用来保存多个轮廓之间的继承关系。方法 findContours 来找到图片中所有图形的轮廓,结果存放到 contours 向量。轮廓之间的关系放到 hierarchy 向量。第四个参数定义轮廓的检索模式,本例用 RETR_TREE 模式。RETR_TREE 模式检测所有的轮廓,并建立一个等级树状结构,外层轮廓包含内层轮廓,内层轮廓进而包含内嵌轮廓。第五个参数定义轮廓的近似方法。CV_CHAIN_APPROX_SIMPLE 只保存轮廓的拐点,轮廓拐点上的点存放到 contours 向量中。
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;
findContours( img_gray, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE );
第四步,得到图形轮廓后,我们开始绘制轮廓多边形,并画出包含轮廓的最小圆形。 approxPolyDP 方法根据图形轮廓 contours 上的点来获取包含该轮廓的多边形点集合,多边形点集合存放到 poly 向量中。第三个参数定义输出精度为 5。第四个参数表示输出是封闭图形。 接下来我们画出该多边形,方法 drawContours 将多边形 poly 绘制到目标图片 dst 上。 然后我们获取并绘制包含轮廓的最小圆形。首先调用方法 minEnclosingCircle 来获取包含多边形 poly 的最小圆形的圆心 circle_center 和半径 circle_radius。然后调用方法 circle 将圆形画到目标图片 dst 上。
vector<vector<Point> > poly( contours.size() );
vector<Point2f>circle_center( contours.size() );
vector<float>circle_radius( contours.size() );
Mat dst = Mat::zeros( img_gray.size(), CV_8UC3 );
if(!contours.empty())
{
RNG rng(time(0));
size_t i = 0;
for( ; i < contours.size(); i++ )
{
Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) );
approxPolyDP( Mat(contours[i]), poly[i], 5, true );
drawContours( dst, poly, (int)i, color, 1, 8, vector<Vec4i>(), 0, Point() );
minEnclosingCircle( poly[i], circle_center[i], circle_radius[i] );
circle( dst, circle_center[i], (int)circle_radius[i], color, 2, 8 );
}
}
第五步,保存图片到文件。经过第四步,图片 dst 上包含了图形轮廓信息以及包含图形轮廓的最小圆形。最后我们调用 imwrite 方法将图片保存到文件。
imwrite( "images/Output_Image.jpg", dst );
你可以查看 源代码 ,将源代码导入到 Eclipse,然后按照上文中 Eclipse 的配置方法配置 Eclipse 项目,然后构建并运行该项目。 运行结果如下:
图 17. 源图片
图 18. 运行结果
遇到的问题
问题 1. opencv 的 lib 没有正确引入
13:41:20 **** Incremental Build of configuration Debug for project DisplayImage ****
Info: Internal Builder is used for build
g++ -L/lib -o DisplayImage.exe "src\\DisplayImage.o"
/usr/lib/gcc/x86_64-pc-cygwin/10/../../../../x86_64-pc-cygwin/bin/ld: src\DisplayImage.o: in function `cv::String::String(char const*)':
/usr/include/opencv2/core/cvstd.hpp:602: undefined reference to `cv::String::allocate(unsigned long)'
/usr/include/opencv2/core/cvstd.hpp:602:(.text$_ZN2cv6StringC1EPKc[_ZN2cv6StringC1EPKc]+0x51): relocation truncated to fit: R_X86_64_PC32 against undefined symbol `cv::String::allocate(unsigned long)'
/usr/lib/gcc/x86_64-pc-cygwin/10/../../../../x86_64-pc-cygwin/bin/ld: src\DisplayImage.o: in function `cv::String::~String()':
/usr/include/opencv2/core/cvstd.hpp:648: undefined reference to `cv::String::deallocate()'
……
collect2: error: ld returned 1 exit status
当运行时遇到上面的错时,原因是 opencv 的 lib 没有正确引入。请参照下图进行 opencv 的 lib 配置。
图 19. 配置 lib
问题 2. 运行上面的程序不能看到图片的显示
首先请在 Eclipse Run Configurations -> Environment 添加配置 Display = :0.0,并在 CMD 运行 C:\cygwin64\bin\XWin.exe (C:\cygwin64 可替换成 cygwin 安装的目录)。此时再次运行上面的程序,图像将会在 cygwin:0.0 窗口里显示。
图 20. 配置 DISPLAY
问题 3. Windows Server2012 运行显示图片的程序报错
错误信息:
libGL error: Windows-DRI extension disabled for GDI Generic renderer
系统兼容问题,此时可以在命令行窗口或者使用 Windows 10 正常运行程序。
问题 4. make: * multiple target patterns 错误
编译后一切正常,但是运行的时候会报错:
Description Resource Path Location Type
make: *** multiple target patterns. Stop.
配置 cygwin 的时候,在 Window>preferences>C/C++>Debug>Source Lookup Path 都要新建一个 path mapping,即将/cygdrive/c/映射成 C:\。 但 ADT Bundle 提供的 Eclipse 里,点确定后/cygdrive/c/自动变成\cygdrive\c\而使映射无效。解决方式为选中项目点 Alt+Enter,在 C/C++ Build>Tool Chain Editor>Current Builder 选择 CDT Internal Builder 代替 Gnu Make Builder。
图 21. 配置 Current builder
问题 5. Windows 环境中 Can’t open display 错误
即便正确设置了 DISPLAY 为 :0.0,运行程序仍然得到 can’t open display 的错误信息,这是因为 Unix GUI 程序是通过 Xsever 来显示的,而 Cygwin 不会自动启动 Xserver,安装 xorg-server 和 xinit 程序包再执行 startxwin 即可解决。
小结
本文介绍了 OpenCV,以及 Windows 上 OpenCV 开发环境的搭建步骤和相关问题。相信通过上面的步骤,你可以搭建属于你自己的开发环境。另外本文介绍了 OpenCV 获取图片中图形轮廓的一个例子。你也可以用 OpenCV 来开发图片,视频,AI 的其他应用,开启你的 OpenCV 之旅。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论