广告位联系
返回顶部
分享到

openCV实现图像分割的方法

C语言 来源:转载 作者:秩名 发布时间:2021-09-05 20:21:51 人浏览
摘要

一.实验目的 进一步理解图像的阈值分割方法和边缘检测方法的原理。 掌握图像基本全局阈值方法和最大类间方差法(otsu法)的原理并编程实现。 编程实现图像的边缘检测。 二.实验内容和要求 编程实现图像阈值分割(基本全局阈值方法和otsu法)和边缘检测。 三.

一.实验目的

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

二.实验内容和要求

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

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

计算机,VS2017+OpenCV

四.实验原理与方法

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

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

thr表示选取的阈值。二值化的过程就是当原图的像素灰度值大于阈值就将其变白,否则就将其变黑。即将256个亮度等级的灰度图像通过适当的阀值选取而将图像变为二个级别灰度级,这样只有二个灰度级的图像在图像处理分析过程中占有非常重要的地位,特别是在实用的图像处理中。
根据对全图使用统一阈值还是对不同区域使用不同阈值,可以分为全局阈值方法(global thresholding)和局部阈值方法(local thresholding,也叫做自适应阈值方法adaptive thresholding);这种与坐标相关的阈值也叫动态阈值,具体的方法,可以参考相关的图像处理书籍。

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

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

2、Otsu方法的算法步骤为:

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

边缘检测

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

五.实验内容

1、图像的阈值分割:

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

2、边缘检测

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

代码:

#include "pch.h"
#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, CV_THRESH_OTSU);
 threshold(image, image2, OstuThreshold2, 255, CV_THRESH_OTSU);

 LaplacianSharpDeal(image2, image3);
 LaplacianSharpDeal(image, image4);
 
 imshow("基本全局阈值方法", image1);
 imshow("Otsu方法", image2);
 imshow("先阈值分割后边缘检测", image3);
 imshow("直接对图像进行边缘检测", image4);
 waitKey();
}


版权声明 : 本文内容来源于互联网或用户自行发布贡献,该文观点仅代表原作者本人。本站仅提供信息存储空间服务和不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权, 违法违规的内容, 请发送邮件至2530232025#qq.cn(#换@)举报,一经查实,本站将立刻删除。
原文链接 : https://blog.csdn.net/weixin_43601554/article/details/106745126
相关文章
  • C++中类的六大默认成员函数的介绍

    C++中类的六大默认成员函数的介绍
    一、类的默认成员函数 二、构造函数Date(形参列表) 构造函数主要完成初始化对象,相当于C语言阶段写的Init函数。 默认构造函数:无参的构
  • C/C++实现遍历文件夹最全方法总结介绍

    C/C++实现遍历文件夹最全方法总结介绍
    一、filesystem(推荐) 在c++17中,引入了文件系统,使用起来非常方便 在VS中,可以直接在项目属性中调整: 只要是C++17即以上都可 然后头文件
  • C语言实现手写Map(数组+链表+红黑树)的代码

    C语言实现手写Map(数组+链表+红黑树)的代码
    要求 需要准备数组集合(List) 数据结构 需要准备单向链表(Linked) 数据结构 需要准备红黑树(Rbtree)数据结构 需要准备红黑树和链表适配策略
  • MySQL系列教程之使用C语言来连接数据库

    MySQL系列教程之使用C语言来连接数据库
    写在前面 知道了 Java中使用 JDBC编程 来连接数据库了,但是使用 C语言 来连接数据库却总是连接不上去~ 立即安排一波使用 C语言连接 MySQL数
  • 基于C语言实现简单学生成绩管理系统

    基于C语言实现简单学生成绩管理系统
    一、系统主要功能 1、密码登录 2、输入数据 3、查询成绩 4、修改成绩 5、输出所有学生成绩 6、退出系统 二、代码实现 1 2 3 4 5 6 7 8 9 10 11
  • C语言实现共享单车管理系统

    C语言实现共享单车管理系统
    1.功能模块图; 2.各个模块详细的功能描述。 1.登陆:登陆分为用户登陆,管理员登陆以及维修员登录,登陆后不同的用户所执行的操作
  • C++继承与菱形继承的介绍

    C++继承与菱形继承的介绍
    继承的概念和定义 继承机制是面向对象程序设计的一种实现代码复用的重要手段,它允许程序员在保持原有类特性的基础上进行拓展,增加
  • C/C++指针介绍与使用介绍

    C/C++指针介绍与使用介绍
    什么是指针 C/C++语言拥有在程序运行时获得变量的地址和操作地址的能力,这种用来操作地址的特殊类型变量被称作指针。 翻译翻译什么
  • C++进程的创建和进程ID标识介绍
    进程的ID 进程的ID,可称为PID。它是进程的唯一标识,类似于我们的身份证号是唯一标识,因为名字可能会和其他人相同,生日可能会与其他
  • C++分析如何用虚析构与纯虚析构处理内存泄漏

    C++分析如何用虚析构与纯虚析构处理内存泄漏
    一、问题引入 使用多态时,如果有一些子类的成员开辟在堆区,那么在父类执行完毕释放后,没有办法去释放子类的内存,这样会导致内存
  • 本站所有内容来源于互联网或用户自行发布,本站仅提供信息存储空间服务,不拥有版权,不承担法律责任。如有侵犯您的权益,请您联系站长处理!
  • Copyright © 2017-2022 F11.CN All Rights Reserved. F11站长开发者网 版权所有 | 苏ICP备2022031554号-1 | 51LA统计