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

目录
  • 前言
  • 一、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、通过轮廓提取定位网孔位置。

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

(0)

相关推荐

  • opencv3/C++实现霍夫圆/直线检测

    霍夫直线检测 参数说明: cv::HoughLinesP( InputArray src, // 输入图像(8位灰度图像) OutputArray lines, // 输出直线两点坐标(vector<Vec4i>) double rho, // 生成极坐标时候的像素扫描步长 double theta, //生成极坐标时候的角度步长(一般取CV_PI/180) int threshold, // 累加器阈值,获得足够交点的极坐标点才被看成是直线 double minLineLength=0;//

  • opencv3/C++ 实现SURF特征检测

    SURF即Speeded Up Robust Features加速鲁棒特征: SURF可以用于对象定位和识别.人脸识别.3D重建.对象跟踪和提取兴趣点等. 工作原理: 1.选择图像中POI(Points of Interest) Hessian Matrix; 2.在不同的尺度空间发现关键点,非最大信号压制; 3.发现特征点方法.旋转不变性要求; 4.生成特征向量; 类SURF中成员函数create()参数说明: static Ptr<SURF> create( double hessianT

  • C++ OpenCV实战之标记点检测的实现

    在实际应用中,能够直接利用霍夫圆检测这些理想方法的应用场景是非常少的,更多的是利用拟合的办法去寻找圆形. 大致思路如下,首先先选择要处理的ROI部分,记录下该图的左上点在原图的坐标,如果原图过大,要先进行等比例缩放:然后利用自适应阈值和Canny边缘提取进行处理,再进行闭运算与轮廓检测,计算点集面积,通过筛选面积阈值去除杂点,最后进行轮廓检测,拟合椭圆,效果如下: 1.导入原图: 2.截取ROI 3.进行自适应阈值化与Canny边缘提取 4.进行闭运算,然后轮廓检测,然后计算点集面积,通过面积阈

  • C++ opencv霍夫圆检测使用案例详解

    本程序是一个最简单的霍夫圆检测函数的使用案例,刚刚学会的用法,发一下,可以参考,参数啥的可根据图片调节. #pragma once #include<quickopencv.h> #include<vector> #include <stdio.h> #include <iostream> #include "opencv2/highgui/highgui.hpp" #include "opencv2/imgproc/imgpr

  • C++ OpenCV实战之车道检测

    目录 前言 一.获取车道ROI区域 二.车道检测 1.灰度.阈值 2.获取非零像素点 3.绘制车道线 总结 前言 本文将使用OpenCV C++ 进行车道检测. 一.获取车道ROI区域 原图如图所示. 使用下面代码段获取ROI区域.该ROI区域点集根据图像特征自己设定.通过fillPoly填充ROI区域,最终通过copyTo在原图中扣出ROI. void GetROI(Mat src, Mat &image) {     Mat mask = Mat::zeros(src.size(), src

  • C++ OpenCV实现二维码检测功能

    目录 前言 一.二维码检测 二.二维码识别 三.二维码绘制 四.源码 总结 前言 本文将使用OpenCV C++ 进行二维码检测. 一.二维码检测 首先我们要先将图像进行预处理,通过灰度.滤波.二值化等操作提取出图像轮廓.在这里我还添加了形态学操作,消除噪点,有效将矩形区域连接起来. Mat gray; cvtColor(src, gray, COLOR_BGR2GRAY); Mat blur; GaussianBlur(gray, blur, Size(3, 3), 0); Mat bin;

  • C++利用opencv实现人脸检测

    小编所有的帖子都是基于unbuntu系统的,当然稍作修改同样试用于windows的,经过小编的绞尽脑汁,把刚刚发的那篇python 实现人脸和眼睛的检测的程序用C++ 实现了,当然,也参考了不少大神的博客,下面我们就一起来看看: Linux系统下安装opencv我就再啰嗦一次,防止有些人没有安装没调试出来喷小编的程序是个坑, sudo apt-get install libcv-dev sudo apt-get install libopencv-dev 看看你的usr/share/opencv

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

    目录 前言 一.HSV通道转换 二.图像修复 2.1 OpenCV函数实现 2.2 MyFunction 三.轮廓提取 四.效果显示 五.源码 总结 前言 前段时间,有位粉丝私信我,给我发了一张图片,如下图所示: 在这里贴出他的原话. 从他给的图片分析,该图存在遮挡,所以不能简单的二值化,然后提取图像轮廓去寻找结果.所以,我就想如何去掉这些遮挡物(即图像修复).从图像可知,该遮挡物是黄色的线,所以,我就想可否使用hsv色彩空间提取出黄色,然后得到二值掩模图像,最后对原图进行修复.接下来,就一起看

  • Python Opencv实战之文字检测OCR

    目录 1.相关函数的讲解 2.代码展示 Detecting Words Detecting ONLY Digits 3.问题叙述 4.image_to_data()配置讲解 5.项目拓展 6.总结与评价 1.相关函数的讲解 image_to_data()的输出结果是表格形式,输出变量的类型依旧是字符串. 你会得到一个这样的列表['level', 'page_num', 'block_num', 'par_num', 'line_num', 'word_num', 'left', 'top', '

  • C++ OpenCV实战之零部件的自动光学检测

    目录 一.背景 二.基础知识 三.代码实现 1.实现多窗口展示 2.降噪处理 3.背景去除 4.连通图实现 5.计算连通域面积 6.轮廓检测 四.总结 一.背景 首先任务背景是AOI(自动光学检测) 最重要的目的在于:将前景和物体进行分割与分类: 场景示意图: 需要注意,在螺母的传送带上,需要有前光和背光,给物体打光才能够拍摄清晰的图像: 二.基础知识 首先分为以下几步: 1.噪声抑制(预处理) 2.背景移除(分割) 3.二值化 4.连通域.轮廓查找算法 降噪算法 先使用中值滤波对椒盐噪声进行过

  • Python+OpenCV实现单个圆形孔和针检测

    如果中间红色区域是针则可以用下面的代码检测,其阈值和斑点检测的参数根据图像像素值做相应修改 检测的主要思路是先通过找到外面的大圆,再通过圆心定位出一个ROI区域,在ROI区域中检测中心的检测对象 import os import cv2 import numpy as np import math # 检测针脚位置 def needelCenter_detect(img): params = cv2.SimpleBlobDetector_Params() # Setup SimpleBlobDe

  • JavaCV摄像头实战之实现口罩检测

    目录 本篇概览 问题提前告知 关于百度AI开放平台 编码:添加依赖库 编码:封装请求和响应百度AI开放平台的代码 DetectService接口的实现 主程序 验证 本篇概览 本文是<JavaCV的摄像头实战>系列的第十四篇,如标题所说,今天的功能是检测摄像头内的人是否带了口罩,把检测结果实时标注在预览窗口,如下图所示: 整个处理流程如下,实现口罩检测的关键是将图片提交到百度AI开放平台,然后根据平台返回的结果在本地预览窗口标识出人脸位置,以及此人是否带了口罩: 问题提前告知 依赖云平台处理业

  • OpenCV+python实现实时目标检测功能

    环境安装 安装Anaconda,官网链接Anaconda 使用conda创建py3.6的虚拟环境,并激活使用 conda create -n py3.6 python=3.6 //创建 conda activate py3.6 //激活 3.安装依赖numpy和imutils //用镜像安装 pip install -i https://pypi.tuna.tsinghua.edu.cn/simple numpy pip install -i https://pypi.tuna.tsinghua

  • Python使用Opencv实现边缘检测以及轮廓检测的实现

    边缘检测 Canny边缘检测器是一种被广泛使用的算法,并被认为是边缘检测最优的算法,该方法使用了比高斯差分算法更复杂的技巧,如多向灰度梯度和滞后阈值化. Canny边缘检测器算法基本步骤: 平滑图像:通过使用合适的模糊半径执行高斯模糊来减少图像内的噪声. 计算图像的梯度:这里计算图像的梯度,并将梯度分类为垂直.水平和斜对角.这一步的输出用于在下一步中计算真正的边缘. 非最大值抑制:利用上一步计算出来的梯度方向,检测某一像素在梯度的正方向和负方向上是否是局部最大值,如果是,则抑制该像素(像素不属于

  • Python+Opencv实战之人脸追踪详解

    目录 前言 人脸追踪技术简介 使用基于 dlib DCF 的跟踪器进行人脸跟踪 使用基于 dlib DCF 的跟踪器进行对象跟踪 小结 前言 人脸处理是人工智能中的一个热门话题,人脸处理可以使用计算机视觉算法从人脸中自动提取大量信息,例如身份.意图和情感:而目标跟踪试图估计目标在整个视频序列中的轨迹,其中只有目标的初始位置是已知的,将这两者进行结合将产生许多有趣的应用.由于外观变化.遮挡.快速运动.运动模糊和比例变化等多种因素,人脸追踪非常具有挑战性. 人脸追踪技术简介 基于判别相关滤波器 (d

随机推荐