计算机视觉是一门研究如何使机器“看”的科学,更进一步的说,就是是指用摄像头和计算机代替人眼对目标进行识别、跟踪和测量等,并进一步做图像处理,使计算机处理成为更适合人眼观察或传送给仪器检测的图像。作为一个科学学科,计算机视觉研究相关的理论和技术,试图建立能够从图像或者多维数据中获取“信息”的人工智能系统。

图像和视频再当今的数字世界可谓无处不在,随着运算能力强劲而又实惠的计算设备的问世,创建复杂的图像应用从未像今天这般容易。市面上有众多的软件和库用于操作图像和视频,但是对于期望自己开发软件的人而言,OpenCV库是一款必备的工具。OpenCV(Open Source Computer Vision)是一个开放源代码的图像及视频分析库,它包含500多个优化过的算法。自1999年问世以来,它已经被计算机视觉领域的学者和开发人员视为首选工具。下面就一起进入计算机视觉的大门!

文章目录

  • 一、接触图像
  • 二、操作像素
  • 三、基于类的图像处理
  • 四、使用直方图统计像素
  • 五、基于形态学运算的图像变换
  • 六、图像滤波
  • 七、检测并匹配特征点

一、接触图像

本章将带领你完成最基本的操作:读取、显示及保存图像。在着手开发前需要先安装库和一个顺手的IDE,这里推荐VS或者Qt。计算机视觉不依赖于特定的环境或操作系统。

  • opencv_core模块:包含核心功能,尤其是底层数据结构和算法函数。
  • opencv_imgproc模块:包含图像处理函数。
  • opencv_highgui模块:包含读写图像及视频的函数,以及操作图形用户界面函数。
  • opencv_features2d模块:包含兴趣点检测子、描述子以及兴趣点匹配框架。

下面开始读取我们准备的图像,然后设置窗口,接着在窗口中显示图像,不停等待用户键入退出:

cv::Mat image = cv::imread("/home/dzh/QtOpenCV/image.png", 1);
cv::namedWindow("Image");
cv::imshow("Image", image);
cv::waitKey(0);

下面我是在写的一个图像查看类,主要功能是读取文件夹中所有图像并依次显示出来。

二、操作像素

为了编写计算机视觉应用,你必须会存取图像的内容,如修改和创建图像。本章会教会你如何操作图像的基本像素,即所谓的像素。你将学会如何遍历一张图像并且处理其像素。opencv采用cv::Mat这个数据结构来表示图像是因为矩阵的每个元素代表一个像素。对于灰度图像而言,像素由8位无符号数来表示,其中0代表黑色,255代表白色;对于彩色图像则需要3个颜色通道的24位无符号数表示。

我们可以使用指针遍历图像,遍历图像的领域操作,进行简单的图像运算,定义感兴趣区域。

// 颜色缩减[指针遍历]
void MainWindow::colorReduce(cv::Mat &image, cv::Mat &result, int div) {// 行数int nl = image.rows;// 每行的元素个数(像素个数 x 通道数)int nc = image.cols * image.channels();// 左移位数int n = 0;// 遍历每一行for (int j = 0; j < nl; j++) {// 得到第j行的首地址uchar* data = image.ptr<uchar>(j);// 求解pow的反函数for (int k = 1; k <= 8; k++) {if (pow(2, k) == div) {n = k;break;} else if (pow(2, k) > div) {n = k - 1;break;}}// 掩码左移uchar mask = 0xFF << n;for (int i = 0; i < nc; i++) {//            data[i] = data[i] / div * div + div / 2;data[i] = (data[i] & mask) + div / 2;}}
}// 图像运算
void MainWindow::imageProc(cv::Mat &image1, cv::Mat &image2, cv::Mat &result) {result = image1 * 0.8 + image2 * 0.2;
}// 感兴趣区域
void MainWindow::imageROI(cv::Mat &image1, cv::Mat &image2) {// 相当于截取图像的一个区域cv::Mat roi = image1(cv::Rect(280, 260, image2.cols, image2.rows));cv::addWeighted(roi, 0.2, image2, 0.8, 0.1, roi);}

三、基于类的图像处理

计算机视觉程序的质量与良好的编程习惯紧密相关。创建不含BUG的应用仅仅是开始,我们希望应用能够轻松应付新的需求。设计模式是软件工程中众所周知的概念。一个设计模式是一个可靠的、可重用的方案,用于解决软件设计中频繁出现的问题。首先是策略模式,使用控制器实现模块间通信,使用单件设计模式,使用MVC架构设计应用程序。

void Histogram1D::process() {cv::Mat image = cv::imread("/home/dzh/QtOpenCV/image.png");if (!image.data) {cout << "图像不存在" << endl;return;} else {cout << "图像的宽度:" << image.cols << "图像的高度:" << image.rows << "像素总数:" << image.cols * image.rows << endl;}Histogram1D hc;cv::Mat imageROI; // 获取感兴趣区域imageROI = image(cv::Rect(160, 300, 100, 120));int minSat = 65;  // 彩色直方图cv::MatND colorhist = hc.getHueHistogram(imageROI, minSat);ContentFinder finder;finder.setHistogram(colorhist);cv::Mat detect = cv::imread("/home/dzh/QtOpenCV/image.png");cv::imshow("Detect", detect);cv::Mat hsv;cv::cvtColor(image, hsv, CV_BGR2HSV);vector<cv::Mat> v;cv::split(hsv, v);cv::Mat result;cv::threshold(v[1], v[1], minSat, 255, cv::THRESH_BINARY);result = finder.find(hsv, 0.0f, 180.0f, channels, 1);cv::bitwise_and(result, v[1], result);cv::Rect rect(110, 260, 35, 40);cv::rectangle(image, rect, cv::Scalar(255, 255, 255));cv::TermCriteria criteria(cv::TermCriteria::MAX_ITER, 10, 0.01);cv::meanShift(result, rect, criteria);
//    cv::imshow("origin", colorhist);cv::imshow("output", result);cv::waitKey(0);
}

颜色空间转换效果图:

四、使用直方图统计像素

一个图像是由不同颜色值的像素组成的。像素值在图像中的分布情况是这幅图像的一个重要特征。可以计算并使用直方图来修改图像的外观。对于灰度图像,直方图相当于长度为256的数组,每个数组元素代表灰度值为当前下标的像素个数。

cv::Mat Histogram3D::getHistogramImage(cv::Mat &image) {// 先求取直方图(256x256x256)cv::MatND hist = getHistogram(image);// 设置最大值和最小值double maxVal = INT_MIN;double minVal = INT_MAX;// 创建显示图像256x256x3cv::Mat histImg(histSize[0], histSize[0], CV_8UC3, cv::Scalar(255, 255, 255));int hpt = static_cast<int>(0.9 * histSize[0]);// 3D->2D,可以减少一个维度vector<vector<float>> vec(3, vector<float>(256));// b通道for (int i = 0; i < 256; i++) {// g通道for (int j = 0; j < 256; j++) {// r通道for (int k = 0; k < 256; k++) {vec[0][i] += hist.at<float>(i, j, k);vec[1][j] += hist.at<float>(i, j, k);vec[2][k] += hist.at<float>(i, j, k);}}}// 先遍历每一行for (int i = 0; i < vec.size(); i++) {// 对于每一行直方图取最大值和最小值cv::minMaxLoc(vec[i], &minVal, &maxVal, 0, 0);cout << "maxVal:" << maxVal <<",minVal:" << minVal << endl;// 再遍历每一列for (int j = 0; j < vec[i].size(); j++) {float val = vec[i][j];int intensity = static_cast<int>(val * hpt / maxVal);cv::Scalar color;color[i] = 255;cv::line(histImg, cv::Point(j, histSize[i]), cv::Point(j, histSize[i] - intensity), color);}}return histImg;
}

即使是最常用的640x480的图像,也有30万个像素,可想平时看视频时候的1080P和4K,那每秒都是30帧以上,每帧都几百万像素。

五、基于形态学运算的图像变换

形态学滤波理论于上世纪90年代提出,被用于分析及处理离散图形。它定义了一系列运算,应用预定义的形状元素来变换一张图像。形状元素与像素相邻点相交的方式确定了运算结果。腐蚀和膨胀就是最基本的形态学运算。由于形态学滤波通常使用于二值图像,使用白色像素表示前景物体,使用黑色像素表示背景。开闭运算都是最基本的,这里我们演示下使用形态学滤波对图像进行边缘及角点检测。

cv::Mat MorphoFeatures::getEdges(cv::Mat &image) {// 得到梯度图cv::Mat result;cv::morphologyEx(image, result, cv::MORPH_GRADIENT, cv::Mat());// 阈值化得到二值图像applyThreshold(result);return result;
}void MorphoFeatures::setThreshold(int value) {threshold = value;
}cv::Mat MorphoFeatures::getCorners(cv::Mat &image) {cv::Mat result;cv::dilate(image, result, cross);cv::erode(result, result, diamond);cv::Mat result2;cv::dilate(image, result2, x);cv::erode(result2, result, square);cv::absdiff(result2, result, result);applyThreshold(result);return result;
}

使用自带函数可以轻松检测直线,角点需要定义4种结构元素:方形、菱形、十字形和X形。

可以使用分水岭算法对图像进行分割,还可以使用GrabCut算法提取前景物体。

六、图像滤波

滤波(Filtering)是信号处理及图像处理中的一个基本操作,旨在特定的应用程序中,选择性地提取图像中被认为传达重要信息的部分。滤波去除图像中的噪声,提取感兴趣的视觉特征,允许图像重采样。矩阵位于中心的元素对应的是滤波器当前正在处理的像素。这样的矩阵称为核(Kernel)或者掩码(Mask)。最常用的有:均值滤波、中值滤波、Sobel滤波和图像的拉普拉斯变换。

cv::Mat contoursInv;
cv::threshold(contours, contoursInv, 128, 255, cv::THRESH_BINARY_INV);
cv::imshow("Inv", contoursInv);
cv::Mat result1, result2;
cv::Sobel(image, result1, CV_8U, 1, 0, 3, 0.4, 128);
cv::Sobel(image, result2, CV_8U, 0, 1, 3, 0.4, 128);
cv::imshow("result1", result1);
cv::imshow("result2", result2);
cv::Mat sobelX, sobelY;
cv::Sobel(image, sobelX, CV_8U, 1, 0);
cv::Sobel(image, sobelY, CV_8U, 0, 1);
cv::Mat sobel;
sobel = sobelX + sobelY;
cv::imshow("Sobel", sobel);

下面从左上是原图,然后依次是均值滤波、中值滤波和sobel滤波后的结果,均值滤波一般都都会模糊图像,中值滤波去除噪声点非常有效,sobel算子广泛用于边缘或轮廓的检测。

七、检测并匹配特征点

在计算机视觉中兴趣点(也叫做关键点或特征点)的概念被大量用于解决物体识别、图像匹配、视觉跟踪和三维重建等问题。cv::cornerHarris检测Harris角点,当然Fast角点检测要更加快速。这里介绍下尺度不变的概念,它是指每个检测到的特征点都伴随着对应的尺寸因子,其中非常受欢迎的特征点:SURF特征点,它也是SIFT算法的高效变种。

在特征匹配中,特征描述子通常是N维向量,在光照以及少许透视变换的情况下很理想。检测特征点可以概述为:提取关键点,计算描述子。

// 计算Harris角点
void HarrisDetector::detect(cv::Mat &image) {cv::cornerHarris(image, cornerStrength, neighbourhood, aperture, k);double minStrength;cv::minMaxLoc(cornerStrength, &minStrength, &maxStregth);cv::Mat dilated;cv::dilate(cornerStrength, dilated, cv::Mat());cv::compare(cornerStrength, dilated, localMax, cv::CMP_EQ);
}// 由Harris值获取角点图
cv::Mat HarrisDetector::getCornerMap(double qualityLevel) {cv::Mat cornerMap;threshold = qualityLevel * maxStregth;cv::threshold(cornerStrength, cornerTh, threshold, 255, cv::THRESH_BINARY);cornerTh.convertTo(cornerMap, CV_8U);cv::bitwise_and(cornerMap, localMax, cornerMap);return cornerMap;
}

当然以上特征点检测库函数并不在OpenCV中,由于专利原因被全部安排到扩展库中了。安装方法可以参考我的教程:ubuntu安装opencv_contrib扩展库,附踩坑+测试

当然计算机视觉是一个非常庞大的学科,本文限于篇幅只能讲解一二,感兴趣的同学可以再去读相关的书籍。现在CV主要任务是目标识别、目标检测和目标跟踪,网络结构也从传统的CNN变为了Transformer,人工智能的快速发展离不开CV,也离不开大家开源的贡献!

猿创征文|OpenCV编程——计算机视觉的登堂入室相关推荐

  1. 猿创征文 | Shell编程【上篇】

    目录 1,Shell编程 1.1:简介 1.1.1:shell解释器 1.2:快速入门 1.2.1:编写脚本 1.2.2:执行shell脚本 1.3:shell变量 1.3.1:简介 1.3.2:使用 ...

  2. 猿创征文|OpenCV 如何提高条形码识别率

    猿创征文|OpenCV 如何提高条形码识别率 今天介绍一个使用OpenCV提高条形码识别率的算法 平台及OpenCV库简介 强烈建议:先学习一下OpenCV的课程 步入正题:从图片读取到条码截取部分( ...

  3. 猿创征文|前路有光,初心莫忘,从编程小白,到如今小有所成,我这一路是如何走来的?

    前言 无论是谁,对于编程来说,一开始看都很难看懂的,这也是为什么这个行业,属于互联网高薪行业代表的原因之一. 我是属于自学编程的非科班码农,在我看来,自学编程应该重点思考下自己的学习方式以及是否对 J ...

  4. 猿创征文|收到谷歌开发者大会正式邀请(Java学生的自学之路)

    文章目录 一.前言 二.收到谷歌邮件 三.感想 四.学习之路 1. 坚持看网课并整理笔记 2.勤加练习 3.坚持总结 4.刷题技巧 5.心态调整 五.结语 一.前言 上一次通过了CSDN内部筛选后,在 ...

  5. 猿创征文|当我在追光 我与光同航--我与Java的技术成长之路

    文章目录 前言 材料转码 初识JAVA 大学建议 1. 参加比赛 2. 坚持创作 3.养成看书的习惯 Java路线 1. java基础 2. 数据库 3. javaWeb 4. 框架 前言 今天借着官 ...

  6. 猿创征文|六年一日,我的焚膏继晷之路

    猿创征文|我在Python领域的焚膏继晷之路 一.自我介绍 二.我和师父的机缘 三.拜师 or 闹剧? 四.我在CSDN的收获 五.关于我的学习 六.我的憧憬 一.自我介绍 大家好,我是 热爱科技的刘 ...

  7. 猿创征文|【深度学习前沿应用】文本生成

    猿创征文|[深度学习前沿应用]文本生成 作者简介:在校大学生一枚,C/C++领域新星创作者,华为云享专家,阿里云专家博主,腾云先锋(TDP)成员,云曦智划项目总负责人,全国高等学校计算机教学与产业实践 ...

  8. 猿创征文|工作中遇到技术盲区后的自我成长

    猿创征文|工作中遇到技术盲区后的自我成长 1.立场 我是一名python后端开发程序员,在一家创业公司中兢兢业业工作快两年了,从软件架构.开发.测试.部署.运维一手经办,到开发文档.API接口.开发周 ...

  9. 猿创征文|我的Go成长之路道阻且长

    猿创征文|我的Go成长之路道阻且长 自从2016年09月04日加入CSDN,已经整整六年了,回顾自己不太长的技术成长之路(毕竟还是00后),前前后后捣鼓过网络安全.人工智能.区块链.舆情分析.可以说是 ...

最新文章

  1. python代码画皮卡丘_Python气象绘图实例我们一起画台风(代码+数据)
  2. 聚合复合_【专家视觉】聚合物接枝多壁碳纳米管及其聚氨酯复合材料
  3. PowerDesigner连接SqlServer数据库
  4. 833系列——二叉排序树
  5. 服务器创建多个dhcp服务_如何在15分钟内创建无服务器服务
  6. 非线性回归的数学理论与方法(非线性最小二乘法)
  7. JVM虚拟机-Class文件之字段表集合
  8. broadcast receiver 接收设备重启意图( boot_completed Broadcast Intent)而重启定时器
  9. maven启动web服务报错原因
  10. Android 经常使用设计模式(一)
  11. 【好看图标不用愁】吾爱万能软件ICO图标提取器
  12. 泛型与STL Note
  13. 如何搭建OpenOCD环境基于Window10+Cygwin?
  14. 分享一下自己存的网站
  15. 文件路径名太长导致IAR编译报错:Fatal Error[Pe1696]: cannot open source file
  16. c语言(cn)括号的作用,c语言小括号的用法
  17. java根据word模板导出_java如何根据word模板生成word文档
  18. Linux - 操作系统
  19. JEECG容器化部署:Alpine镜像方式
  20. 计算机系统读书笔记三

热门文章

  1. 杰理之修改提高摄像头源视频输出帧率,确定摄像头源输出高帧率【篇】
  2. 《风之旅人》游戏设计思想一
  3. 【RSkype Recorder】 5.5_最简洁好用的免费Skype录音软件
  4. php sin 函数,PHP sin()函数
  5. postgresql逻辑备份工具pg_dump和pg_resotre学习
  6. fprom预测结果内容_启动子的分析和预测
  7. 什么是 Ribbon?什么是负载均衡?怎么用Ribbon
  8. pyc文件究竟是用来干什么的?
  9. 大虎2021软件校招笔试题
  10. 高等数学 函数极限求法(二) 画图法