云衣坊 發表於 2019-6-22 14:58:00

(三)OpenCV-Python学习—图像平滑

<p>  由于种种原因,图像中难免会存在噪声,需要对其去除。噪声可以理解为灰度值的随机变化,即拍照过程中引入的一些不想要的像素点。噪声可分为椒盐噪声,高斯噪声,加性噪声和乘性噪声等,参见:https://zhuanlan.zhihu.com/p/52889476</p>
<p>  噪声主要通过平滑进行抑制和去除,包括基于二维离散卷积的高斯平滑,均值平滑,基于统计学的中值平滑,以及能够保持图像边缘的双边滤波,导向滤波算法等。下面介绍其具体使用</p>
<p><span style="font-size: 18px"><strong>1. 二维离散卷积</strong></span></p>
<p>  理解卷积:https://www.zhihu.com/question/22298352/answer/637156871</p>
<p>       https://www.zhihu.com/question/22298352/answer/228543288</p>
<p>  学习图像平滑前,有必要了解下卷积的知识,看完上述连接,对于图像处理中卷积应该了解几个关键词:卷积核,锚点,步长,内积,卷积模式</p>
<p>    <strong>卷积核(kernel)</strong>:用来对图像矩阵进行平滑的矩阵,也称为过滤器(filter)</p>
<p>    <strong>锚点</strong>:卷积核和图像矩阵重叠,进行内积运算后,锚点位置的像素点会被计算值取代。一般选取奇数卷积核,其中心点作为锚点</p>
<p>    <strong>步长</strong>:卷积核沿着图像矩阵每次移动的长度</p>
<p>    <strong>内积</strong>:卷积核和图像矩阵对应像素点相乘,然后相加得到一个总和,如下图所示。(不要和矩阵乘法混淆)</p>
<p>        <img src="https://img2018.cnblogs.com/blog/1483773/201906/1483773-20190615122333697-651120309.png"></p>
<p>  </p>
<p>    <strong>卷积模式</strong>:卷积有三种模式,FULL, SAME,VALID,实际使用注意区分使用的那种模式。(参考:https://zhuanlan.zhihu.com/p/62760780)</p>
<p>      Full:全卷积,full模式的意思是,<strong>从filter和image刚相交开始做卷积,</strong>白色部分为填0,橙色部分为image, 蓝色部分为filter,filter的运动范围如图所示。</p>
<p>          <img src="https://img2018.cnblogs.com/blog/1483773/201906/1483773-20190615122700207-1234682017.png"></p>
<p>      Same卷积:<strong>当filter的锚点(K)与image的边角重合时,开始做卷积运算</strong>,可见filter的运动范围比full模式小了一圈,same mode为full mode 的子集,即full mode的卷积结果包括same mode。</p>
<p>          <img src="https://img2018.cnblogs.com/blog/1483773/201906/1483773-20190615122929602-1449760045.png"></p>
<p>      valid卷积:<strong>当filter全部在image里面的时候,进行卷积运算</strong>,可见filter的移动范围较same更小了,同样valid mode为same mode的子集。valid mode的卷积计算,填充边界中的像素值不会参与计算,即无效的填充边界不影响卷积,所以称为valid mode。</p>
<p>          <img src="https://img2018.cnblogs.com/blog/1483773/201906/1483773-20190615123549017-1545465812.png"></p>
<p>&nbsp;   python的scipy包中提供了convolve2d()函数来实现卷积运算,其参数如下:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 255, 1)">from</span><span style="color: rgba(0, 0, 0, 1)"> scipy import signal

signal.convolve2d(src,kernel,mode,boundary,fillvalue)
   
src: 输入的图像矩阵,只支持单通的(即二维矩阵)
kernel:卷积核
mode:卷积类型:full, same, valid
boundary:边界填充方式:fill,wrap, symm
fillvalue: 当boundary为fill时,边界填充的值,默认为0</span></pre>
</div>
<p>  opencv中提供了flip()函数翻转卷积核,filter2D进行same 卷积, 其参数如下:</p>
<div class="cnblogs_code">
<pre>   dst =<span style="color: rgba(0, 0, 0, 1)"> cv2.flip(src,flipCode)
      src: 输入矩阵
      flipCode:0表示沿着x轴翻转,1表示沿着y轴翻转,</span>-<span style="color: rgba(0, 0, 0, 1)">1表示分别沿着x轴,y轴翻转
      dst:输出矩阵(和src的shape一样)
   
    cv2.filter2D(src,dst,ddepth,kernel,anchor</span>=(-<span style="color: rgba(128, 0, 128, 1)">1</span>,-<span style="color: rgba(128, 0, 128, 1)">1</span>),delta=<span style="color: rgba(128, 0, 128, 1)">0</span>,borderType=<span style="color: rgba(0, 0, 0, 1)">cv2.BORDER_DEFAULT)
      src: 输入图像对象矩阵
      dst:输出图像矩阵
      ddepth:输出矩阵的数值类型
      kernel:卷积核
      anchor:卷积核锚点,默认(</span>-<span style="color: rgba(128, 0, 128, 1)">1</span>,-<span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">)表示卷积核的中心位置
      delat:卷积完后相加的常数
      borderType:填充边界类型</span></pre>
</div>
<p>&nbsp;</p>
<p><span style="font-size: 18px"><strong>2 图像平滑</strong></span></p>
<p>  <span style="font-size: 16px"><strong>2.1 高斯平滑</strong></span></p>
<p>    高斯平滑即采用高斯卷积核对图像矩阵进行卷积操作。高斯卷积核是一个近似服从高斯分布的矩阵,随着距离中心点的距离增加,其值变小。这样进行平滑处理时,图像矩阵中锚点处像素值权重大,边缘处像素值权重小,下为一个3*3的高斯卷积核:<img src="https://img2018.cnblogs.com/blog/1483773/201906/1483773-20190615191937329-2114108689.png"></p>
<p>    opencv中提供了GaussianBlur()函数来进行高斯平滑,其对应参数如下:</p>
<div class="cnblogs_code">
<pre>dst =<span style="color: rgba(0, 0, 0, 1)"> cv2.GaussianBlur(src,ksize,sigmaX,sigmay,borderType)
      src: 输入图像矩阵,可为单通道或多通道,多通道时分别对每个通道进行卷积
      dst:输出图像矩阵,大小和数据类型都与src相同
      ksize:高斯卷积核的大小,宽,高都为奇数,且可以不相同
      sigmaX: 一维水平方向高斯卷积核的标准差
      sigmaY: 一维垂直方向高斯卷积核的标准差,默认值为0,表示与sigmaX相同
      borderType:填充边界类型</span></pre>
</div>
<p>   代码使用示例和效果如下:(相比于原图,平滑后图片变模糊)</p>
<div class="cnblogs_code"><img src="http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif"><img alt="" id="code_img_opened_72b818cc-42af-415f-9fbc-1add522235a4" class="code_img_opened lazyload" style="display: none" data-src="http://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif">
<div id="cnblogs_code_open_72b818cc-42af-415f-9fbc-1add522235a4" class="cnblogs_code_hide">
<pre>#coding:utf-<span style="color: rgba(128, 0, 128, 1)">8</span><span style="color: rgba(0, 0, 0, 1)">

import cv2 </span><span style="color: rgba(0, 0, 255, 1)">as</span><span style="color: rgba(0, 0, 0, 1)"> cv
import matplotlib.pyplot </span><span style="color: rgba(0, 0, 255, 1)">as</span><span style="color: rgba(0, 0, 0, 1)"> plt
import numpy </span><span style="color: rgba(0, 0, 255, 1)">as</span><span style="color: rgba(0, 0, 0, 1)"> np


img </span>= cv.imread(r<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">C:\Users\Administrator\Desktop\timg.jpg</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
img_gauss </span>= cv.GaussianBlur(img,(<span style="color: rgba(128, 0, 128, 1)">3</span>,<span style="color: rgba(128, 0, 128, 1)">3</span>),<span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">)
cv.imshow(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">img</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,img)
cv.imshow(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">img_gauss</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,img_gauss)
cv.waitKey(</span><span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">)
cv.destroyAllWindows()</span></pre>
</div>
<span class="cnblogs_code_collapse">GaussianBlur()</span>  </div>
<p>&nbsp;<img alt="" style="display: block; margin-left: auto; margin-right: auto" data-src="https://img2018.cnblogs.com/blog/1483773/201906/1483773-20190615200146961-223945327.png"></p>
<p>   对于上面的高斯卷积核,可以由如下两个矩阵相乘进行构建,说明高斯核是<strong>可分离卷积核</strong>,因此高斯卷积操作可以分成先进行垂直方向的一维卷积,再进行一维水平方向卷积。</p>
<p style="text-align: center">          <img src="https://img2018.cnblogs.com/blog/1483773/201906/1483773-20190615200405240-1898675383.png"></p>
<p>&nbsp;  &nbsp; opencv中getGaussianKernel()能用来产生一维的高斯核,分别获得水平和垂直的高斯核,分两步也能完成高斯卷积,获得和<span style="color: rgba(0, 0, 0, 1)">GaussianBlur一样的结果。其参数如下:</span></p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">cv2.getGaussianKernel(ksize,sigma,ktype)
      ksize:奇数,一维核长度
      sigma:标准差
      ktype:数据格式,应该为CV_32F 或者 CV_64F<br><br>返回矩阵如下:垂直的矩阵<br>[[ 0.27406862]<br>&nbsp;[ 0.45186276]<br>&nbsp;[ 0.27406862]</span>   </pre>
</div>
<div class="cnblogs_code"><img src="http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif"><img alt="" id="code_img_opened_668ed193-365f-4640-990c-928aa210a340" class="code_img_opened lazyload" style="display: none" data-src="http://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif">
<div id="cnblogs_code_open_668ed193-365f-4640-990c-928aa210a340" class="cnblogs_code_hide">
<pre>#coding:utf-<span style="color: rgba(128, 0, 128, 1)">8</span><span style="color: rgba(0, 0, 0, 1)">

import cv2 </span><span style="color: rgba(0, 0, 255, 1)">as</span><span style="color: rgba(0, 0, 0, 1)"> cv
import matplotlib.pyplot </span><span style="color: rgba(0, 0, 255, 1)">as</span><span style="color: rgba(0, 0, 0, 1)"> plt
import numpy </span><span style="color: rgba(0, 0, 255, 1)">as</span><span style="color: rgba(0, 0, 0, 1)"> np
</span><span style="color: rgba(0, 0, 255, 1)">from</span><span style="color: rgba(0, 0, 0, 1)"> scipy import signal

#convolve2d只是对单通道进行卷积,若要实现cv.GaussianBlur()多通道高斯卷积,需要拆分三个通道进行,再合并

def gaussianBlur(img,h,w,sigma,boundary</span>=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">fill</span><span style="color: rgba(128, 0, 0, 1)">"</span>,fillvalue=<span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">):
    kernel_x </span>=<span style="color: rgba(0, 0, 0, 1)"> cv.getGaussianKernel(w,sigma,cv.CV_64F)   #默认得到的为垂直矩阵
   
    kernel_x </span>=<span style="color: rgba(0, 0, 0, 1)"> np.transpose(kernel_x)#转置操作,得到水平矩阵
   
    #水平方向卷积
    gaussian_x </span>= signal.convolve2d(img,kernel_x,mode=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">same</span><span style="color: rgba(128, 0, 0, 1)">"</span>,boundary=boundary,fillvalue=<span style="color: rgba(0, 0, 0, 1)">fillvalue)
   
    #垂直方向卷积
    kernel_y </span>=<span style="color: rgba(0, 0, 0, 1)"> cv.getGaussianKernel(h,sigma,cv.CV_64F)
    gaussian_xy </span>= signal.convolve2d(gaussian_x,kernel_y,mode=<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">same</span><span style="color: rgba(128, 0, 0, 1)">"</span>,boundary=boundary,fillvalue=<span style="color: rgba(0, 0, 0, 1)">fillvalue)
   
    #cv.CV_64F数据转换为uint8
    gaussian_xy </span>=<span style="color: rgba(0, 0, 0, 1)"> np.round(gaussian_xy)
    gaussian_xy </span>=<span style="color: rgba(0, 0, 0, 1)"> gaussian_xy.astype(np.uint8)
   
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> gaussian_xy

</span><span style="color: rgba(0, 0, 255, 1)">if</span> __name__==<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">__main__</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">:
    img </span>= cv.imread(r<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">C:\Users\Administrator\Desktop\timg.jpg</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">)
    img_gauss </span>= gaussianBlur(img,<span style="color: rgba(128, 0, 128, 1)">3</span>,<span style="color: rgba(128, 0, 128, 1)">3</span>,<span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">)
    cv.imshow(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">img</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,img)
    cv.imshow(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">img_gauss</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,img_gauss)
    cv.waitKey(</span><span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">)
    cv.destroyAllWindows()</span></pre>
</div>
<span class="cnblogs_code_collapse">先水平卷积,再垂直卷积</span></div>
<p>        <img alt="" data-src="https://img2018.cnblogs.com/blog/1483773/201906/1483773-20190615205925319-297926909.png"></p>
<p>   <strong><span style="font-size: 16px">2.2 均值平滑</span></strong></p>
<p>      高斯卷积核,对卷积框中像素值赋予不同权重,而均值平滑赋予相同权重,一个3*5的均值卷积核如下,均值卷积核也是可分离的。</p>
<p>                <img src="https://img2018.cnblogs.com/blog/1483773/201906/1483773-20190615211043999-1084591749.png"></p>
<p>    opencv的boxFilter()函数和blur()函数都能用来进行均值平滑,其参数如下:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">  cv2.boxFilter(src,ddepth,ksize,dst,anchor,normalize,borderType)
      src: 输入图像对象矩阵,
      ddepth:数据格式,位深度
      ksize:高斯卷积核的大小,格式为(宽,高)
      dst:输出图像矩阵,大小和数据类型都与src相同
      anchor:卷积核锚点,默认(</span>-<span style="color: rgba(128, 0, 128, 1)">1</span>,-<span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">)表示卷积核的中心位置
      normalize:是否归一化 (若卷积核3</span>*<span style="color: rgba(128, 0, 128, 1)">5</span><span style="color: rgba(0, 0, 0, 1)">,归一化卷积核需要除以15)
      borderType:填充边界类型
      
    cv2.blur(src,ksize,dst,anchor,borderType)
      src: 输入图像对象矩阵,可以为单通道或多通道
      ksize:高斯卷积核的大小,格式为(宽,高)
      dst:输出图像矩阵,大小和数据类型都与src相同
      anchor:卷积核锚点,默认(</span>-<span style="color: rgba(128, 0, 128, 1)">1</span>,-<span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">)表示卷积核的中心位置
      borderType:填充边界类型</span></pre>
</div>
<p>    示例代码和使用效果如下:</p>
<div class="cnblogs_code"><img src="http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif"><img alt="" id="code_img_opened_6887614b-82b6-4584-8e1d-efdee607bff6" class="code_img_opened lazyload" style="display: none" data-src="http://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif">
<div id="cnblogs_code_open_6887614b-82b6-4584-8e1d-efdee607bff6" class="cnblogs_code_hide">
<pre>#coding:utf-<span style="color: rgba(128, 0, 128, 1)">8</span><span style="color: rgba(0, 0, 0, 1)">

import cv2 </span><span style="color: rgba(0, 0, 255, 1)">as</span><span style="color: rgba(0, 0, 0, 1)"> cv
import matplotlib.pyplot </span><span style="color: rgba(0, 0, 255, 1)">as</span><span style="color: rgba(0, 0, 0, 1)"> plt
import numpy </span><span style="color: rgba(0, 0, 255, 1)">as</span><span style="color: rgba(0, 0, 0, 1)"> np

img </span>= cv.imread(r<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">C:\Users\Administrator\Desktop\timg.jpg</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
img_blur </span>= cv.blur(img,(<span style="color: rgba(128, 0, 128, 1)">3</span>,<span style="color: rgba(128, 0, 128, 1)">5</span><span style="color: rgba(0, 0, 0, 1)">))
# img_blur </span>= cv.boxFilter(img,-<span style="color: rgba(128, 0, 128, 1)">1</span>,(<span style="color: rgba(128, 0, 128, 1)">3</span>,<span style="color: rgba(128, 0, 128, 1)">5</span><span style="color: rgba(0, 0, 0, 1)">))
cv.imshow(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">img</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,img)
cv.imshow(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">img_blur</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,img_blur)
cv.waitKey(</span><span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">)
cv.destroyAllWindows()</span></pre>
</div>
<span class="cnblogs_code_collapse">blur()和boxFilter()</span></div>
<p><img alt="" style="display: block; margin-left: auto; margin-right: auto" data-src="https://img2018.cnblogs.com/blog/1483773/201906/1483773-20190615214642657-711288840.png"></p>
<p>  </p>
<p>   <span style="font-size: 16px"><strong>2.3 中值平滑</strong></span></p>
<p>      中值平滑也有核,但并不进行卷积计算,而是对核中所有像素值排序得到中间值,用该中间值来代替锚点值。opencv中利用medianBlur()来进行中值平滑,中值平滑特别适合用来去除椒盐噪声,其参数如下:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">    cv2.medianBlur(src,ksize,dst)
      src: 输入图像对象矩阵,可以为单通道或多通道
      ksize:核的大小,格式为 </span><span style="color: rgba(128, 0, 128, 1)">3</span>      #注意不是(<span style="color: rgba(128, 0, 128, 1)">3</span>,<span style="color: rgba(128, 0, 128, 1)">3</span><span style="color: rgba(0, 0, 0, 1)">)
      dst:输出图像矩阵,大小和数据类型都与src相同</span></pre>
</div>
<p>    其使用代码及效果如下:(加上的白点噪声都被平滑掉了)</p>
<div class="cnblogs_code"><img src="http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif"><img alt="" id="code_img_opened_669f3b99-2e6f-47bd-a358-0fd43d0b35fc" class="code_img_opened lazyload" style="display: none" data-src="http://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif">
<div id="cnblogs_code_open_669f3b99-2e6f-47bd-a358-0fd43d0b35fc" class="cnblogs_code_hide">
<pre>#coding:utf-<span style="color: rgba(128, 0, 128, 1)">8</span><span style="color: rgba(0, 0, 0, 1)">

import cv2 </span><span style="color: rgba(0, 0, 255, 1)">as</span><span style="color: rgba(0, 0, 0, 1)"> cv
import matplotlib.pyplot </span><span style="color: rgba(0, 0, 255, 1)">as</span><span style="color: rgba(0, 0, 0, 1)"> plt
import numpy </span><span style="color: rgba(0, 0, 255, 1)">as</span><span style="color: rgba(0, 0, 0, 1)"> np
import random

img </span>= cv.imread(r<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">C:\Users\Administrator\Desktop\timg.jpg</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
rows,cols </span>= img.shape[:<span style="color: rgba(128, 0, 128, 1)">2</span><span style="color: rgba(0, 0, 0, 1)">]

#加入椒盐噪声
</span><span style="color: rgba(0, 0, 255, 1)">for</span> i <span style="color: rgba(0, 0, 255, 1)">in</span> range(<span style="color: rgba(128, 0, 128, 1)">100</span><span style="color: rgba(0, 0, 0, 1)">):
    r </span>= random.randint(<span style="color: rgba(128, 0, 128, 1)">0</span>,rows-<span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">)
    c </span>= random.randint(<span style="color: rgba(128, 0, 128, 1)">0</span>,cols-<span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">)
    img</span>=<span style="color: rgba(128, 0, 128, 1)">255</span><span style="color: rgba(0, 0, 0, 1)">


img_medianblur </span>= cv.medianBlur(img,<span style="color: rgba(128, 0, 128, 1)">5</span><span style="color: rgba(0, 0, 0, 1)">)

cv.imshow(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">img</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,img)
cv.imshow(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">img_medianblur</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,img_medianblur)
cv.waitKey(</span><span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">)
cv.destroyAllWindows()</span></pre>
</div>
<span class="cnblogs_code_collapse">medianBlur()</span></div>
<p><img alt="" style="display: block; margin-left: auto; margin-right: auto" data-src="https://img2018.cnblogs.com/blog/1483773/201906/1483773-20190615220524952-2071217810.png"></p>
<p>&nbsp;中值滤波自己实现代码如下:</p>
<div class="cnblogs_code"><img src="http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif"><img alt="" id="code_img_opened_cf0502db-7e97-4851-9ed8-b525e3cbd3cc" class="code_img_opened lazyload" style="display: none" data-src="http://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif">
<div id="cnblogs_code_open_cf0502db-7e97-4851-9ed8-b525e3cbd3cc" class="cnblogs_code_hide">
<pre>#coding:utf-<span style="color: rgba(128, 0, 128, 1)">8</span><span style="color: rgba(0, 0, 0, 1)">

import heapq
import cv2

#实现图片的中值滤波算法
# 2D median filter with no stride, zero padding

def medain_filter(img, kernel_w, kernel_h):
    </span><span style="color: rgba(128, 0, 0, 1)">"""
</span><span style="color: rgba(0, 0, 0, 1)">    img: cv2 matrix
    kernel_w: kernel width
    kernel_h: kernel height
    </span><span style="color: rgba(128, 0, 0, 1)">"""
</span>    rows, cols = img.shape[:<span style="color: rgba(128, 0, 128, 1)">2</span><span style="color: rgba(0, 0, 0, 1)">]
    </span><span style="color: rgba(0, 0, 255, 1)">for</span> i <span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> range(rows):
      </span><span style="color: rgba(0, 0, 255, 1)">for</span> j <span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> range(cols):
            left </span>= max(<span style="color: rgba(128, 0, 128, 1)">0</span>, j-kernel_w<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">2)</span>
            right = min(cols-<span style="color: rgba(128, 0, 128, 1)">1</span>, j+kernel_w<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">2)</span>
            upper = max(<span style="color: rgba(128, 0, 128, 1)">0</span>, i-kernel_h<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">2)</span>
            lower = min(rows-<span style="color: rgba(128, 0, 128, 1)">1</span>, i+kernel_h<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">2)</span>
<span style="color: rgba(0, 0, 0, 1)">            
            #kernel中的像素点放入堆中
            hq </span>=<span style="color: rgba(0, 0, 0, 1)"> []
            </span><span style="color: rgba(0, 0, 255, 1)">for</span> m <span style="color: rgba(0, 0, 255, 1)">in</span> range(upper, lower+<span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">):
                </span><span style="color: rgba(0, 0, 255, 1)">for</span> n <span style="color: rgba(0, 0, 255, 1)">in</span> range(left, right+<span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">):
                  heapq.heappush(hq, img)
            size </span>= (right-left+<span style="color: rgba(128, 0, 128, 1)">1</span>)*(lower-upper+<span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">)
            </span><span style="color: rgba(0, 0, 255, 1)">if</span> size&amp;<span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">:#奇数个元素,取中间值
                </span><span style="color: rgba(0, 0, 255, 1)">for</span> k <span style="color: rgba(0, 0, 255, 1)">in</span> range(<span style="color: rgba(128, 0, 128, 1)">0</span>, (size+<span style="color: rgba(128, 0, 128, 1)">1</span>)<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">2):</span>
                  median =<span style="color: rgba(0, 0, 0, 1)"> heapq.heappop(hq)
                img </span>=<span style="color: rgba(0, 0, 0, 1)"> median
            </span><span style="color: rgba(0, 0, 255, 1)">else</span><span style="color: rgba(0, 0, 0, 1)">:#偶数个元素,取中间两个元素平均值
                </span><span style="color: rgba(0, 0, 255, 1)">for</span> k <span style="color: rgba(0, 0, 255, 1)">in</span> range(<span style="color: rgba(128, 0, 128, 1)">0</span>, (size+<span style="color: rgba(128, 0, 128, 1)">1</span>)<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">2):</span>
                  median1 =<span style="color: rgba(0, 0, 0, 1)"> heapq.heappop(hq)
                median2 </span>=<span style="color: rgba(0, 0, 0, 1)"> heapq.heappop(hq)
                img </span>= (median1+median2)<span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">2</span>
    <span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> img

</span><span style="color: rgba(0, 0, 255, 1)">if</span> __name__ == <span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">__main__</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">:
    img </span>= cv2.imread(r<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">C:\Users\Administrator\Desktop\dog.jpg</span><span style="color: rgba(128, 0, 0, 1)">"</span>, <span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">)
    img2 </span>= medain_filter(img, <span style="color: rgba(128, 0, 128, 1)">3</span>, <span style="color: rgba(128, 0, 128, 1)">3</span><span style="color: rgba(0, 0, 0, 1)">)
    cv2.imshow(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">img</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, img)
    cv2.imshow(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">img2</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">, img2)
    cv2.waitKey(</span><span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">)
    cv2.destroyAllWindows()
               
            </span></pre>
</div>
<span class="cnblogs_code_collapse">Medain Filter算法实现</span></div>
<p>&nbsp;</p>
<p>   <span style="font-size: 16px"><strong>2.4 双边滤波</strong></span></p>
<p>    双边滤波原理讲解:https://zhuanlan.zhihu.com/p/161665205, https://zhuanlan.zhihu.com/p/37404280  </p>
<p>    相比于上面几种平滑算法,双边滤波在平滑的同时还能保持图像中物体的轮廓信息。双边滤波在高斯平滑的基础上引入了灰度值相似性权重因子,所以在构建其卷积核核时,要同时考虑空间距离权重和灰度值相似性权重。在进行卷积时,每个位置的邻域内,根据和锚点的距离d构建距离权重模板,根据和锚点灰度值差异r构建灰度值权重模板,结合两个模板生成该位置的卷积核。opencv中的bilateralFilter()函数实现了双边滤波,其参数对应如下:</p>
<div class="cnblogs_code">
<pre>dst =<span style="color: rgba(0, 0, 0, 1)"> cv2.bilateralFilter(src,d,sigmaColor,sigmaSpace,borderType)
      src: 输入图像对象矩阵,可以为单通道或多通道
      d:用来计算卷积核的领域直径,如果d</span>&lt;=<span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">,从sigmaSpace计算d
      sigmaColor:颜色空间滤波器标准偏差值,决定多少差值之内的像素会被计算(构建灰度值模板)
      sigmaSpace:坐标空间中滤波器标准偏差值。如果d</span>&gt;<span style="color: rgba(128, 0, 128, 1)">0</span>,设置不起作用,否则根据它来计算d值(构建距离权重模板)</pre>
</div>
<p>    其使用代码及效果如下:</p>
<div class="cnblogs_code"><img alt="" id="code_img_closed_1ba75bbf-772a-4a28-b30a-e29a94b8ad01" class="code_img_closed lazyload" data-src="http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif"><img alt="" id="code_img_opened_1ba75bbf-772a-4a28-b30a-e29a94b8ad01" class="code_img_opened lazyload" style="display: none" data-src="http://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif">
<div id="cnblogs_code_open_1ba75bbf-772a-4a28-b30a-e29a94b8ad01" class="cnblogs_code_hide">
<pre>#coding:utf-<span style="color: rgba(128, 0, 128, 1)">8</span><span style="color: rgba(0, 0, 0, 1)">

import cv2 </span><span style="color: rgba(0, 0, 255, 1)">as</span><span style="color: rgba(0, 0, 0, 1)"> cv
import matplotlib.pyplot </span><span style="color: rgba(0, 0, 255, 1)">as</span><span style="color: rgba(0, 0, 0, 1)"> plt
import numpy </span><span style="color: rgba(0, 0, 255, 1)">as</span><span style="color: rgba(0, 0, 0, 1)"> np
import random
import math

img </span>= cv.imread(r<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">C:\Users\Administrator\Desktop\timg.jpg</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
img_bilateral </span>= cv.bilateralFilter(img,<span style="color: rgba(128, 0, 128, 1)">0</span>,<span style="color: rgba(128, 0, 128, 1)">0.2</span>,<span style="color: rgba(128, 0, 128, 1)">40</span><span style="color: rgba(0, 0, 0, 1)">)

cv.imshow(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">img</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,img)
cv.imshow(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">img_bilateral</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,img_bilateral)
cv.waitKey(</span><span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">)
cv.destroyAllWindows()</span></pre>
</div>
<span class="cnblogs_code_collapse">bilateralFilter</span></div>
<p><img alt="" style="display: block; margin-left: auto; margin-right: auto" data-src="https://img2018.cnblogs.com/blog/1483773/201906/1483773-20190618221929500-1684780629.png"></p>
<p>    同样,利用numpy也可以自己实现双边滤波算法,同样需要对每个通道进行双边滤波,最后进行合并,下面代码只对单通道进行了双边滤波,代码和效果如下图:</p>
<div class="cnblogs_code"><img src="http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif"><img alt="" id="code_img_opened_8bb05849-8f28-4fae-9cfa-3586a53b7cce" class="code_img_opened lazyload" style="display: none" data-src="http://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif">
<div id="cnblogs_code_open_8bb05849-8f28-4fae-9cfa-3586a53b7cce" class="cnblogs_code_hide">
<pre>#coding:utf-<span style="color: rgba(128, 0, 128, 1)">8</span><span style="color: rgba(0, 0, 0, 1)">

import cv2 </span><span style="color: rgba(0, 0, 255, 1)">as</span><span style="color: rgba(0, 0, 0, 1)"> cv
import matplotlib.pyplot </span><span style="color: rgba(0, 0, 255, 1)">as</span><span style="color: rgba(0, 0, 0, 1)"> plt
import numpy </span><span style="color: rgba(0, 0, 255, 1)">as</span><span style="color: rgba(0, 0, 0, 1)"> np
import random
import math


def getDistanceWeight(sigmaSpace,H,W):
    r,c </span>= np.mgrid[<span style="color: rgba(128, 0, 128, 1)">0</span>:H:<span style="color: rgba(128, 0, 128, 1)">1</span>,<span style="color: rgba(128, 0, 128, 1)">0</span>:W:<span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">]

    r </span>= r-(H-<span style="color: rgba(128, 0, 128, 1)">1</span>)/<span style="color: rgba(128, 0, 128, 1)">2</span><span style="color: rgba(0, 0, 0, 1)">
    c </span>=c-(W-<span style="color: rgba(128, 0, 128, 1)">1</span>)/<span style="color: rgba(128, 0, 128, 1)">2</span><span style="color: rgba(0, 0, 0, 1)">
    distanceWeight </span>= np.exp(-<span style="color: rgba(128, 0, 128, 1)">0.5</span>*(np.power(r,<span style="color: rgba(128, 0, 128, 1)">2</span>)+np.power(c,<span style="color: rgba(128, 0, 128, 1)">2</span>))/math.pow(sigmaSpace,<span style="color: rgba(128, 0, 128, 1)">2</span><span style="color: rgba(0, 0, 0, 1)">))
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> distanceWeight

def bilateralFilter(img,H,W,sigmaColor,sigmaSpace):
    distanceWeight </span>=<span style="color: rgba(0, 0, 0, 1)"> getDistanceWeight(sigmaSpace,H,W)
    cH </span>= (H-<span style="color: rgba(128, 0, 128, 1)">1</span>)/<span style="color: rgba(128, 0, 128, 1)">2</span><span style="color: rgba(0, 0, 0, 1)">
    cW </span>= (W-<span style="color: rgba(128, 0, 128, 1)">1</span>)/<span style="color: rgba(128, 0, 128, 1)">2</span><span style="color: rgba(0, 0, 0, 1)">
    rows,cols </span>= img.shape[:<span style="color: rgba(128, 0, 128, 1)">2</span><span style="color: rgba(0, 0, 0, 1)">]
    bilateralImg </span>=<span style="color: rgba(0, 0, 0, 1)"> np.zeros((rows,cols),np.float32)
    </span><span style="color: rgba(0, 0, 255, 1)">for</span> r <span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> range(rows):
      </span><span style="color: rgba(0, 0, 255, 1)">for</span> c <span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> range(cols):
            pixel </span>=<span style="color: rgba(0, 0, 0, 1)"> img
            rTop </span>= <span style="color: rgba(128, 0, 128, 1)">0</span> <span style="color: rgba(0, 0, 255, 1)">if</span> r-cH&lt;<span style="color: rgba(128, 0, 128, 1)">0</span> <span style="color: rgba(0, 0, 255, 1)">else</span> r-<span style="color: rgba(0, 0, 0, 1)">cH
            rBottom </span>= rows-<span style="color: rgba(128, 0, 128, 1)">1</span> <span style="color: rgba(0, 0, 255, 1)">if</span> r+cH&gt;rows-<span style="color: rgba(128, 0, 128, 1)">1</span> <span style="color: rgba(0, 0, 255, 1)">else</span> r+<span style="color: rgba(0, 0, 0, 1)">cH
            cLeft </span>= <span style="color: rgba(128, 0, 128, 1)">0</span> <span style="color: rgba(0, 0, 255, 1)">if</span> c-cW&lt;<span style="color: rgba(128, 0, 128, 1)">0</span> <span style="color: rgba(0, 0, 255, 1)">else</span> c-<span style="color: rgba(0, 0, 0, 1)">cW
            cRight </span>= cols-<span style="color: rgba(128, 0, 128, 1)">1</span> <span style="color: rgba(0, 0, 255, 1)">if</span> c+cW&gt;cols-<span style="color: rgba(128, 0, 128, 1)">1</span> <span style="color: rgba(0, 0, 255, 1)">else</span> c+<span style="color: rgba(0, 0, 0, 1)">cW
      
            #权重模板作用区域
            region</span>=img
            
            #灰度值差异权重
            colorWeight </span>= np.exp(<span style="color: rgba(128, 0, 128, 1)">0.5</span>*np.power(region-pixel,<span style="color: rgba(128, 0, 128, 1)">2.0</span>)/math.pow(sigmaColor,<span style="color: rgba(128, 0, 128, 1)">2</span><span style="color: rgba(0, 0, 0, 1)">))
            print(colorWeight.shape)
            #距离权重
            distanceWeightTemp </span>= distanceWeight
            print(distanceWeightTemp.shape)
            #权重相乘并归一化
            weightTemp </span>= colorWeight*<span style="color: rgba(0, 0, 0, 1)">distanceWeightTemp
            weightTemp </span>= weightTemp/<span style="color: rgba(0, 0, 0, 1)">np.sum(weightTemp)
            bilateralImg</span>=np.sum(region*<span style="color: rgba(0, 0, 0, 1)">weightTemp)
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> bilateralImg

</span><span style="color: rgba(0, 0, 255, 1)">if</span> __name__==<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">__main__</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">:
    img </span>= cv.imread(r<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">C:\Users\Administrator\Desktop\timg.jpg</span><span style="color: rgba(128, 0, 0, 1)">"</span>,<span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">)
    img_temp </span>= img/<span style="color: rgba(128, 0, 128, 1)">255.0</span><span style="color: rgba(0, 0, 0, 1)">
    img_bilateral </span>= bilateralFilter(img_temp,<span style="color: rgba(128, 0, 128, 1)">3</span>,<span style="color: rgba(128, 0, 128, 1)">3</span>,<span style="color: rgba(128, 0, 128, 1)">0.2</span>,<span style="color: rgba(128, 0, 128, 1)">19</span>)*<span style="color: rgba(128, 0, 128, 1)">255</span><span style="color: rgba(0, 0, 0, 1)">
    img_bilateral = <span style="color: rgba(128, 0, 128, 1)">255</span><span style="color: rgba(0, 0, 0, 1)">
    img_bilateral </span>=<span style="color: rgba(0, 0, 0, 1)"> img_bilateral.astype(np.uint8)
    cv.imshow(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">img</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,img)
    cv.imshow(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">img_bilateral</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,img_bilateral)
    cv.waitKey(</span><span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">)
    cv.destroyAllWindows()</span></pre>
</div>
<span class="cnblogs_code_collapse">python实现双边滤波</span></div>
<p><img alt="" style="display: block; margin-left: auto; margin-right: auto" data-src="https://img2018.cnblogs.com/blog/1483773/201906/1483773-20190622114728602-35968956.png"></p>
<p>&nbsp;</p>
<p>   <span style="font-size: 16px"><strong> 2.5 联合双边滤波</strong></span></p>
<p>      双边滤波是根据原图中不同位置灰度相似性来构建相似性权重模板,而联合滤波是先对原图进行高斯平滑,然后根据平滑后的图像灰度值差异建立相似性模板,再与距离权重模板相乘得到最终的卷积核,最后再对原图进行处理。所以相比于双边滤波,联合双边滤波只是建立灰度值相似性模板的方法不一样。 联合双边滤波原理讲解:https://blog.csdn.net/panda1234lee/article/details/52839205</p>
<p>      联合双边滤波作为边缘保留滤波算法时,进行joint的图片即为自身原图片,如果将joint换为其他引导图片,联合双边滤波算法还可以用来实现其他功能。opencv 2中不支持联合双边滤波,opencv 3中除了主模块,还引入了contrib,其中的ximgproc模块包括了联合双边滤波的算法。因此如果需要使用opencv的联合双边滤波,需要安装opencv-contrib-python包。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">安装opencv主模块和contrib附加模块步骤:
  pip uninstall opencv</span>-python (如果已经安装opencv-<span style="color: rgba(0, 0, 0, 1)">python包,先卸载)
  pip install opencv</span>-contrib-python</pre>
</div>
<p>    联合双边滤波: cv2.xmingproc.jointBilateralFilter(), 其相关参数如下:</p>
<div class="cnblogs_code">
<pre>dst =<span style="color: rgba(0, 0, 0, 1)"> cv2.xmingproc.jointBilateralFilter(joint,src,d,sigmaColor,sigmaSpace,borderType)
      joint: 进行联合滤波的导向图像,可以为单通道或多通道,保持边缘的滤波算法时常采用src
      src: 输入图像对象矩阵,可以为单通道或多通道
      d:用来计算卷积核的领域直径,如果d</span>&lt;<span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">,从sigmaSpace计算d
      sigmaColor:颜色空间滤波器标准偏差值,决定多少差值之内的像素会被计算(构建灰度值模板)
      sigmaSpace:坐标空间中滤波器标准偏差值。如果d</span>&gt;<span style="color: rgba(128, 0, 128, 1)">0</span>,设置不起作用,否则根据它来计算d值(构建距离权重模板)</pre>
</div>
<p>  下面是联合双边滤波的使用代码和效果:(采用src的高斯平滑图片作为joint)</p>
<div class="cnblogs_code"><img src="http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif"><img alt="" id="code_img_opened_d4bb3ac7-e8e0-45c2-8bda-762993b22e90" class="code_img_opened lazyload" style="display: none" data-src="http://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif">
<div id="cnblogs_code_open_d4bb3ac7-e8e0-45c2-8bda-762993b22e90" class="cnblogs_code_hide">
<pre>#coding:utf-<span style="color: rgba(128, 0, 128, 1)">8</span><span style="color: rgba(0, 0, 0, 1)">
import cv2 </span><span style="color: rgba(0, 0, 255, 1)">as</span><span style="color: rgba(0, 0, 0, 1)"> cv
import matplotlib.pyplot </span><span style="color: rgba(0, 0, 255, 1)">as</span><span style="color: rgba(0, 0, 0, 1)"> plt
import numpy </span><span style="color: rgba(0, 0, 255, 1)">as</span><span style="color: rgba(0, 0, 0, 1)"> np
import random
import math

src </span>= cv.imread(r<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">C:\Users\Administrator\Desktop\timg.jpg</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
joint</span>= cv.GaussianBlur(src,(<span style="color: rgba(128, 0, 128, 1)">7</span>,<span style="color: rgba(128, 0, 128, 1)">7</span>),<span style="color: rgba(128, 0, 128, 1)">1</span>,<span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">)
dst </span>= cv.ximgproc.jointBilateralFilter(joint,src,<span style="color: rgba(128, 0, 128, 1)">33</span>,<span style="color: rgba(128, 0, 128, 1)">2</span>,<span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">)
# dst </span>= cv.ximgproc.jointBilateralFilter(src,src,<span style="color: rgba(128, 0, 128, 1)">33</span>,<span style="color: rgba(128, 0, 128, 1)">2</span>,<span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">) #采用src作为joint

cv.imshow(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">img</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,src)
cv.imshow(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">joint</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,joint)
cv.imshow(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">dst</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,dst)
cv.waitKey(</span><span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">)
cv.destroyAllWindows()</span></pre>
</div>
<span class="cnblogs_code_collapse">cv2.ximgproc.jointBilateralFilter()</span></div>
<p><img alt="" data-src="https://img2018.cnblogs.com/blog/1483773/201906/1483773-20190622143230093-807432425.png"></p>
<p>&nbsp;   <span style="font-size: 16px"><strong> 2.6 导向滤波</strong></span></p>
<p>      导向滤波也是需要一张图片作为引导图片,来表明边缘,物体等信息,作为保持边缘滤波算法,可以采用自身作为导向图片。opencv 2中也暂不支持导向滤波, 同样在opencv-contrib-python包的ximgproc模块提供了导向滤波函。</p>
<p>      导向滤波具体原理可以参考:https://zhuanlan.zhihu.com/p/161666126</p>
<p>      opencv中导向滤波cv2.ximgproc.guidedFilter()的参数如下:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 0, 0, 1)">导向滤波
    cv2.ximgproc.guidedFilter(guide,src,radius,eps,dDepth)
      guide: 导向图片,单通道或三通道
      src: 输入图像对象矩阵,可以为单通道或多通道
      radius:用来计算卷积核的领域直径
      eps:规范化参数, eps的平方类似于双边滤波中的sigmaColor(颜色空间滤波器标准偏差值)
            (regularization term of Guided Filter. eps2 </span><span style="color: rgba(0, 0, 255, 1)">is</span> similar to the sigma <span style="color: rgba(0, 0, 255, 1)">in</span><span style="color: rgba(0, 0, 0, 1)"> the color space into bilateralFilter.)
      dDepth: 输出图片的数据深度</span></pre>
</div>
<p>      其代码使用和效果如下:</p>
<div class="cnblogs_code"><img src="http://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif"><img alt="" id="code_img_opened_15412e40-f82f-46cd-a8db-3add61c9182b" class="code_img_opened lazyload" style="display: none" data-src="http://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif">
<div id="cnblogs_code_open_15412e40-f82f-46cd-a8db-3add61c9182b" class="cnblogs_code_hide">
<pre>#coding:utf-<span style="color: rgba(128, 0, 128, 1)">8</span><span style="color: rgba(0, 0, 0, 1)">
import cv2 </span><span style="color: rgba(0, 0, 255, 1)">as</span><span style="color: rgba(0, 0, 0, 1)"> cv

src </span>= cv.imread(r<span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">C:\Users\Administrator\Desktop\timg.jpg</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">)
dst </span>= cv.ximgproc.guidedFilter(src,src,<span style="color: rgba(128, 0, 128, 1)">33</span>,<span style="color: rgba(128, 0, 128, 1)">2</span>,-<span style="color: rgba(128, 0, 128, 1)">1</span><span style="color: rgba(0, 0, 0, 1)">)
cv.imshow(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">img</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,src)
cv.imshow(</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(128, 0, 0, 1)">dst</span><span style="color: rgba(128, 0, 0, 1)">"</span><span style="color: rgba(0, 0, 0, 1)">,dst)
cv.waitKey(</span><span style="color: rgba(128, 0, 128, 1)">0</span><span style="color: rgba(0, 0, 0, 1)">)
cv.destroyAllWindows()</span></pre>
</div>
<span class="cnblogs_code_collapse">cv2.ximgproc.guidedFilter</span></div>
<p><img alt="" style="display: block; margin-left: auto; margin-right: auto" data-src="https://img2018.cnblogs.com/blog/1483773/201906/1483773-20190622145422449-1273655096.png"></p>
<p>&nbsp;</p>
<p><span style="color: rgba(0, 0, 0, 1)">  </span></p><br><br>
来源:https://www.cnblogs.com/silence-cho/p/11027218.html
頁: [1]
查看完整版本: (三)OpenCV-Python学习—图像平滑