OpenCV3計算機視覺Python語言實現筆記(三)

1、使用OpenCV處理圖像數組

1.不一樣顏色空間的轉換app

  OpenCV中有數百種關於在不一樣色彩空間之間轉換的方法。當前,在計算機視覺中有三種經常使用的色彩空間:灰度、BGR以及HSV(Hue, Saturation, Value)函數

  灰度色彩空間是經過去除彩色信息來將其轉換爲灰階,灰度色彩空間對中間處理特別有效,好比人臉檢測。性能

  BGR,即藍-綠-紅色彩空間,每個像素點都由一個三元數組來表示,分別表明藍、綠、紅三種顏色。spa

  HSV,H(Hue)是色度,S(Saturation)是飽和度,V(value)表示黑暗的程度(或光譜另外一端的明亮程度)。code

  BGR的簡短說明:當第一次處理BGR色彩空間時,能夠不要其中的一個色彩份量,好比像素值[0, 255, 255](沒有藍色,綠色份量取最大值,紅色份量取最大值)表示黃色。視頻

2. 傅里葉變換blog

  NumPy有快速傅里葉變換(FFT)的包,它包含了fft2()函數,該函數能夠計算一幅圖像的離散傅里葉變換(DFT)。圖片

  下面經過傅里葉變換來介紹圖像的幅度譜。圖像的幅度譜是另外一種圖像,幅度譜圖像呈現了原始圖像在變換方面的一種表示:把一幅圖像中最明亮的像素放到圖像中央,而後逐漸變暗,在邊緣上的像素最暗。這樣能夠發現圖像中有多少亮的像素和暗的像素,以及它們分佈的百分比。傅里葉變換的概念是邊緣檢測或線段和形狀檢測等圖像處理操做的基礎。ip

2.1 高通濾波器

  高通濾波器(HPF)是檢測圖像的某個區域,而後根據像素與周圍像素的亮度差值來提高(boost)該像素的亮度的濾波器。

  核是指一組權重的集合,它會應用在源圖像的一個區域,並由今生成目標圖像的一個像素。好比,大小爲7的核意味着每49(7 x 7)個源圖像的像素會產生目標圖像的一個像素。可把核看做一塊覆蓋在源圖像上可移動的毛玻璃片,玻璃片覆蓋區域的光線會按某種方式進行擴散混合後透過去。以以下的核(kernal)爲例:

[[0, -0.25, 0],

 [-0.25, 1, -0.25],

 [0, -0.25, 0]]

  在計算完中央像素與周圍鄰近像素的亮度差值之和之後,若是亮度變化很大,中央像素的亮度會增長(反之則不會)。換句話說,若是一個像素比它周圍的像素更突出,就會提高它的亮度。這在邊緣檢測上尤爲有效,它會採用一種稱爲高頻提高濾波器(high boost filter)的高通濾波器。

  高通和低通濾波器都有一個稱爲半徑(radius)的屬性,它決定了多大面積的鄰近像素參與濾波計算。下面是一個高通濾波器的例子。

import cv2
import numpy as np
from scipy import ndimage
kernal_3x3 = np.array([[-1, -1, -1],
[-1, 8, -1],
[-1, -1, -1]])
kernal_5x5 = np.array([[-1, -1, -1, -1, -1],
[-1, 1, 2, 1, -1],
[-1, 2, 4, 2, -1],
[-1, 1, 2, 1, -1],
[-1, -1, -1, -1,-1]])
# 使用函數cv2.imread() 讀入圖像。這幅圖像應該在此程序的工做路徑,或者給函數提供完整路徑,第二個參數是要告訴函數應該如何讀取這幅圖片。

#    • cv2.IMREAD_COLOR:讀入一副彩色圖像。圖像的透明度會被忽略,這是默認參數。 

  #    • cv2.IMREAD_GRAYSCALE:以灰度模式讀入圖像

img = cv2.imread('LENA256.bmp',0)       # 注:此處後面要加上0,表示已灰度模式讀入圖像
k3 = ndimage.convolve(img, kernal_3x3) # 注:使用ndimage.convolve()時,濾波核的維度應與原始圖像的維度相同,故此採用灰度圖
k5 = ndimage.convolve(img, kernal_5x5)

blurred = cv2.GaussianBlur(img, (11, 11), 0)
g_hpf = img - blurred
cv2.imshow("image", img)
cv2.imshow("3x3", k3)
cv2.imshow("5x5", k5)
cv2.imshow("g_hpf", g_hpf)
cv2.waitKey()
cv2.destroyAllWindows()

注:這些濾波器中的全部值加起來爲0.

運行結果爲:

 

  導入模塊以後,咱們定義一個3x3和一個5x5的核,而後將讀入的圖像轉換爲灰度格式。一般大多數的圖像處理會用NumPy來完成,可是這裏的狀況比較特殊,由於須要用一個給定的核與圖像進行「卷積」(convolve),可是NumPy碰巧只接受一維數組。ndimage的convolve()函數支持經典的NumPy數組,cv2模塊用這種數組來存儲圖像。

  還有一種方法可實現高通濾波器:經過對圖像應用低通濾波器以後,與原始圖像計算差值。

2.2 低通濾波器

  高通濾波器是根據像素與鄰近像素的亮度差值來提高該像素的亮度。低通濾波器(Low Pass Filter, LPF)則是在像素與周圍像素的亮度差值小於一個特定值時,平滑該像素的亮度。它主要用於去噪和模糊化,好比說,高斯模糊是最經常使用的模糊濾波器(平滑濾波器)之一,它是一個削弱高頻信號信息強度的低通濾波器。

3. 邊緣檢測

  OpenCV提供了許多邊緣檢測濾波函數,包括Laplacian()、Sobel()以及Scharr()。這些濾波函數都會將非邊緣區域轉爲黑色,將邊緣區域轉爲白色或其餘飽和的顏色。可是,這些函數都很容易將噪聲錯誤地識別爲邊緣。緩解這個問題的方法是在找到邊緣以前對圖像進行模糊處理。OpenCV也提供了許多模糊濾波函數,包括blur()(簡單的算術平均)、medianBlur()以及GaussianBlur()。邊緣檢測濾波函數和模糊濾波函數的參數有不少,但總會有一個ksize參數,它是一個奇數,表示濾波器的寬和高(以像素爲單位)。

  這裏使用medianBlur()做爲模糊函數,它對去除數字化的視頻噪聲很是有效,特別是去除彩色圖像的噪聲;使用Laplacian()做爲邊緣檢測函數,它會產生明顯的邊緣線條,灰度圖像更是如此。在使用medianBlur()函數以後,將要使用Laplacian()函數以前,須要將圖像從BGR色彩空間轉爲灰度色彩空間。

  在獲得Laplacian()函數的結果以後,須要將其轉換成黑色邊緣和白色背景的圖像。而後將其歸一化(使它的像素值在0到1之間),並乘以源圖像以便能將邊緣變黑。

  注意,核的大小可由strokeEdges()函數的參數來指定。blurKsize參數會 做爲medianBlur()含糊的ksize參數,edgeKsize參數會做爲Laplacian()函數的ksize參數。對於做者的攝像頭,將blurKsize值設爲7,將edgeKsize值設爲5會獲得最好的效果。但對於較大的ksize(好比7),使用medianBlur()的代價很高。若是在使用strokeEdges()函數時遇到性能問題,可試着減少blurKsize的值。要關閉模糊效果,能夠將blurKsize的值設爲3如下。

4. 用定製內核作卷積

  OpenCV預約義的許多濾波器(濾波函數)都會使用核。其實核是一組權重,它決定如何經過鄰近像素點來計算新的像素點。核也稱爲卷積矩陣,它對一個區域的像素作調和(mix up)或卷積運算。一般基於核的濾波器(濾波函數)被稱爲卷積濾波器(濾波函數)。

  OpenCV提供了一個很是通用的filter2D()函數,它運用由用戶指定的任意核或卷積矩陣。卷積矩陣是一個二維數組,有奇數行、奇數列,中心的元素對應於感興趣的像素。其餘的元素對應於這個像素周圍的鄰近像素,每一個元素都有一個整數或浮點數的值,這些值就是應用在像素值上的權重。如:

kernel = numpy.array([[-1, -1 , -1],
                      [-1,  9,  -1],
                      [-1, -1, -1]])

  其中感興趣的像素權重爲9,其鄰近像素權重爲-1。對感興趣的像素來講,新的像素值使用當前像素值乘以9,而後減去8個鄰近像素值。若是感興趣的像素已經與其鄰近像素有一點差異,那麼這個差異會增長。這樣會讓圖像銳化,由於該像素的值與鄰近像素值之間的差距拉大了。注意權重加起來爲1,若是不想改變圖像的亮度就應該這樣。若是稍微修改一下銳化核使它的權重加起來爲0,就會獲得一個邊緣檢測核,把邊緣轉爲白色,把非邊緣區域轉爲黑色。

  在源圖像和目標圖像上分別使用卷積矩陣:cv2.filter2D(src, -1, kernel, dst). 第二個參數指定了目標圖像每一個通道的位深度(好比,位深度cv2.CV_8U表示每一個通道爲8位),若是爲負值,則表示目標圖像和源圖像有一樣的位深度。

  注:對彩色圖像來講,filter2D()會對每一個通道都用一樣的核。若是要對每一個通道使用不一樣的核,就必須用split()函數和merge()函數。

  對於模糊濾波器,爲了達到模糊效果,一般權重和應該爲1,並且鄰近像素的權重全爲正。

  銳化、邊緣檢測以及模糊等濾波器都是用了高度對稱的核。可是有時不對稱的核也會獲得一些有趣的效果。

# VConvolutionFilter 表示通常的濾波器
class VConvolutionFilter(object):
    """A filter that applies a convolution to V(or all of BGR)."""

    def __init__(self, kernel):
        self._kernel = kernel

    def apply(self, src, dst):
        """Apply the filter with a BGR or gray source/destination."""
        cv2.filter2D(src, -1, self._kernel, dst)

# SharpenFilter 表示特定的銳化濾波器
class SharpenFilter(VConvolutionFilter):
    """A sharpen filter with a 1-pixel radius."""
    def __init__(self):
        kernel = numpy.array([[-1, -1, -1],
                              [-1, 9, -1],
                              [-1, -1, -1]])
        VConvolutionFilter.__init__(self, kernel)

# 邊緣檢測濾波器
class FindEdgesFilter(VConvolutionFilter):
    """A edge-finding filter with a 1-pixel radius."""
    def __init__(self):
        kernel = numpy.array([[-1, -1, -1],
                              [-1, 8, -1],
                              [-1, -1, -1]])
        VConvolutionFilter.__init__(self, kernel)

# 鄰近平均濾波器
class BlurFilter(VConvolutionFilter):
    """A edge-finding filter with a 1-pixel radius."""
    def __init__(self):
        kernel = numpy.array([[0.04, 0.04, 0.04, 0.04, 0.04],
                              [0.04, 0.04, 0.04, 0.04, 0.04],
                              [0.04, 0.04, 0.04, 0.04, 0.04],
                              [0.04, 0.04, 0.04, 0.04, 0.04],
                              [0.04, 0.04, 0.04, 0.04, 0.04]])
        VConvolutionFilter.__init__(self, kernel)

  下面介紹一種核,它同時具備模糊(有正的權重)和銳化(有負的權重)的做用。這會產生一種脊狀(ridge)或者浮雕(embossed)的效果。

class EmbossFilter(VConvolutionFilter):
    """A edge-finding filter with a 1-pixel radius."""

    def __init__(self):
        kernel = numpy.array([[-2, -1, 0],
                              [-1, 1, 1],
                              [0, 1, 2]])
        VConvolutionFilter.__init__(self, kernel)
相關文章
相關標籤/搜索