实验环境
本实验均在笔记本电脑完成,电脑的配置如表1所示:
系统 |
Windows 10 家庭版 |
处理器 |
英特尔 Core i5-6200 @ 2.30GHz 双核 |
主板 |
宏碁 Zoro_SL |
内存 |
16G(金士顿 DDR3 1600MHz) |
主硬盘 |
西数 WDC WD10JPVX-22JC3T0 |
显卡 |
NVIDIA GeForce 940M(4G) |
显示器 |
奇美 CMN15C4(15.5英寸) |
表1:电脑配置
本实验使用Opencv对图像处理,使用MFC对图像显示,具体介绍如表2所示:
Visual Studio 2019 |
MFC |
Opencv3.3.0 |
表2:环境介绍
主要原理
由于OpenCV常用的界面只是单纯的打开图像窗口,相关界面控件和工具较少且不美观,故使用MFC制作界面,而用OpenCV单纯做图像处理。此时便需要在MFC中显示OpenCV所用的图片,现有以下三种方法可以实现:参考(链接)
(1)、嵌套。直接将OpenCV窗口嵌套到MFC的Pictrue Control控件中。此方法既能直接显示图片,也可直接使用OpenCV的鼠标按键事件,但对于鼠标滚轮事件只能使用MFC本地的滚轮函数。
(2)、转换。将OpenCV读取或处理的图片转换格式,使之成为MFC的Pictrue Control控件可显示的图片格式。
(3)、保存。将OpenCV读取或处理的图片保存为本地图片,然后用MFC读取图片的方法读取并显示。此方法是笨方法,在特定情况下使用,保存和读取图片比较耗时,但无需转换格式,同样只能使用MFC的鼠标事件。
本实验中使用的是“转换”方式将Opencv处理后的图像显示到MFC的控件上,具体代码如下:
//显示到第一个Pic控件 void CMFC_DEMODlg::ShowPic_1(Mat input_1) { Mat imagedst; // Mat是在矩阵中存储图片的数据结构 CRect rect; //定义矩阵类,记录一个矩形信息(四个坐标点等) /* GetDlgItem(IDC_STATIC):获取控件IDC_STATIC句柄 GetClientRect(&rect):获取句柄指向控件区域的大小 */ GetDlgItem(IDC_STATIC)->GetClientRect(&rect); //获取图像大小(长、宽、高等) Rect dst(rect.left, rect.top, rect.right, rect.bottom); //调整图像大小,含有格式转换 resize(input_1, imagedst, cv::Size(rect.Width(), rect.Height())); imshow("view", imagedst); }
配置MFC
在VS中添加MFC的组件即可,如图1所示:
图1:MFC配置
Opencv介绍
人类获取的所有信息中,视觉信息占绝大多数。在大数据时代,图像、视频等视觉信息载体也是最主要的数据来源之一,在铁路工程、公路、机场、医学、生物学、军事等领域有着广泛的应用。由于计算机视觉涉及多个领域的专业知识,以及视觉任务的多样性和视觉对象的复杂性,这使得计算机是视觉研究具有一定的困难性。
Opencv是跨平台、跨语言、开源、支持模块多、功能强大、性能高、稳定的机器学习库和计算机视觉库,其全称为Open Source Computer Vision Library。OpenCV是由Intel公司组织开发的,自1999年问世以来,逐渐成为计算机视觉研究领域人员的标准库工具。
Opencv中包含了大量的模块,highgui、imgproc和core是最基础的三个模块,介绍了图像处理基础方法的原理,也是研究Opencv的开始。Highgui模块包含用于在Opencv中输入、存储、输出图像的UI接口;core模块包含了Opencv一些基本运算函数和最核心的数据结构;imgproc模块包含了Opencv中图像处理的基本方法,包括图像的平滑、对比度增强、形态学处理、阈值分割、边缘检测几何图像的检测和拟合、傅里叶变换、频率域滤波等。Opencv中也包含了更高层次层次饿的图像处理方法的相关模块,包括用于机器学习的ml模块,如神经网络、随机森林、支持向量机等;实现对目标检测功能的objdetect模块,如基于HOG的汽车、行人的检测,基于LBP、Haar特征的人脸等目标的检测;针对视频处理的video模块,如运行物体的跟踪、背景建模、前景检测等。由此可见,在计算机视觉研究领域的所有方向,Opencv几乎都可以实现。Opencv提供的标准统一的函数和数据结构的混合能够更好地检测、分割是识别出物体的特征,这些优势都为图像处理研究奠定了良好的基础。
Opencv在VS中配置
首先,先下载Opencv,进行安装;然后配置电脑系统变量;最后设置项目属性,主要分为Debug和Release两种调试方法,分别设置项目的通用属性:VC++目录—包含目录和库目录和链接器:输入-添加依赖项,具体如图2、图3所示:
图2:VC++配置
图3:链接器配置
功能介绍
效果分为主页面,即一个窗口,可以显示图像和处理后的图像,最上面有三个菜单里面有实现主要的功能,具体的如图4、图5、图6、图7所示:
图4:主界面
图5:文件操作
图6:图像处理
图7:实时图像处理
灰度化和二值化
(1)灰度化
图像灰度化核心思想是 R = G = B ,这个值也叫灰度值
主要代码如下,运行结果如图8所示:
//转换成灰度图像 Mat CMFC_DEMODlg::ImageGray1() { Mat huidu, out2; cvtColor(image, huidu, COLOR_BGR2GRAY); return huidu; }
图8:灰度化
(2)二值化
从灰度图像中获取二进制图像,滤除大小或太大的像素值,k为阈值
主要代码如下,运行结果如图9所示:
//二值化函数 void CMFC_DEMODlg::ImageEZH1() { Mat huidu; newform2 Dl; if (Dl.DoModal() == IDOK) { int k = Dl.canshu; cvtColor(image, huidu, COLOR_BGR2GRAY); threshold(huidu, out, k, 255, CV_THRESH_BINARY); ShowPic_2(out); } }
图9:二值化
灰度变换
灰度变换是图像增强的一种重要手段,用于改善图像显示效果,属于空间域处理方法,它可以使图像动态范围加大,使图像对比度扩展,图像更加清晰,特征更加明显。灰度变换其实质就是按一定的规则修改图像每一个像素的灰度,从而改变图像的灰度范围。常见的灰度变换图像反转,对数变换和伽马变换等。其具体分类如下图10所示:
图10:灰度变换分类
(1)均值滤波
均值滤波是对是对信号进行局部平均, 以平均值来代表该像素点的灰度值
主要代码如下:
//均值滤波 void CMFC_DEMODlg::ImageJZ1() { newform6 D; if (D.DoModal() == IDOK) { int k = D.n; //Mat junzhi,out2; out.create(image.size(), image.type()); blur(image, out, Size(k, k)); ShowPic_2(out); } }
(2)高斯滤波
由于高斯函数的傅立叶变换仍是高斯函数, 因此高斯函数能构成一个在频域具有平滑性能的低通滤波器。可以通过在频域做乘积来实现高斯滤波
主要代码如下:
//高斯滤波 void CMFC_DEMODlg::ImageGS1() { newform6 D; if (D.DoModal() == IDOK) { int k = D.n; GaussianBlur(image, out, Size(k,k), 0, 0); ShowPic_2(out); } }
(3)拉普拉斯滤波
由于拉普拉斯是一种微分算子,它的应用可增强图像中灰度突变的区域,减弱灰度的缓慢变化区域。
主要代码如下:
//拉普拉斯 Mat CMFC_DEMODlg::ImageLPLS1() { Mat lpls; Mat K = (Mat_<double>(3, 3) << -1, -1, -1, -1, 9, -1, -1, -1, -1); filter2D(image, lpls, image.depth(), K); return lpls; }
边缘检测
梯度:像素灰度值变化的速度
canny边缘检测:目的是寻找一个最优的边缘,运行图像如图11所示:
最优的边缘定义为:
1.好的检测--算法能够尽可能的标识出图像中的实际边缘
2.好的定位--标识出的边缘要与实际图像中的实际边缘尽可能接近
3.最小响应--图像中的边缘只能标识一次,并和可能存在存在的图像噪声不应该标识为边缘
步骤:
1、高斯滤波:去燥(根据待滤波的像素点极其邻域点的灰度值按照高斯公式生成参数规则进行加权平均,这样可以有效去除理想图像中叠加的高频噪声)
2、计算梯度图像与角度图像
slobel算子:
根据像素点上下,左右邻点灰度加权差,再边缘处达到极值这一现象检测边缘,对噪声具有平滑作用,但是边缘定位精度不够高,当对精度要求不是很高时,是一种常用的边缘检测算法
图11:canny边缘检测
直方图
图像的直方图:指具有某种灰度级的像素的个数,反应图像中每种灰度出现的频率
直方图均衡化:是间接增减对比度的方法之一,主要把给定图像的直方图分布改变为“均匀”分布。原理是:对个数多的灰度级进行展宽,对个数少的灰度级进行缩减,把原始图像的灰度直方图从比较集中的某灰度区间在全部灰度范围内的均匀分布,从而达到清晰图像目的
主要流程如图12所示,显示如图13所示:
图12:直方图流程图
图13:直方图显示
混沌加密
混沌:混沌是一种复杂的动力学行为,不是简单的无序,它没有明显的周期和对称,其内部结构丰富是非线性系统的一种新形式。
Li- Yorke定义:
对于闭区间J,R,设连续映射J—J,如果存在不可数集S J,满足:
1、S不含周期点
2、对任意的两个点p,q∈S(p≠q)
3、对任意p∈S及周期点q∈J,且p≠q
称F映射在S上是混沌的
超混沌:一般混沌系统是一种典型的三维现象,其特点是只有一个正的李雅普诺夫指数,其运动轨迹只在某个方向上产生不稳定性。在自然界中普遍存在高维非线性系统,它们有不止一个正的李雅普诺夫指数,其运动轨迹在两个以上的方向出现指数型的发散轨迹,这种混沌态被称为超混沌
超混沌加密:对称加密,处理速度和密钥长度无关,运行显示如图14所示:
图14:混沌加密
打开摄像头
使用OPENCV打开摄像头,并显示到指定控件中:
主要代码如下,运行结果如图15所示:
// 实时视频处理 static void refineSegments(const Mat& img, Mat& mask, Mat& dst); void CMFC_DEMODlg::VIDEO_deal_fun() { bool update_bg_model = true; Mat tmp_frame, bgmask, out_frame, foreground, bw, gray;; cap.open(0); if (!cap.isOpened()) { AfxMessageBox("打开摄像头失败!"); exit(-1); } cap >> tmp_frame; if (tmp_frame.empty()) { AfxMessageBox("读取帧失败!"); exit(-1); } Ptr<BackgroundSubtractorMOG2> bgsubtractor = createBackgroundSubtractorMOG2(); bgsubtractor->setVarThreshold(10); for (;;) { cap >> tmp_frame; if (tmp_frame.empty()) break; bgsubtractor->apply(tmp_frame, bgmask, update_bg_model ? -1 : 0); ShowPic_1(tmp_frame); } }
图15:打开摄像头
视频灰度化和模糊化和边缘检测
(1)灰度化
主要代码如下:
//灰度化 cvtColor(tmp_frame, out_frame, CV_BGR2GRAY); ShowPic_2(out_frame);
(2)模糊化
主要代码如下:
//模糊化 blur(tmp_frame, out_frame, Size(7, 7));//模糊化 ShowPic_2(out_frame);
(3)边缘检测
主要代码如下:
//边缘检测 GaussianBlur(tmp_frame, out_frame, cvSize(3,3), 2, 2, BORDER_DEFAULT);//高斯平滑 Canny(tmp_frame, out_frame,20,100,3); ShowPic_2(out_frame);
清除背景分割
主要代码如下,运行结果如图16所示:
来源:链接
static void refineSegments(const Mat& img, Mat& mask, Mat& dst) { int niters = 3; vector<vector<Point> > contours; vector<Vec4i> hierarchy; Mat temp; dilate(mask, temp, Mat(), Point(-1, -1), niters); // 膨胀:求核区域像素最大值,可以填补凹洞 erode(temp, temp, Mat(), Point(-1, -1), niters * 2); // 腐蚀:求核区域最小值,能消除凸起 dilate(temp, temp, Mat(), Point(-1, -1), niters); // 膨胀:求核区域像素最大值,可以填补凹洞 findContours(temp, contours, hierarchy, RETR_CCOMP, CHAIN_APPROX_SIMPLE); // 轮廓提取 dst = Mat::zeros(img.size(), CV_8UC3); if (contours.size() == 0) return; int idx = 0, largestComp = 0; double maxArea = 0; for (; idx >= 0; idx = hierarchy[idx][0]) { const vector<Point>& c = contours[idx]; double area = fabs(contourArea(Mat(c))); // 求绝对值 if (area > maxArea) { maxArea = area; largestComp = idx; } } Scalar color(0, 0, 255); //将图像设置成单一灰度和颜色 drawContours(dst, contours, largestComp, color, FILLED, LINE_8, hierarchy); // 轮廓填充 }
图16:清除背景分割
存在的问题
1、主窗口关闭不掉,内部有退出按钮,但只能强行关闭窗口,需要手动杀死进程
2、对于实时图像处理的功能,只用了简单地 if-else 进行切换,不存在实用价值,且演示顺序只能为:灰度化、模糊化、边缘检测、清除背景分割。
3、opencv调用摄像头是存在诸多问题,以及始终实现不了加载视频,我太菜!