阅读 117

openCV实现图像分割

这篇文章主要为大家详细介绍了openCV实现图像分割,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

本次实验为大家分享了openCV实现图像分割的具体实现代码,供大家参考,具体内容如下

一.实验目的

进一步理解图像的阈值分割方法和边缘检测方法的原理。
掌握图像基本全局阈值方法和最大类间方差法(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函数)。比较先阈值分割后边缘检测和直接对图像进行边缘检测这两种情况的结果是否有差别。
注意:这里提取灰度边缘即可。

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
#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();
}

以上就是本文的全部内容,希望对大家的学习有所帮助

服务器评测 http://www.cncsto.com/ 

服务器测评 http://www.cncsto.com/ 

站长资源 https://www.cscnn.com/ 

小鱼创业 https://www.237fa.com/ 



文章分类
后端
文章标签
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐