数字图像处理OpenCV——实验三 图像分割实验

本文涉及的产品
视觉智能开放平台,分割抠图1万点
视觉智能开放平台,图像资源包5000点
视觉智能开放平台,视频资源包5000点
简介: 实验三 图像分割实验实验项目名称:图像分割实验(1) 进一步理解图像的阈值分割方法和边缘检测方法的原理。(2) 掌握图像基本全局阈值方法和最大类间方差法(otsu法)的原理并编程实现。(3) 编程实现图像的边缘检测。编程实现图像阈值分割(基本全局阈值方法和otsu法)和边缘检测。图像的二值化处理图像分割中的一个主要内容,就是将图像上的点的灰度置为0或255,也就是讲整个图像呈现出明显的黑白效果。用I表示原图,R表示二值化后的图,则二值化的过程可以用以下公式表示:thr表示选取的阈值。二值化的过

实验三 图像分割实验

实验项目名称:图像分割实验

实验项目性质:验证性实验

所属课程名称:数字图像分析与艺术化处理

实验计划学时:2

一、实验目的

    1. 进一步理解图像的阈值分割方法和边缘检测方法的原理。
    2. 掌握图像基本全局阈值方法和最大类间方差法(otsu法)的原理并编程实现。
    3. 编程实现图像的边缘检测。

    二、实验内容和要求

    编程实现图像阈值分割(基本全局阈值方法和otsu法)和边缘检测。

    三、实验主要仪器设备和材料

    计算机,VS2017+OpenCV

    四、实验原理与方法

    1、图像的阈值分割的基本原理

    图像的二值化处理图像分割中的一个主要内容,就是将图像上的点的灰度置为0255,也就是讲整个图像呈现出明显的黑白效果。用I表示原图,R表示二值化后的图,则二值化的过程可以用以下公式表示:

        image.gif编辑

    thr表示选取的阈值。二值化的过程就是当原图的像素灰度值大于阈值就将其变白,否则就将其变黑。即将256个亮度等级的灰度图像通过适当的阀值选取而将图像变为二个级别灰度级,这样只有二个灰度级的图像在图像处理分析过程中占有非常重要的地位,特别是在实用的图像处理中。

    根据对全图使用统一阈值还是对不同区域使用不同阈值,可以分为全局阈值方法(global thresholding)和局部阈值方法(local thresholding,也叫做自适应阈值方法adaptive thresholding);这种与坐标相关的阈值也叫动态阈值,具体的方法,可以参考相关的图像处理书籍。

    基本全局阈值方法,即在整个图像中所有的象素点,其阈值thr相同,具体步骤为:

      1. 选取一个初始估计值T;
      2. 用T分割图像。这样便会生成两组像素集合:G1由所有灰度值大于T的像素组成,而G2由所有灰度值小于或等于T的像素组成。
      3. 对G1和G2中所有像素计算平均灰度值u1和u2。
      4. 计算新的阈值:T=(u1 + u2)/2。
      5. 重复步骤(2)到(4),直到得到的T值之差小于一个事先定义的参数T0。

      Otsu方法的算法步骤为:

        1. 先计算图像的归一化直方图;
        2. i表示分类的阈值,也即一个灰度级,从0开始迭代;
        3. 通过归一化的直方图,统计0~i 灰度级的像素(背景像素) 所占整幅图像的比例w0,并统计背景像素的平均灰度u0;统计i~255灰度级的像素(前景像素) 所占整幅图像的比例w1,并统计前景像素的平均灰度u1;
        4. 计算前景像素和背景像素的方差 g = w0*w1*(u0-u1) (u0-u1)
        5. i++,直到i为256时结束迭代;
        6. 将最大g相应的i值作为图像的全局阈值。

        2、边缘检测

        图像中边缘的检测可以借助一阶和二阶微分实现,常见的一阶边缘检测算子即梯度算子包括Roberts算子、Prewitt算子和Sobel算子,二阶算子主要是Laplacian算子,由于受噪声影响比较大,往往在使用之前先对图像进行平滑处理,LOG算子就是先对图像进行高斯平滑,然后进行拉普拉斯变换并求零交叉点。Canny算子是最优的边缘检测算子。

        五、实验内容和要求

        1.图像的阈值分割:

        图像为车牌图像,编写代码实现基本全局阈值法和Otsu法,比较分割结果。

        2.边缘检测

        用边缘检测算子对车牌图像进行处理,可以用梯度算子、LOG算子或Canny算子(Canny算子可以直接用OpenCV函数)。比较先阈值分割后边缘检测和直接对图像进行边缘检测这两种情况的结果是否有差别。

        注意:这里提取灰度边缘即可。

        六.实验代码

        #include <iostream>  
        #include <opencv2/opencv.hpp>  
        using namespace std;
        using namespace cv;
        // 拉普拉斯锐化函数
        void LaplacianSharpDeal(const Mat& src, Mat& dst) {
          if (!src.data)return;
          for (int i = 0; i < src.rows; ++i)
            for (int j = 0; j < src.cols; ++j) {
              float a;
              if (i > 1 && i < src.rows - 1 && j > 1 && j < src.cols - 1) {
                a = 5 * (float)src.at<uchar>(i, j) - (float)src.at<uchar>(i - 1, j) - (float)src.at<uchar>(i, j - 1) -
                  (float)src.at<uchar>(i, j + 1) - (float)src.at<uchar>(i + 1, j);
              }
              else {//边缘赋值
                a = src.at<uchar>(i, j);
              }
              if (a > 255 || a < 0) {
                dst.at<uchar>(i, j) = src.at<uchar>(i, j);
              }
              else {
                dst.at<uchar>(i, j) = a;
              }
            }
        }
        // 基本全局阈值方法函数
        int BasicGlobalThreshold(Mat src, float oldValue)
        {
          int cols = src.cols;
          int rows = src.rows;
          float G1 = 0;
          float G2 = 0;
          float g1 = 0;
          float g2 = 0;
          float u1 = 0;
          float u2 = 0;
          float T0 = 0;
          // 计算灰度直方图分布,统计像素数和频率
          for (int i = 0; i < rows; i++)
          {
            for (int j = 0; j < cols; j++)
            {
              if (src.at<uchar>(i, j) > oldValue)
              {
                G1 += src.at<uchar>(i, j);
                g1 += 1;
              }
              else
              {
                G2 += src.at<uchar>(i, j);
                g2 += 1;
              }
            }
          }
          u1 = G1 / g1;
          u2 = G2 / g2;
          T0 = (u1 + u2) / 2;
          std::cout << T0 << std::endl;
          if (abs(oldValue - T0) < 0.1) {
            return T0;
          }
          else
          {
            BasicGlobalThreshold(src, T0);
          }
        }
        // Otsu方法函数
        int Otsu(Mat src)
        {
          int cols = src.cols;
          int rows = src.rows;
          int nPixelNum = cols * rows;
          // 初始化
          int pixelNum[256];
          double probability[256];
          for (int i = 0; i < 256; i++)
          {
            pixelNum[i] = 0;
            probability[i] = 0.0;
          }
          // 统计像素数和频率
          for (int i = 0; i < rows; i++)
          {
            for (int j = 0; j < cols; j++)
            {
              pixelNum[src.at<uchar>(i, j)]++;
            }
          }
          for (int i = 0; i < 256; i++)
          {
            probability[i] = (double)0.1 * pixelNum[i] / nPixelNum;
          }
          // 计算
          int Threshold = 0;          // 最佳阈值
          double MaxDelta = 0.0;      // 最大类间方差
          double Mean_0 = 0.0;        // 左边平均值
          double Mean_1 = 0.0;        // 右边平均值
          double Delta = 0.0;         // 类间方差
          double Mean_0_temp = 0.0;   // 左边平均值中间值
          double Mean_1_temp = 0.0;   // 右边平均值中间值
          double Probability_0 = 0.0;       // 左边频率值
          double Probability_1 = 0.0;       // 右边频率值
          for (int j = 0; j < 256; j++)
          {
            for (int i = 0; i < 256; i++)
            {
              if (i < j)// 前半部分
              {
                Probability_0 += probability[i];
                Mean_0_temp += i * probability[i];
              }
              else      // 后半部分
              {
                Probability_1 += probability[i];
                Mean_1_temp += i * probability[i];
              }
            }
            // 计算平均值
            // Mean_0_teamp计算的是前半部分的灰度值的总和除以总像素数,
            // 所以要除以前半部分的频率才是前半部分的平均值,后半部分同样
            Mean_0 = Mean_0_temp / Probability_0;
            Mean_1 = Mean_1_temp / Probability_1;
            Delta = (double)(Probability_0 * Probability_1 * pow((Mean_0 - Mean_1), 2));
            if (Delta > MaxDelta)
            {
              MaxDelta = Delta;
              Threshold = j;
            }
            // 相关参数归零
            Probability_0 = 0.0;
            Probability_1 = 0.0;
            Mean_0_temp = 0.0;
            Mean_1_temp = 0.0;
            Mean_0 = 0.0;
            Mean_1 = 0.0;
            Delta = 0.0;
          }
          return Threshold;
        }
        void main() {
          Mat image = imread("A1.bmp", 0);
          Mat image1, image2;
          Mat image3(image.size(), image.type());
          Mat image4(image.size(), image.type());
          std::cout << "基本全局阈值方法" << std::endl;
          int OstuThreshold1 = BasicGlobalThreshold(image, 0.01);
          int OstuThreshold2 = Otsu(image);
          std::cout << "Otsu方法" << std::endl;
          std::cout << OstuThreshold2 << std::endl;
          threshold(image, image1, OstuThreshold1, 255, THRESH_OTSU);
          threshold(image, image2, OstuThreshold2, 255, THRESH_OTSU);
          LaplacianSharpDeal(image2, image3);
          LaplacianSharpDeal(image, image4);
          imshow("原图像二值化", image);
          imshow("基本全局阈值方法", image1);
          imshow("Otsu方法", image2);
          imshow("先阈值分割后边缘检测", image3);
          imshow("直接对图像进行边缘检测", image4);
          waitKey();
        }

        image.gif

        七、实验结果

        (1)

        image.gif编辑

        (2)

        image.gif编辑

        在本图中,很明显先阈值分割后边缘检测的效果比直接进行边缘检测效果好,但阈值分割效果不是很明显,但仔细比较Otsu方法的分割要优于基本的全局阈值处理,采用基本的全局阈值处理得到的图像分割效果没有Otsu效果好,这是因为阈值不能通过迭代很好的确定导致的。本次实验中,学习到了阈值分割以及边缘检测的方法,对图像进行实践,能更好的学习应用当中。

        相关文章
        |
        6月前
        |
        算法 计算机视觉
        OpenCV(四十一):图像分割-分水岭法
        OpenCV(四十一):图像分割-分水岭法
        101 0
        |
        6月前
        |
        算法 计算机视觉
        OpenCV(四十):图像分割—漫水填充
        OpenCV(四十):图像分割—漫水填充
        169 0
        |
        5月前
        |
        机器学习/深度学习 算法 开发工具
        【四箭齐发】OpenCV实验大师工作流引擎SDK
        【四箭齐发】OpenCV实验大师工作流引擎SDK
        61 1
        【四箭齐发】OpenCV实验大师工作流引擎SDK
        |
        5月前
        |
        算法 开发工具 计算机视觉
        【零代码研发】OpenCV实验大师工作流引擎C++ SDK演示
        【零代码研发】OpenCV实验大师工作流引擎C++ SDK演示
        77 1
        |
        3月前
        |
        计算机视觉 C++
        基于VS2019和Opencv4,对hsv颜色空间的图像分割原理以及实现
        这篇文章介绍了基于HSV颜色空间的图像分割原理,包括HSV模型的基本概念和如何在OpenCV中通过设置HSV的色彩范围来实现图像中特定颜色的物体分割,并通过示例代码展示了在静态图像和视频流中进行颜色分割的方法。
        基于VS2019和Opencv4,对hsv颜色空间的图像分割原理以及实现
        |
        5月前
        |
        机器学习/深度学习 算法 Ubuntu
        十年OpenCV开发以后发布的作品 - OpenCV实验大师
        十年OpenCV开发以后发布的作品 - OpenCV实验大师
        50 2
        |
        缓存 API 计算机视觉
        OpenCV-实现天空变换(图像分割)
        OpenCV-实现天空变换(图像分割)
        226 0
        |
        6月前
        |
        算法 计算机视觉
        OpenCV4-图像分割-watershed(分水岭算法)
        1.分水岭概念 分水岭法是根据像素灰度值之间的差值寻找相同区域以实现分割的算法。我们可以将灰度值理解成像素的高度,这样一张图像可以看成崎岖不平的地面或者山区。向地面低洼的地方倾倒一定量的水,水将会掩盖低于某个高度的区域。
        134 0
        |
        6月前
        |
        算法 计算机视觉
        OpenCV图像处理-图像分割-MeanShift
        1. 基本概念 MeanShift严格说来并不是用来对图像进行分割的,而是在色彩层面的平滑滤波。它会中和色彩分布相近的颜色,平滑色彩细节,侵蚀掉面积较小的的颜色区域,它以图像上任意一点P为圆心,半径为sp,色彩幅值为sr进行不断地迭代。
        126 0
        |
        机器学习/深度学习 计算机视觉 Python
        【OpenCV图像处理14】图像分割与修复(上)
        【OpenCV图像处理14】图像分割与修复(上)
        106 0

        热门文章

        最新文章