c/c++语言开发共享C++ 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++&nbsp;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++&nbsp;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;  }  

总结

c/c++开发分享C++ OpenCV实战之网孔检测的实现使用opencv c++实现网孔检测,主要操作有以下几点。

1、hsv通道转换,提取出黄色分量,得到掩模图像。

2、利用掩模图像对原图进行图像修复。

3、通过轮廓提取定位网孔位置。

以上就是c++ opencv实战之网孔检测的实现的详细内容,更多关于c++ opencv网孔检测的资料请关注<计算机技术网(www.ctvol.com)!!>其它相关文章!

需要了解更多c/c++开发分享C++ OpenCV实战之网孔检测的实现,都可以关注C/C++技术分享栏目—计算机技术网(www.ctvol.com)!

本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。

ctvol管理联系方式QQ:251552304

本文章地址:https://www.ctvol.com/c-cdevelopment/1248242.html

(0)
上一篇 2022年9月29日
下一篇 2022年9月29日

精彩推荐