OpenCV C++案例实战二十三《网孔检测》
OpenCV C++案例实战二十三《网孔检测》
- 前言
- 一、HSV通道转换
- 二、图像修复
- 2.1 OpenCV函数实现
- 2.2 MyFunction
- 三、轮廓提取
- 四、效果显示
- 五、源码
- 总结
前言
前段时间,有位粉丝私信我,给我发了一张图片,如下图所示:
在这里贴出他的原话。
从他给的图片分析,该图存在遮挡,所以不能简单的二值化,然后提取图像轮廓去寻找结果。所以,我就想如何去掉这些遮挡物(即图像修复)。从图像可知,该遮挡物是黄色的线,所以,我就想可否使用hsv色彩空间提取出黄色,然后得到二值掩模图像,最后对原图进行修复。接下来,就一起看看是如何一步步实现的吧。
一、HSV通道转换
通过hsv通道转换,可以提取出图像中的黄色分量。
//hsv颜色通道转换,提取图像中黄色线部分,生成掩膜图像Mat hsv;cvtColor(src, hsv, COLOR_BGR2HSV);Mat mask;inRange(hsv, Scalar(10, 50, 255), Scalar(40, 255, 255), mask);
结果如图所示:
二、图像修复
关于图像修复的相关知识可以参考我之前的博文。这里就不细说了。
OpenCV C++案例实战十四《图像修复》
OpenCV C++案例实战十七《图像去水印》
我们拿到上面的mask掩模图像,需要对其进行膨胀处理,使修复区域范围扩大。
//将生成的掩膜mask膨胀一下,使掩膜区域放大Mat kernel = getStructuringElement(MORPH_RECT, Size(9, 9));dilate(mask, mask, kernel);
接下来,需要对图像进行修复。这里我提供两种修复方法,一种是OpenCV提供的inpaint函数,一种是我自己写的。
2.1 OpenCV函数实现
//使用OpenCV自带的inpaint函数进行图像修复,得到目标图像Mat inpaintImg;inpaint(src, mask, inpaintImg, 1, INPAINT_NS);
效果如图所示。
2.2 MyFunction
通过修改图像像素达到图像修复的效果。具体请看源码注释。
//自己写的算法,修改图像像素,完成图像修复Mat canvas = Mat::zeros(src.size(), src.type());int r = 1;//像素查找范围--表示在该像素点上下几行像素进行查找for (int i = r; i < src.rows- r; i++){for (int j = 0; j < src.cols; j++){ if (mask.at<uchar>(i, j) != 255){ //对于非掩膜区域,直接将原像素进行像素赋值for (int c = 0; c < 3; c++){canvas.at<Vec3b>(i, j)[c] = src.at<Vec3b>(i, j)[c];} }else{//找到距离该掩膜像素点最近的非掩膜区域像素进行赋值Point res = find_Nearest_Point(mask, i, j, r);for (int c = 0; c < 3; c++){canvas.at<Vec3b>(i, j)[c] = src.at<Vec3b>(res.x, res.y)[c];}}}}
效果如何所示
三、轮廓提取
接下来我们只需要对修复之后的图像进行轮廓提取就可以了。
//将修复之后的目标图像进行图像预处理,提取轮廓Mat gray;cvtColor(canvas, gray, COLOR_BGR2GRAY);Mat gaussian;GaussianBlur(gray, gaussian, Size(3, 3), 0);Mat thresh;threshold(gaussian, thresh, 30, 255, THRESH_BINARY_INV);Mat kernel1 = getStructuringElement(MORPH_RECT, Size(3, 3));morphologyEx(thresh, thresh, MORPH_OPEN, kernel);//namedWindow("thresh", WINDOW_NORMAL);//imshow("thresh", thresh);//轮廓提取vector<vector<Point>>contours;findContours(thresh, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);//经过面积,外接矩形特征筛选出目标区域vector<vector<Point>>EffectiveConts;for (int i = 0; i < contours.size(); i++){double area = contourArea(contours[i]);if (area>100){Rect rect = boundingRect(contours[i]);if (double(rect.height) > 30 && double(rect.width) > 30){EffectiveConts.push_back(contours[i]);}}}
四、效果显示
for (int i = 0; i < EffectiveConts.size(); i++){//计算轮廓矩Moments Mo = moments(EffectiveConts[i]);//计算质心--即插孔坐标Point center = Point(Mo.m10 / Mo.m00, Mo.m01 / Mo.m00);//效果绘制Rect rect = boundingRect(EffectiveConts[i]);rectangle(src, rect, Scalar(0, 255, 0), 5);circle(src, center, 3, Scalar(0, 0, 255), -1);}
如图为该案例最终效果。
五、源码
#include<opencv2/opencv.hpp>
#include <iostream>
#include<opencv2/photo.hpp>
using namespace std;
using namespace cv;double EuDis(Point pt1, Point pt2)
{return sqrt(pow(pt1.x - pt2.x, 2) + pow(pt1.y - pt2.y, 2));
}Point find_Nearest_Point(Mat mask , int currentrow, int currentcol, int r)
{ double mindis = 100000.0;Point res(0,0);//查找该像素点上下r行像素,找到最接近该像素的非掩膜区域像素for (int i = currentrow - r; i < currentrow + r; i++){for (int j = 0; j < mask.cols; j++){if (mask.at<uchar>(i, j) != 255){//Point(currentrow, currentcol) 表示当前需要赋值的掩膜像素点double dis = EuDis(Point(currentrow, currentcol), Point(i, j));if (dis < mindis){mindis = dis;res = Point(i, j); //目标像素点}}}}return res;
}int main()
{Mat src = imread("test.jpg");if (src.empty()){cout << "No Image!" << endl;system("pause");return -1;}//hsv颜色通道转换,提取图像中黄色线部分,生成掩膜图像Mat hsv;cvtColor(src, hsv, COLOR_BGR2HSV);Mat mask;inRange(hsv, Scalar(10, 50, 255), Scalar(40, 255, 255), mask);//将生成的掩膜mask膨胀一下,使掩膜区域放大Mat kernel = getStructuringElement(MORPH_RECT, Size(9, 9));dilate(mask, mask, kernel);//使用OpenCV自带的inpaint函数进行图像修复,得到目标图像//Mat inpaintImg;//inpaint(src, mask, inpaintImg, 1, INPAINT_NS);//namedWindow("inpaintImg", WINDOW_NORMAL);//imshow("inpaintImg", inpaintImg);//自己写的算法,修改图像像素,完成图像修复Mat canvas = Mat::zeros(src.size(), src.type());int r = 1;//像素查找范围--表示在该像素点上下几行像素进行查找for (int i = r; i < src.rows- r; i++){for (int j = 0; j < src.cols; j++){ if (mask.at<uchar>(i, j) != 255){ //对于非掩膜区域,直接将原像素进行像素赋值for (int c = 0; c < 3; c++){canvas.at<Vec3b>(i, j)[c] = src.at<Vec3b>(i, j)[c];} }else{//找到距离该掩膜像素点最近的非掩膜区域像素进行赋值Point res = find_Nearest_Point(mask, i, j, r);for (int c = 0; c < 3; c++){canvas.at<Vec3b>(i, j)[c] = src.at<Vec3b>(res.x, res.y)[c];}}}}//namedWindow("canvas", WINDOW_NORMAL);//imshow("canvas", canvas);//将修复之后的目标图像进行图像预处理,提取轮廓Mat gray;cvtColor(canvas, gray, COLOR_BGR2GRAY);Mat gaussian;GaussianBlur(gray, gaussian, Size(3, 3), 0);Mat thresh;threshold(gaussian, thresh, 30, 255, THRESH_BINARY_INV);Mat kernel1 = getStructuringElement(MORPH_RECT, Size(3, 3));morphologyEx(thresh, thresh, MORPH_OPEN, kernel);//namedWindow("thresh", WINDOW_NORMAL);//imshow("thresh", thresh);//轮廓提取vector<vector<Point>>contours;findContours(thresh, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);//经过面积,外接矩形特征筛选出目标区域vector<vector<Point>>EffectiveConts;for (int i = 0; i < contours.size(); i++){double area = contourArea(contours[i]);if (area>100){Rect rect = boundingRect(contours[i]);if (double(rect.height) > 30 && double(rect.width) > 30){EffectiveConts.push_back(contours[i]);}}}for (int i = 0; i < EffectiveConts.size(); i++){//计算轮廓矩Moments Mo = moments(EffectiveConts[i]);//计算质心--即插孔坐标Point center = Point(Mo.m10 / Mo.m00, Mo.m01 / Mo.m00);//效果绘制Rect rect = boundingRect(EffectiveConts[i]);rectangle(src, rect, Scalar(0, 255, 0), 5);circle(src, center, 3, Scalar(0, 0, 255), -1);}namedWindow("src", WINDOW_NORMAL);imshow("src", src);waitKey(0);system("pause");return 0;
}
总结
本文使用OpenCV C++实现网孔检测,主要操作有以下几点。
1、hsv通道转换,提取出黄色分量,得到掩模图像。
2、利用掩模图像对原图进行图像修复。
3、通过轮廓提取定位网孔位置。
以上就是我对该案例的构思以及实现方法,如果大家有更好的算法可以实现,欢迎交流学习。。。
OpenCV C++案例实战二十三《网孔检测》相关推荐
- OpenCV C++案例实战二十九《遥感图像分割》
OpenCV C++案例实战二十九<遥感图像分割> 前言 一.准备数据 二.K-Means分类 三.效果显示 四.源码 总结 前言 本案例基于k-means机器学习算法进行遥感图像分割.主 ...
- OpenCV C++案例实战二《生成蒙太奇图像》
OpenCV C++案例实战二<生成蒙太奇图像> 前言 一.输入模板图像 二.读取素材图像 三.生成蒙太奇模板 四.生成蒙太奇图像 五.源码 总结 前言 本文将使用OpenCV C++ 生 ...
- OpenCV C++案例实战二十一《制作视频播放器》
OpenCV C++案例实战二十一<制作视频播放器> 前言 一.源码 二.效果 总结 前言 本文将使用OpenCV C++ 制作简易视频播放器,用于实现视频播放基本功能. 1.通过创建滑动 ...
- OpenCV C++案例实战二十二《手势识别》
OpenCV C++案例实战二十二<手势识别> 前言 一.手部关键点检测 1.1 功能源码 1.2 功能效果 二.手势识别 2.1算法原理 2.2功能源码 三.结果显示 3.1功能源码 3 ...
- OpenCV C++案例实战二十七《角度测量》
OpenCV C++案例实战二十七<角度测量> 前言 一.鼠标响应事件 1.1功能源码 1.2功能效果 二.计算直线角度 2.1 计算直线斜率 2.2计算直线角度 2.3功能源码 三.绘制 ...
- OpenCV C++案例实战十三《人脸打马赛克》
OpenCV C++案例实战十三<人脸打马赛克> 前言 一.人脸检测 二.马赛克效果 三.效果显示 四.源码 总结 前言 本文将使用OpenCV C++ 对人脸部位打上马赛克.实现步骤其实 ...
- OpenCV C++案例实战三《二维码检测》
OpenCV C++案例实战三<二维码检测> 前言 一.二维码检测 二.二维码识别 1.通过findContours找到轮廓层级关系 三.二维码绘制 四.源码 总结 前言 本文将使用Ope ...
- OpenCV C++案例实战十二《图像全景拼接》
OpenCV C++案例实战十二<图像全景拼接> 前言 一.OpenCV Stitcher 1.功能源码 2.效果 二.图像全景拼接 1.特征检测 2.计算单应性矩阵 3.透视变换 4.图 ...
- OpenCV C++案例实战三十二《字符识别》
OpenCV C++案例实战三十二<字符识别> 前言 一.结果演示 二.制作数据集 三.字符识别 四.源码 总结 前言 本案例将使用OpenCV C++ 进行字符识别.主要包括制作数据集. ...
- OpenCV C++案例实战五《答题卡识别》
OpenCV C++案例实战五<答题卡识别> 前言 一.图像矫正 1.源码 二.获取选项区域 1.扣出每题选项 2.源码 三.获取答案 1.思路 2.辅助函数 3.源码 4.效果 总结 前 ...
最新文章
- 记一次OOM问题排查过程
- python替换所有标点符号 正则_python 把标点符号替换为空
- java属于以下哪种语言_Java属于以下哪种语言?
- Java基础---分支结构(if--else / switch---case)
- C语言socket发送json,C++实现Socket传输json封装的Mat
- PetShop 4.0知识点:加密和解密Web.config文件的配置节
- 深入浅出Python机器学习3——K最近邻算法
- 广数928te_广数928te2说明书
- BP算法(神经网络基础+BP算法推导+BP算法举例+java代码实现+Python代码实现+局限性)
- python将图片base流保存为图片文件
- 关于阿里云windows服务器上ping不通公网 ip 的解决思路
- 如何在ChemDraw中输入℃温度符号
- 提高数据分析思维能力的三大方法
- 将视频作为网站背景html,将视频作为网页背景
- 【MQ-2 可燃气体和烟雾传感器与 Arduino 配合使用】
- Illegal key size or default parameters
- 计算机主机后面板 图解,计算机主板揭秘(下)图文并茂版
- 短信与社交app的好处
- ABAP 获取屏幕字段的值 搜索帮助联动动态查询SAP
- 熟练知道eclipse中outline里各个图标的含义
热门文章
- 递归下降算法语法分析c语言
- matlab 有限元分析与应用,matlab有限元分析与应用(书及源程序)
- 如何长时间保存记忆,分享我的数据备份大法
- Windows Azure AppFabric (一) 平台简介
- 新版qq虚拟摄像头颜色不正常_云答辩 | QQ群“视频通话”来了
- oracle怎么将数据删除文件,oracle删除数据文件
- python保存h264格式视频(linux和windows)
- ffmpeg mp4视频流解码
- class文件拒绝访问
- vb.net的socket编程