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++案例实战二十三《网孔检测》相关推荐

  1. OpenCV C++案例实战二十九《遥感图像分割》

    OpenCV C++案例实战二十九<遥感图像分割> 前言 一.准备数据 二.K-Means分类 三.效果显示 四.源码 总结 前言 本案例基于k-means机器学习算法进行遥感图像分割.主 ...

  2. OpenCV C++案例实战二《生成蒙太奇图像》

    OpenCV C++案例实战二<生成蒙太奇图像> 前言 一.输入模板图像 二.读取素材图像 三.生成蒙太奇模板 四.生成蒙太奇图像 五.源码 总结 前言 本文将使用OpenCV C++ 生 ...

  3. OpenCV C++案例实战二十一《制作视频播放器》

    OpenCV C++案例实战二十一<制作视频播放器> 前言 一.源码 二.效果 总结 前言 本文将使用OpenCV C++ 制作简易视频播放器,用于实现视频播放基本功能. 1.通过创建滑动 ...

  4. OpenCV C++案例实战二十二《手势识别》

    OpenCV C++案例实战二十二<手势识别> 前言 一.手部关键点检测 1.1 功能源码 1.2 功能效果 二.手势识别 2.1算法原理 2.2功能源码 三.结果显示 3.1功能源码 3 ...

  5. OpenCV C++案例实战二十七《角度测量》

    OpenCV C++案例实战二十七<角度测量> 前言 一.鼠标响应事件 1.1功能源码 1.2功能效果 二.计算直线角度 2.1 计算直线斜率 2.2计算直线角度 2.3功能源码 三.绘制 ...

  6. OpenCV C++案例实战十三《人脸打马赛克》

    OpenCV C++案例实战十三<人脸打马赛克> 前言 一.人脸检测 二.马赛克效果 三.效果显示 四.源码 总结 前言 本文将使用OpenCV C++ 对人脸部位打上马赛克.实现步骤其实 ...

  7. OpenCV C++案例实战三《二维码检测》

    OpenCV C++案例实战三<二维码检测> 前言 一.二维码检测 二.二维码识别 1.通过findContours找到轮廓层级关系 三.二维码绘制 四.源码 总结 前言 本文将使用Ope ...

  8. OpenCV C++案例实战十二《图像全景拼接》

    OpenCV C++案例实战十二<图像全景拼接> 前言 一.OpenCV Stitcher 1.功能源码 2.效果 二.图像全景拼接 1.特征检测 2.计算单应性矩阵 3.透视变换 4.图 ...

  9. OpenCV C++案例实战三十二《字符识别》

    OpenCV C++案例实战三十二<字符识别> 前言 一.结果演示 二.制作数据集 三.字符识别 四.源码 总结 前言 本案例将使用OpenCV C++ 进行字符识别.主要包括制作数据集. ...

  10. OpenCV C++案例实战五《答题卡识别》

    OpenCV C++案例实战五<答题卡识别> 前言 一.图像矫正 1.源码 二.获取选项区域 1.扣出每题选项 2.源码 三.获取答案 1.思路 2.辅助函数 3.源码 4.效果 总结 前 ...

最新文章

  1. 记一次OOM问题排查过程
  2. python替换所有标点符号 正则_python 把标点符号替换为空
  3. java属于以下哪种语言_Java属于以下哪种语言?
  4. Java基础---分支结构(if--else / switch---case)
  5. C语言socket发送json,C++实现Socket传输json封装的Mat
  6. PetShop 4.0知识点:加密和解密Web.config文件的配置节
  7. 深入浅出Python机器学习3——K最近邻算法
  8. 广数928te_广数928te2说明书
  9. BP算法(神经网络基础+BP算法推导+BP算法举例+java代码实现+Python代码实现+局限性)
  10. python将图片base流保存为图片文件
  11. 关于阿里云windows服务器上ping不通公网 ip 的解决思路
  12. 如何在ChemDraw中输入℃温度符号
  13. 提高数据分析思维能力的三大方法
  14. 将视频作为网站背景html,将视频作为网页背景
  15. 【MQ-2 可燃气体和烟雾传感器与 Arduino 配合使用】
  16. Illegal key size or default parameters
  17. 计算机主机后面板 图解,计算机主板揭秘(下)图文并茂版
  18. 短信与社交app的好处
  19. ABAP 获取屏幕字段的值 搜索帮助联动动态查询SAP
  20. 熟练知道eclipse中outline里各个图标的含义

热门文章

  1. 递归下降算法语法分析c语言
  2. matlab 有限元分析与应用,matlab有限元分析与应用(书及源程序)
  3. 如何长时间保存记忆,分享我的数据备份大法
  4. Windows Azure AppFabric (一) 平台简介
  5. 新版qq虚拟摄像头颜色不正常_云答辩 | QQ群“视频通话”来了
  6. oracle怎么将数据删除文件,oracle删除数据文件
  7. python保存h264格式视频(linux和windows)
  8. ffmpeg mp4视频流解码
  9. class文件拒绝访问
  10. vb.net的socket编程