OpenCV-差分法实现绿叶识别(图像差分+颜色通道)

简介: OpenCV-差分法实现绿叶识别(图像差分+颜色通道)

实现原理

      物体识别是图像处理学在现实生活中较多的应用之一,目前最为流行的就是运用AI、机器学习等技术结合图像处理学,大量训练数据集,以实现智能且精确的识别。说到人工智能,很多人可能觉得它非常深奥和复杂,其实说白了它最底层的识别逻辑还是基于普通的图像分析,像特征提取、轮廓分析、比对分析等等,再在庞大的数据集中按照相似程度,分析出一个最可能的结果。


      本文提供了一种相对简单的思路来实现绿叶识别,适合初学图像处理的新人研究参考。该方法为差分法:首先对图像进行高斯滤波处理预处理,平滑图像数据;其次,将图像颜色通道按RGB拆分,因为识别物为绿叶,其最明显的特征就是颜色;差分法,将绿色通道减去蓝色通道,之所以选择这两个通道,是因为蓝色通道和绿叶的关系较远,而红色搭配绿色可是黄色哦,绿叶中存在黄色特征信息可是再正常不过了;之后,对差分图进行OTSU阈值处理,得到掩膜感兴趣ROI区域;再后,就是对区域进行闭运算和孔洞闭合处理,保持区域完整性;最后,根据掩膜提取绿叶,完成。

功能函数代码

1)识别绿叶函数。

// 识别绿叶
Mat IdentifyLeaves(cv::Mat input)
{
  CV_Assert(input.channels() == 3);
  Mat temp, result, mask, hole;
  int row = input.rows;
  int col = input.cols;
  // 高斯滤波
  GaussianBlur(input, temp, Size(5, 5), 0);
  // 通道拆分
  vector<cv::Mat> c;
  split(temp, c);
  // 绿通道-蓝通道,提取绿色区域
  Mat diff = c[1] - c[0];
  threshold(diff, mask, 0, 255, THRESH_OTSU);
  // 闭运算封口
  cv::Mat element = getStructuringElement(MORPH_ELLIPSE, Size(9, 9));
  cv::morphologyEx(mask, mask, MORPH_CLOSE, element);
  // 孔洞闭合
  hole = 255 - mask;
  Clear_MicroConnected_Areas(hole, hole, row*col / 300);
  mask = 255 - hole;
  Clear_MicroConnected_Areas(mask, mask, row*col / 300);
  // 识别区域标记
  result = input.clone();
  result.setTo(Scalar(0, 0, 0), mask == 0);
  return result;
}

2)清除微小面积连通区函数,用于孔洞闭合。具体介绍见:

OpenCV-清除小面积连通域_翟天保的博客-CSDN博客

/**
* @brief  Clear_MicroConnected_Areas         清除微小面积连通区函数
* @param  src                                输入图像矩阵
* @param  dst                                输出结果
* @return min_area                           设定的最小面积清除阈值
*/
void Clear_MicroConnected_Areas(cv::Mat src, cv::Mat &dst, double min_area)
{
  // 备份复制
  dst = src.clone();
  std::vector<std::vector<cv::Point> > contours;  // 创建轮廓容器
  std::vector<cv::Vec4i>  hierarchy;
  // 寻找轮廓的函数
  // 第四个参数CV_RETR_EXTERNAL,表示寻找最外围轮廓
  // 第五个参数CV_CHAIN_APPROX_NONE,表示保存物体边界上所有连续的轮廓点到contours向量内
  cv::findContours(src, contours, hierarchy, cv::RETR_TREE, cv::CHAIN_APPROX_NONE, cv::Point());
  if (!contours.empty() && !hierarchy.empty())
  {
    std::vector<std::vector<cv::Point> >::const_iterator itc = contours.begin();
    // 遍历所有轮廓
    while (itc != contours.end())
    {
      // 定位当前轮廓所在位置
      cv::Rect rect = cv::boundingRect(cv::Mat(*itc));
      // contourArea函数计算连通区面积
      double area = contourArea(*itc);
      // 若面积小于设置的阈值
      if (area < min_area)
      {
        // 遍历轮廓所在位置所有像素点
        for (int i = rect.y; i < rect.y + rect.height; i++)
        {
          uchar *output_data = dst.ptr<uchar>(i);
          for (int j = rect.x; j < rect.x + rect.width; j++)
          {
            // 将连通区的值置0
            if (output_data[j] == 255)
            {
              output_data[j] = 0;
            }
          }
        }
      }
      itc++;
    }
  }
}

C++测试代码

#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
void Clear_MicroConnected_Areas(cv::Mat src, cv::Mat &dst, double min_area);
Mat IdentifyLeaves(cv::Mat input);
int main()
{
  Mat src = imread("test1.png");
  Mat result = IdentifyLeaves(src);
  imshow("src", src);
  imshow("result", result);
  waitKey(0);
  return 0;
}
/**
* @brief  Clear_MicroConnected_Areas         清除微小面积连通区函数
* @param  src                                输入图像矩阵
* @param  dst                                输出结果
* @return min_area                           设定的最小面积清除阈值
*/
void Clear_MicroConnected_Areas(cv::Mat src, cv::Mat &dst, double min_area)
{
  // 备份复制
  dst = src.clone();
  std::vector<std::vector<cv::Point> > contours;  // 创建轮廓容器
  std::vector<cv::Vec4i>  hierarchy;
  // 寻找轮廓的函数
  // 第四个参数CV_RETR_EXTERNAL,表示寻找最外围轮廓
  // 第五个参数CV_CHAIN_APPROX_NONE,表示保存物体边界上所有连续的轮廓点到contours向量内
  cv::findContours(src, contours, hierarchy, cv::RETR_TREE, cv::CHAIN_APPROX_NONE, cv::Point());
  if (!contours.empty() && !hierarchy.empty())
  {
    std::vector<std::vector<cv::Point> >::const_iterator itc = contours.begin();
    // 遍历所有轮廓
    while (itc != contours.end())
    {
      // 定位当前轮廓所在位置
      cv::Rect rect = cv::boundingRect(cv::Mat(*itc));
      // contourArea函数计算连通区面积
      double area = contourArea(*itc);
      // 若面积小于设置的阈值
      if (area < min_area)
      {
        // 遍历轮廓所在位置所有像素点
        for (int i = rect.y; i < rect.y + rect.height; i++)
        {
          uchar *output_data = dst.ptr<uchar>(i);
          for (int j = rect.x; j < rect.x + rect.width; j++)
          {
            // 将连通区的值置0
            if (output_data[j] == 255)
            {
              output_data[j] = 0;
            }
          }
        }
      }
      itc++;
    }
  }
}
// 识别绿叶
Mat IdentifyLeaves(cv::Mat input)
{
  CV_Assert(input.channels() == 3);
  Mat temp, result, mask, hole;
  int row = input.rows;
  int col = input.cols;
  // 高斯滤波
  GaussianBlur(input, temp, Size(5, 5), 0);
  // 通道拆分
  vector<cv::Mat> c;
  split(temp, c);
  // 绿通道-蓝通道,提取绿色区域
  Mat diff = c[1] - c[0];
  threshold(diff, mask, 0, 255, THRESH_OTSU);
  // 闭运算封口
  cv::Mat element = getStructuringElement(MORPH_ELLIPSE, Size(9, 9));
  cv::morphologyEx(mask, mask, MORPH_CLOSE, element);
  // 孔洞闭合
  hole = 255 - mask;
  Clear_MicroConnected_Areas(hole, hole, row*col / 300);
  mask = 255 - hole;
  Clear_MicroConnected_Areas(mask, mask, row*col / 300);
  // 识别区域标记
  result = input.clone();
  result.setTo(Scalar(0, 0, 0), mask == 0);
  return result;
}

测试效果

图1 原图1

图2 效果图1

图3 原图2

图4 效果图2

图5 原图3

图6 效果图3

      本文只是提供了一种简单的识别思路,不可能满足所有的场景。举几个例子,如图6所示,因为孔洞闭合的缘故,导致绿叶间的间隙也被涵盖了;又或者,当所识别的绿叶没那么绿,有点偏暗时,蓝色通道的比例自然也提高了,此时用差分法效果就不会那么好了。


      总而言之,不同的场景和需求还是需要结合实际进行算法的设计,天下没有一种算法是可以解决一切问题的,即便是人工智能也不可能,特殊问题特殊对待,加油!


      如果函数有什么可以改进完善的地方,非常欢迎大家指出,一同进步何乐而不为呢~


      如果文章帮助到你了,可以点个赞让我知道,我会很快乐~加油!

相关文章
|
2月前
|
计算机视觉
Opencv学习笔记(三):图像二值化函数cv2.threshold函数详解
这篇文章详细介绍了OpenCV库中的图像二值化函数`cv2.threshold`,包括二值化的概念、常见的阈值类型、函数的参数说明以及通过代码实例展示了如何应用该函数进行图像二值化处理,并展示了运行结果。
400 0
Opencv学习笔记(三):图像二值化函数cv2.threshold函数详解
|
3月前
|
算法 计算机视觉
opencv图像形态学
图像形态学是一种基于数学形态学的图像处理技术,它主要用于分析和修改图像的形状和结构。
51 4
|
5月前
|
计算机视觉 Python
opencv识别颜色
opencv识别颜色
|
3月前
|
存储 计算机视觉
Opencv的基本操作(一)图像的读取显示存储及几何图形的绘制
本文介绍了使用OpenCV进行图像读取、显示和存储的基本操作,以及如何绘制直线、圆形、矩形和文本等几何图形的方法。
Opencv的基本操作(一)图像的读取显示存储及几何图形的绘制
|
4月前
|
算法 计算机视觉 Python
python利用opencv进行相机标定获取参数,并根据畸变参数修正图像附有全部代码(流畅无痛版)
该文章详细介绍了使用Python和OpenCV进行相机标定以获取畸变参数,并提供了修正图像畸变的全部代码,包括生成棋盘图、拍摄标定图像、标定过程和畸变矫正等步骤。
python利用opencv进行相机标定获取参数,并根据畸变参数修正图像附有全部代码(流畅无痛版)
|
4月前
|
计算机视觉 C++
基于VS2019和Opencv4,对hsv颜色空间的图像分割原理以及实现
这篇文章介绍了基于HSV颜色空间的图像分割原理,包括HSV模型的基本概念和如何在OpenCV中通过设置HSV的色彩范围来实现图像中特定颜色的物体分割,并通过示例代码展示了在静态图像和视频流中进行颜色分割的方法。
基于VS2019和Opencv4,对hsv颜色空间的图像分割原理以及实现
WK
|
4月前
|
编解码 计算机视觉 Python
如何在OpenCV中进行图像转换
在OpenCV中,图像转换涉及颜色空间变换、大小调整及类型转换等操作。常用函数如`cvtColor`可实现BGR到RGB、灰度图或HSV的转换;`resize`则用于调整图像分辨率。此外,通过`astype`或`convertScaleAbs`可改变图像数据类型。对于复杂的几何变换,如仿射或透视变换,则可利用`warpAffine`和`warpPerspective`函数实现。这些技术为图像处理提供了强大的工具。
WK
117 1
|
5月前
|
机器学习/深度学习 数据采集 算法
Python基于OpenCV和卷积神经网络CNN进行车牌号码识别项目实战
Python基于OpenCV和卷积神经网络CNN进行车牌号码识别项目实战
340 19
|
6月前
|
算法 计算机视觉
【Qt&OpenCV 图像的感兴趣区域ROI】
【Qt&OpenCV 图像的感兴趣区域ROI】
186 1
|
6月前
|
运维 算法 计算机视觉
【Qt&OpenCV 图像的模板匹配 matchTemplate/minMaxLoc】
【Qt&OpenCV 图像的模板匹配 matchTemplate/minMaxLoc】
83 1