-
Notifications
You must be signed in to change notification settings - Fork 241
/
Copy pathOpenCV图像处理篇之图像平滑.html
282 lines (254 loc) · 15.4 KB
/
OpenCV图像处理篇之图像平滑.html
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
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="Content-Style-Type" content="text/css" />
<meta name="generator" content="pandoc" />
<title></title>
<style type="text/css">code{white-space: pre;}</style>
<style type="text/css">
table.sourceCode, tr.sourceCode, td.lineNumbers, td.sourceCode {
margin: 0; padding: 0; vertical-align: baseline; border: none; }
table.sourceCode { width: 100%; line-height: 100%; }
td.lineNumbers { text-align: right; padding-right: 4px; padding-left: 4px; color: #aaaaaa; border-right: 1px solid #aaaaaa; }
td.sourceCode { padding-left: 5px; }
code > span.kw { color: #007020; font-weight: bold; }
code > span.dt { color: #902000; }
code > span.dv { color: #40a070; }
code > span.bn { color: #40a070; }
code > span.fl { color: #40a070; }
code > span.ch { color: #4070a0; }
code > span.st { color: #4070a0; }
code > span.co { color: #60a0b0; font-style: italic; }
code > span.ot { color: #007020; }
code > span.al { color: #ff0000; font-weight: bold; }
code > span.fu { color: #06287e; }
code > span.er { color: #ff0000; font-weight: bold; }
</style>
<link rel="stylesheet" href="../stylesheets/Github.css" type="text/css" />
<title>OpenCV图像处理篇之图像平滑</title>
</head>
<body>
<div id="header"><center>
<p class="header_titleline">
<a href="../index.html" target="_self" title="主页">主页 </a><a href="../Search.html" target="_self" title="站内搜索">站内搜索 </a><a href="../Projects.html" target="_self" title="项目研究">项目研究 </a><a href="../Archives.html" target="_self" title="文章存档">文章存档 </a><a href="../README.html" target="_self" title="分类目录">分类目录 </a><a href="../AboutMe.html" target="_self" title="关于我">关于我 </a>
</p>
</center></div>
<h1>OpenCV图像处理篇之图像平滑</h1>
<h4>2014-09-18 / xiahouzuoxin</h4>
<h4>Tags: OpenCV</h4>
转载请注明出处: <a href="http://xiahouzuoxin.github.io/notes/">http://xiahouzuoxin.github.io/notes/</a>
<div id="TOC">
<ul>
<li><a href="#图像平滑算法">图像平滑算法</a></li>
<li><a href="#程序分析及结果">程序分析及结果</a></li>
</ul>
</div>
<!---title:OpenCV图像处理篇之图像平滑-->
<!---keywords:OpenCV-->
<!---date:2014-09-18-->
<h2 id="图像平滑算法">图像平滑算法</h2>
<p>图像平滑与图像模糊是同一概念,主要用于图像的去噪。平滑要使用滤波器,为不改变图像的相位信息,一般使用线性滤波器,其统一形式如下:</p>
<p><img src="https://latex.codecogs.com/png.latex? \Large g(i,j)=\sum_{k,l}f(i+k,j+l)h(k,l)"></p>
<p>其中h称为滤波器的核函数,说白了就是权值。不同的核函数代表不同的滤波器,有不同的用途。</p>
<p>在图像处理中,常见的滤波器包括:</p>
<ol style="list-style-type: decimal">
<li><p>归一化滤波器(Homogeneous blur)</p>
<p>也是__均值滤波器__,用输出像素点核窗口内的像素均值代替输出点像素值。</p></li>
<li><p>高斯滤波器(Guassian blur)</p>
<p>是实际中最常用的滤波器,高斯滤波是将输入数组的每一个像素点与 高斯内核 卷积将卷积和当作输出像素值。高斯核相当于对输出像素的邻域赋予不同的权值,输出像素点所在位置的权值最大(对应高斯函数的均值位置)。二维高斯函数为,</p>
<p><img src="https://latex.codecogs.com/png.latex? \Large G(x,y) = Ae^{\frac{-(x-u_x)^2}{2\delta_x^2}+\frac{-(y-y_x)^2}{2\delta_y^2}"></p></li>
<li><p>中值滤波器(median blur)</p>
<p>中值滤波将图像的每个像素用邻域(以当前像素为中心的正方形区域)像素的中值代替。对椒盐噪声最有效的滤波器,去除跳变点非常有效。</p></li>
<li><p>双边滤波器(Bilatrial blur)</p>
<p>为避免滤波器平滑图像去噪的同时使边缘也模糊,这种情况下使用双边滤波器。关于双边滤波器的解释参见<a href="http://homepages.inf.ed.ac.uk/rbf/CVonline/LOCAL_COPIES/MANDUCHI1/Bilateral_Filtering.html" class="uri">http://homepages.inf.ed.ac.uk/rbf/CVonline/LOCAL_COPIES/MANDUCHI1/Bilateral_Filtering.html</a></p></li>
</ol>
<p>下面的程序将先给标准Lena图像添加椒盐噪声,分别使用4种不同的滤波器进行平滑操作,请注意观察不同滤波器对椒盐噪声的去噪效果!</p>
<h2 id="程序分析及结果">程序分析及结果</h2>
<pre class="sourceCode c"><code class="sourceCode c"><span class="co">/*</span>
<span class="co"> * FileName : image_smoothing.cpp</span>
<span class="co"> * Author : xiahouzuoxin @163.com</span>
<span class="co"> * Version : v1.0</span>
<span class="co"> * Date : Wed 17 Sep 2014 08:30:25 PM CST</span>
<span class="co"> * Brief : </span>
<span class="co"> * </span>
<span class="co"> * Copyright (C) MICL,USTB</span>
<span class="co"> */</span>
<span class="ot">#include "cv.h"</span>
<span class="ot">#include "imgproc/imgproc.hpp"</span>
<span class="ot">#include "highgui/highgui.hpp"</span>
using namespace std;
using namespace cv;
<span class="dt">const</span> <span class="dt">int</span> MAX_KERNEL_LENGTH = <span class="dv">10</span>;
<span class="dt">const</span> <span class="dt">char</span> *wn_name = <span class="st">"Smoothing"</span>;
<span class="dt">static</span> <span class="dt">void</span> salt(Mat &I, <span class="dt">int</span> n);
<span class="dt">static</span> <span class="dt">void</span> disp_caption(<span class="dt">const</span> <span class="dt">char</span> *wn_name, Mat src, <span class="dt">const</span> <span class="dt">char</span> *caption);
<span class="dt">static</span> <span class="dt">void</span> disp_image(<span class="dt">const</span> <span class="dt">char</span> *wn_name, Mat I);
<span class="co">/*</span>
<span class="co"> * @brief </span>
<span class="co"> * @inputs </span>
<span class="co"> * @outputs </span>
<span class="co"> * @retval </span>
<span class="co"> */</span>
<span class="dt">int</span> main(<span class="dt">int</span> argc, <span class="dt">char</span> *argv[])
{
<span class="kw">if</span> (argc<<span class="dv">2</span>) {
cout<<<span class="st">"Usage: ./image_smoothing [file name]"</span><<endl;
<span class="kw">return</span> -<span class="dv">1</span>;
}
Mat I = imread(argv[<span class="dv">1</span>], CV_LOAD_IMAGE_GRAYSCALE);
salt(I, <span class="dv">6000</span>);
imshow(wn_name, I);
waitKey(<span class="dv">0</span>);
Mat dst; <span class="co">// Result</span>
<span class="co">/* Homogeneous blur */</span>
disp_caption(wn_name, I, <span class="st">"Homogeneous blur"</span>);
<span class="kw">for</span> (<span class="dt">int</span> i=<span class="dv">1</span>; i<MAX_KERNEL_LENGTH; i+=<span class="dv">2</span>) {
blur(I, dst, Size(i, i), Point(-<span class="dv">1</span>,-<span class="dv">1</span>));
disp_image(wn_name, dst);
}
<span class="co">/* Guassian blur */</span>
disp_caption(wn_name, I, <span class="st">"Gaussian blur"</span>);
<span class="kw">for</span> (<span class="dt">int</span> i=<span class="dv">1</span>; i<MAX_KERNEL_LENGTH; i+=<span class="dv">2</span>) {
GaussianBlur(I, dst, Size(i, i), <span class="dv">0</span>, <span class="dv">0</span>);
disp_image(wn_name, dst);
}
<span class="co">/* Median blur */</span>
disp_caption(wn_name, I, <span class="st">"Median blur"</span>);
<span class="kw">for</span> (<span class="dt">int</span> i=<span class="dv">1</span>; i<MAX_KERNEL_LENGTH; i+=<span class="dv">2</span>) {
medianBlur(I, dst, i);
disp_image(wn_name, dst);
}
<span class="co">/* Bilatrial blur */</span>
disp_caption(wn_name, I, <span class="st">"Bilatrial blur"</span>);
<span class="kw">for</span> (<span class="dt">int</span> i=<span class="dv">1</span>; i<MAX_KERNEL_LENGTH; i+=<span class="dv">2</span>) {
bilateralFilter(I, dst, i, i*<span class="dv">2</span>, i/<span class="dv">2</span>);
disp_image(wn_name, dst);
}
waitKey(<span class="dv">0</span>);
<span class="kw">return</span> <span class="dv">0</span>;
}
<span class="co">/*</span>
<span class="co"> * @brief 显示提示文字(滤波方法)</span>
<span class="co"> * @inputs </span>
<span class="co"> * @outputs </span>
<span class="co"> * @retval </span>
<span class="co"> */</span>
<span class="dt">static</span> <span class="dt">void</span> disp_caption(<span class="dt">const</span> <span class="dt">char</span> *wn_name, Mat src, <span class="dt">const</span> <span class="dt">char</span> *caption)
{
Mat dst = Mat::zeros(src.size(), src.type());
putText(dst, caption, Point(src.cols/<span class="dv">4</span>, src.rows/<span class="dv">2</span>), CV_FONT_HERSHEY_COMPLEX, <span class="dv">1</span>, Scalar(<span class="dv">255</span>,<span class="dv">255</span>,<span class="dv">255</span>));
imshow(wn_name, dst);
waitKey(<span class="dv">0</span>);
}
<span class="co">/*</span>
<span class="co"> * @brief 显示图像</span>
<span class="co"> * @inputs </span>
<span class="co"> * @outputs </span>
<span class="co"> * @retval </span>
<span class="co"> */</span>
<span class="dt">static</span> <span class="dt">void</span> disp_image(<span class="dt">const</span> <span class="dt">char</span> *wn_name, Mat I)
{
imshow(wn_name, I);
waitKey(<span class="dv">1000</span>);
}
<span class="co">/*</span>
<span class="co"> * @brief 添加椒盐噪声</span>
<span class="co"> * @inputs </span>
<span class="co"> * @outputs </span>
<span class="co"> * @retval </span>
<span class="co"> */</span>
<span class="dt">static</span> <span class="dt">void</span> salt(Mat &I, <span class="dt">int</span> n=<span class="dv">3000</span>)
{
<span class="kw">for</span> (<span class="dt">int</span> k=<span class="dv">0</span>; k<n; k++) {
<span class="dt">int</span> i = rand() % I.cols;
<span class="dt">int</span> j = rand() % I.rows;
<span class="kw">if</span> (I.channels()) {
I.at<uchar>(j,i) = <span class="dv">255</span>;
} <span class="kw">else</span> {
I.at<Vec3b>(j,i)[<span class="dv">0</span>] = <span class="dv">255</span>;
I.at<Vec3b>(j,i)[<span class="dv">1</span>] = <span class="dv">255</span>;
I.at<Vec3b>(j,i)[<span class="dv">2</span>] = <span class="dv">255</span>;
}
}
}</code></pre>
<p>上面程序的逻辑非常清晰:</p>
<ol style="list-style-type: decimal">
<li><p>读入灰度图,并添加椒盐噪声(6000个噪声点):</p>
<pre class="sourceCode c"><code class="sourceCode c">Mat I = imread(argv[<span class="dv">1</span>], CV_LOAD_IMAGE_GRAYSCALE);
salt(I, <span class="dv">6000</span>);</code></pre>
<div class="figure">
<img src="../images/OpenCV图像处理篇之图像平滑/LenaNoise.PNG" alt="LenaNoise" /><p class="caption">LenaNoise</p>
</div></li>
<li><p><code>disp_caption</code>和<code>disp_image</code>函数分别是用于显示提示文字和平滑过程中的变化图像的,平滑过程中图像的变化如下图:</p>
<div class="figure">
<img src="../images/OpenCV图像处理篇之图像平滑/blur.gif" alt="blur" /><p class="caption">blur</p>
</div>
<p>注意观察上面的图,中值滤波(Median Blur)对椒盐噪声的效果最好!</p></li>
<li><p>四种滤波方法分别使用到4个OpenCV函数,这些函数的声明都在<code>imgproc.hpp</code>中,这些函数的前2个参数都是原图像和滤波后图像。</p>
<p>归一化滤波器<code>blur</code>的第3个参数为滤波核窗口的大小,Size(i,i)表示ixi大小的窗口。</p>
<p>高斯滤波器<code>GaussianBlur</code>第3个参数也是滤波核窗口的大小,第4、第5个参数分辨表示x方向和y方向的δ。</p>
<p>中值滤波器<code>medianBlur</code>第3个参数是滤波器的长度,该滤波器的窗口为正方形。</p>
<p>双边滤波器的函数原型如下:</p>
<pre><code>//! smooths the image using bilateral filter
CV_EXPORTS_W void bilateralFilter( InputArray src, OutputArray dst, int d,
double sigmaColor, double sigmaSpace,
int borderType=BORDER_DEFAULT );</code></pre></li>
<li><p>本程序使用的Makefile文件为:</p>
<pre><code>TARG=image_smoothing
SRC=image_smoothing.cpp
LIB=-L/usr/local/lib/
INC=-I/usr/local/include/opencv/ -I/usr/local/include/opencv2
CFLAGS=
$(TARG):$(SRC)
g++ -g -o $@ ${CFLAGS} $(LIB) $(INC) \
-lopencv_core -lopencv_highgui -lopencv_imgproc \
$^
.PHONY:clean
clean:
-rm $(TARG) tags -f </code></pre></li>
</ol>
<div class="ds-thread" data-thread-key="OpenCV图像处理篇之图像平滑" data-title="OpenCV图像处理篇之图像平滑" data-url="xiahouzuoxin.github.io/notes/html/OpenCV图像处理篇之图像平滑.html"></div>
<script>window._bd_share_config={"common":{"bdSnsKey":{},"bdText":"","bdMini":"2","bdMiniList":false,"bdPic":"","bdStyle":"0","bdSize":"16"},"slide":{"type":"slide","bdImg":"5","bdPos":"right","bdTop":"300"},"image":{"viewList":["qzone","tsina","tqq","renren","weixin"],"viewText":"分享到:","viewSize":"16"},"selectShare":{"bdContainerClass":null,"bdSelectMiniList":["qzone","tsina","tqq","renren","weixin"]}};with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='http://bdimg.share.baidu.com/static/api/js/share.js?v=89860593.js?cdnversion='+~(-new Date()/36e5)];</script>
<!-- 多说公共JS代码 start (一个网页只需插入一次) -->
<script type="text/javascript">
var duoshuoQuery = {short_name:"xiahouzuoxin"};
(function() {
var ds = document.createElement('script');
ds.type = 'text/javascript';ds.async = true;
ds.src = (document.location.protocol == 'https:' ? 'https:' : 'http:') + '//static.duoshuo.com/embed.js';
ds.charset = 'UTF-8';
(document.getElementsByTagName('head')[0]
|| document.getElementsByTagName('body')[0]).appendChild(ds);
})();
</script>
<!-- 多说公共JS代码 end -->
<div id="footer">
<p class="footer_subline">联系邮箱: [email protected]</p>
<p class="footer_subline">声明: 本站所有文章如非特别说明均为原创,转载请注明出处!
<script type="text/javascript">var cnzz_protocol = (("https:" == document.location.protocol) ? " https://" : " http://");document.write(unescape("%3Cspan id='cnzz_stat_icon_1253219218'%3E%3C/span%3E%3Cscript src='" + cnzz_protocol + "s4.cnzz.com/z_stat.php%3Fid%3D1253219218%26show%3Dpic' type='text/javascript'%3E%3C/script%3E"));</script>
</p>
</div>
<!-- 回到顶部 -->
<script>
lastScrollY=0;
function heartBeat(){
var diffY;
if (document.documentElement && document.documentElement.scrollTop)
diffY = document.documentElement.scrollTop;
else if (document.body)
diffY = document.body.scrollTop
else
{/*Netscape stuff*/}
percent=.1*(diffY-lastScrollY);
if(percent>0)percent=Math.ceil(percent);
else percent=Math.floor(percent);
document.getElementById("full").style.top=parseInt(document.getElementById("full").style.top)+percent+"px";
lastScrollY=lastScrollY+percent;
}
suspendcode="<div id=\"full\" style='right:1px;POSITION:absolute;TOP:600px;z-index:100'><a onclick='window.scrollTo(0,0);'><img src='../images/top.png'></a><br></div>"
document.write(suspendcode);
window.setInterval("heartBeat()",1);
</script>
</body>
</html>