服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C/C++ - C++ OpenCV实战之网孔检测的实现

C++ OpenCV实战之网孔检测的实现

2022-11-22 14:21Zero___Chen C/C++

这篇文章主要介绍了如何利用C++和OpenCV实现网孔检测,文中的示例代码讲解详细,对我们学习OpenCV有一定帮助,感兴趣的小伙伴可以了解一下

前言

前段时间,有位粉丝私信我,给我发了一张图片,如下图所示:

C++ OpenCV实战之网孔检测的实现

在这里贴出他的原话。

C++ OpenCV实战之网孔检测的实现

从他给的图片分析,该图存在遮挡,所以不能简单的二值化,然后提取图像轮廓去寻找结果。所以,我就想如何去掉这些遮挡物(即图像修复)。从图像可知,该遮挡物是黄色的线,所以,我就想可否使用hsv色彩空间提取出黄色,然后得到二值掩模图像,最后对原图进行修复。接下来,就一起看看是如何一步步实现的吧。

 

一、HSV通道转换

通过hsv通道转换,可以提取出图像中的黄色分量。

    //hsv颜色通道转换,提取图像中黄色线部分,生成掩膜图像
  Mat hsv;
  cvtColor(src, hsv, COLOR_BGR2HSV);

  Mat mask;
  inRange(hsv, Scalar(10, 50, 255), Scalar(40, 255, 255), mask);

结果如图所示:

C++ OpenCV实战之网孔检测的实现

 

二、图像修复

关于图像修复的相关知识可以参考我之前的博文。这里就不细说了。

OpenCV C++案例实战十四《图像修复》

OpenCV C++案例实战十七《图像去水印》

我们拿到上面的mask掩模图像,需要对其进行膨胀处理,使修复区域范围扩大。

    //将生成的掩膜mask膨胀一下,使掩膜区域放大
  Mat kernel = getStructuringElement(MORPH_RECT, Size(9, 9));
  dilate(mask, mask, kernel);

C++ OpenCV实战之网孔检测的实现

接下来,需要对图像进行修复。这里我提供两种修复方法,一种是OpenCV提供的inpaint函数,一种是我自己写的。

2.1 OpenCV函数实现

    //使用OpenCV自带的inpaint函数进行图像修复,得到目标图像
  Mat inpaintImg;
  inpaint(src, mask, inpaintImg, 1, INPAINT_NS);

C++ OpenCV实战之网孔检测的实现

效果如图所示。

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];
              }
          }
      }
  }

C++ OpenCV实战之网孔检测的实现

效果如何所示

 

三、轮廓提取

接下来我们只需要对修复之后的图像进行轮廓提取就可以了。

    //将修复之后的目标图像进行图像预处理,提取轮廓
  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);
  }

C++ OpenCV实战之网孔检测的实现

如图为该案例最终效果。

 

五、源码

#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、通过轮廓提取定位网孔位置。

以上就是C++ OpenCV实战之网孔检测的实现的详细内容,更多关于C++ OpenCV网孔检测的资料请关注服务器之家其它相关文章!

原文链接:https://blog.csdn.net/Zero___Chen/article/details/124537893

延伸 · 阅读

精彩推荐
  • C/C++关于c++ 智能指针及 循环引用的问题

    关于c++ 智能指针及 循环引用的问题

    下面小编就为大家带来一篇关于c++ 智能指针及 循环引用的问题。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧...

    C++教程网11902021-04-26
  • C/C++史上最强C语言分支和循环教程详解

    史上最强C语言分支和循环教程详解

    这篇文章主要介绍了史上最强C语言分支和循环教程详解,本文通过代码演示给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的...

    鹿九丸8142022-02-23
  • C/C++给ActiveX签名的实现方法详解

    给ActiveX签名的实现方法详解

    本篇文章是对给ActiveX签名的实现方法进行了详细的分析介绍,需要的朋友参考下...

    C语言教程网4882020-12-01
  • C/C++C语言圣诞树的实现示例

    C语言圣诞树的实现示例

    本篇主要介绍了C语言圣诞树的实现示例,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    补集王子7742022-07-16
  • C/C++OpenCV图像旋转Rotate的详细介绍

    OpenCV图像旋转Rotate的详细介绍

    这篇文章主要介绍了OpenCV图像旋转Rotate,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...

    翟天保Steven10852022-11-21
  • C/C++C语言实现英文单词助手

    C语言实现英文单词助手

    这篇文章主要为大家详细介绍了C语言实现单词小助手,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...

    SZ9967958832021-08-04
  • C/C++利用Matlab绘制地图的超详细教程

    利用Matlab绘制地图的超详细教程

    worldmap和usamap是axesm的子类,worldmap是用于生成世界地图坐标区域,usamap用于生成美国地图坐标区域。本文将详细为大家介绍如何利用这两个函数绘制地图,...

    slandarer11452022-10-07
  • C/C++c++ 数据结构map的使用详解

    c++ 数据结构map的使用详解

    这篇文章主要介绍了c++ 数据结构map的使用详解,帮助大家更好的理解和学习使用c++,感兴趣的朋友可以了解下...

    bigbillfighter9342021-11-03