訂閱
糾錯(cuò)
加入自媒體

關(guān)于圖像處理和Python深度學(xué)習(xí)的教程:第一部分

介紹

在這篇文章中,我們將學(xué)習(xí)如何執(zhí)行圖像處理。在整篇文章中,我們使用到的庫(kù)是Scikit Image。

基礎(chǔ)知識(shí)

1、什么是圖像?

圖像數(shù)據(jù)可能是文本之后最常見(jiàn)的數(shù)據(jù)。那么,電腦如何理解你在埃菲爾鐵塔前的自拍呢?

它使用一個(gè)稱為像素的小正方形網(wǎng)格。像素覆蓋一個(gè)小區(qū)域,并具有表示顏色的值。圖像中的像素越多,其質(zhì)量越高,存儲(chǔ)所需的內(nèi)存越多。

就是這樣。圖像處理主要是處理這些單獨(dú)的像素(有時(shí)是像素組),以便計(jì)算機(jī)視覺(jué)算法可以從中提取更多信息。

2、NumPy和Skimage的圖像基礎(chǔ)

在Matplotlib和Skimage中,圖像都作為NumPy ndarray加載。

from skimage.io import imread  # pip install scikit-image

image = imread("images/colorful_scenery.jpg")

>>> type(image)

numpy.ndarray

NumPy數(shù)組帶來(lái)靈活性、速度和力量。圖像處理也不例外。

Ndarrays可以輕松檢索圖像的一般詳細(xì)信息,例如圖像的尺寸:

>>> image.shape

(853, 1280, 3)

>>> image.ndim

3

# The number of pixels

>>> image.size  # 853 * 1280 * 3

3275520

我們的圖像高度為853像素,寬度為1280像素。第三維表示RGB(紅、綠、藍(lán))顏色通道的值。最常見(jiàn)的圖像格式是3D。

你可以通過(guò)常規(guī)NumPy索引檢索單個(gè)像素值。下面,我們嘗試索引圖像以檢索三個(gè)顏色通道中的每一個(gè)通道:

red = image[:, :, 0]

compare(image, red, "Red Channel of the Image", cmap_type="Reds_r")

green = image[:, :, 1]

compare(image, green, "Green Channel of the Image", "Greens_r")

blue = image[:, :, 2]

compare(image, blue, "Blue Channel of the Image", "Blues_r")

0表示紅色,1表示綠色,2表示藍(lán)色通道-非常簡(jiǎn)單。

創(chuàng)建了兩個(gè)函數(shù),show和compare,它們顯示一個(gè)圖像或并排顯示其中兩個(gè)進(jìn)行比較。在整個(gè)教程中,我們將廣泛使用這兩個(gè)函數(shù)。

按照約定,ndarray的第三維用于顏色通道,但并不總是遵循此約定。Skimage通常提供參數(shù)來(lái)指定這種行為。

圖像與通常的Matplotlib繪圖不同。它們的原點(diǎn)不位于左下角,而是位于左上角的位置(0,0)。

>>> show(image, axis=True)

當(dāng)我們?cè)贛atplotlib中繪制圖像時(shí),軸表示像素的順序,但我們通常會(huì)隱藏它們。

3、常見(jiàn)轉(zhuǎn)換

我們將要執(zhí)行的最常見(jiàn)的圖像轉(zhuǎn)換是將彩色圖像轉(zhuǎn)換為灰度。許多圖像處理算法需要灰度圖像。因?yàn)轭伾皇菆D片的定義特征,沒(méi)有它,計(jì)算機(jī)仍然可以提取足夠的信息。

from skimage.color import rgb2gray

image = imread("images/grayscale_example.jpg")

# Convert image to grayscale

gray = rgb2gray(image)

compare(image, gray, "Grayscale Image")

>>> gray.shape

(853, 1280)

當(dāng)將圖像轉(zhuǎn)換為灰度時(shí),它們會(huì)丟失其第三維度-顏色通道。相反,圖像數(shù)組中的每個(gè)單元格現(xiàn)在表示uint8類型的整數(shù)。它們的范圍從0到255,提供256種灰度。

你還可以使用np.flipud或者np.fliplr之類的NumPy函數(shù),隨心所欲地以任何方式操縱圖像。

kitten = imread("images/horizontal_flip.jpg")

horizontal_flipped = np.fliplr(kitten)

compare(kitten, horizontal_flipped, "Horizontally Flipped Image")

ball = imread("images/upside_down.jpg")

vertically_flipped = np.flipud(ball)

compare(ball, vertically_flipped, "Vertically Flipped Image")

在“顏色”模塊中,你可以找到許多其他變換函數(shù)來(lái)處理圖像中的顏色。

4、顏色通道直方圖

有時(shí),查看每個(gè)顏色通道的強(qiáng)度有助于了解顏色分布。我們可以通過(guò)切片每個(gè)顏色通道并繪制它們的直方圖來(lái)實(shí)現(xiàn)這一點(diǎn)。以下是執(zhí)行此操作的函數(shù):

def plot_with_h(yuǎn)ist_channel(image, channel):
 

  channels = ["red", "green", "blue"]

  channel_idx = channels.index(channel)

  color = channels[channel_idx]

  extracted_channel = image[:, :, channel_idx]
   

  fig, (ax1, ax2) = plt.subplots(

      ncols=2, figsize=(18, 6)

  )

  ax1.imshow(image)

  ax1.a(chǎn)xis("off")
   

  ax2.hist(extracted_channel.ravel(), bins=256, color=color)
   

  ax2.set_title(f"{channels[channel_idx]} histogram")

除了Matplotlib的一些細(xì)節(jié)之外,你還應(yīng)該注意hist函數(shù)的調(diào)用。提取顏色通道及其數(shù)組后,我們將其展平為1D數(shù)組,并將其傳遞給hist函數(shù)。

bin數(shù)量應(yīng)該是256個(gè),每個(gè)像素值對(duì)應(yīng)一個(gè)-0表示黑色,255表示完全白色。

讓我們使用彩色風(fēng)景圖像:

colorful_scenery = imread("images/colorful_scenery.jpg")

plot_with_h(yuǎn)ist_channel(colorful_scenery, "red")

>>> plot_with_h(yuǎn)ist_channel(colorful_scenery, "green")

>>> plot_with_h(yuǎn)ist_channel(colorful_scenery, "blue")

還可以使用直方圖在將圖像轉(zhuǎn)換為灰度后找出圖像中的亮度:

gray_color_scenery = rgb2gray(colorful_scenery)

plt.hist(gray_color_scenery.ravel(), bins=256);

大多數(shù)像素的值較低,因?yàn)榫拔飯D像較暗。

我們將在以下部分探討直方圖的更多應(yīng)用。

過(guò)濾器

1、手動(dòng)閾值

現(xiàn)在,我們來(lái)看看有趣的東西——過(guò)濾圖像。我們將學(xué)習(xí)的第一個(gè)操作是閾值化。讓我們加載一個(gè)示例圖像:

stag = imread("images/binary_example.jpg")

>>> show(stag)

閾值分割在圖像分割、目標(biāo)檢測(cè)、邊緣或輪廓提取等方面有著廣泛的應(yīng)用,它主要用于區(qū)分圖像的背景和前景。

閾值處理在高對(duì)比度灰度圖像上效果最好:

# Convert to graysacle

stag_gray = rgb2gray(stag)

>>> show(stag_gray)

我們將從基本的手動(dòng)閾值設(shè)置開(kāi)始,然后轉(zhuǎn)到自動(dòng)閾值設(shè)置。

首先,我們查看灰度圖像中所有像素的平均值:

>>> stag_gray.mean()

0.20056262759859955

請(qǐng)注意,通過(guò)將所有灰度圖像的值除以256,上述灰度圖像的像素在0和1之間歸一化。

我們得到的平均值為0.2,這為我們提供了可能要使用的閾值的初步想法。

現(xiàn)在,我們使用這個(gè)閾值來(lái)進(jìn)行掩碼操作。如果像素值低于閾值,否則其值將變?yōu)?-黑色或1-白色。換句話說(shuō),我們得到一個(gè)黑白二值圖像:

# Set threshold

threshold = 0.35

# Binarize

binary_image = stag_gray > threshold

compare(stag, binary_image, "Binary image")

在這個(gè)版本中,我們可以更清楚地區(qū)分鹿的輪廓。我們可以反轉(zhuǎn)遮罩,使背景變?yōu)榘咨?/p>

inverted_binary = stag_gray <= threshold

>>> compare(stag, inverted_binary, "Binary image inverted")

2、閾值-全局

雖然嘗試不同的閾值并觀察它們對(duì)圖像的影響可能很有趣,但我們通常使用比我們的眼球估計(jì)更穩(wěn)健的算法來(lái)執(zhí)行閾值分割。

有很多閾值算法,所以可能很難選擇一種。在這種情況下,skimage具有try_all_threshold函數(shù),該函數(shù)在給定的灰度圖像上運(yùn)行七種閾值算法。讓我們加載一個(gè)示例并進(jìn)行轉(zhuǎn)換:

flower = imread("images/global_threshold_ex.jpg")

flower_gray = rgb2gray(flower)

compare(flower, flower_gray)

我們將看看是否可以使用閾值優(yōu)化郁金香的特征:

from skimage.filters import try_all_threshold

fig, ax = try_all_threshold(  

flower_gray, figsize=(10, 8), verbose=False

正如你所看到的,一些算法在這張圖像上工作得更好,而其他算法則很糟糕。otsu算法看起來(lái)更好,所以我們將繼續(xù)使用它。

在這一點(diǎn)上,我想提請(qǐng)你注意郁金香的原始圖像:

>>> show(flower)

圖像背景不均勻,因?yàn)橛刑喙饩從后面的窗口射進(jìn)來(lái)。我們可以通過(guò)繪制灰色郁金香的直方圖來(lái)證實(shí)這一點(diǎn):

>>> plt.hist(flower_gray.ravel(), bins=256);

正如預(yù)期的那樣,大多數(shù)像素的值都位于直方圖的遠(yuǎn)端,這證實(shí)了它們大部分都是明亮的。

為什么這很重要?根據(jù)圖像的亮度,閾值算法的性能也會(huì)發(fā)生變化。因此,閾值算法通常有兩種類型:

全局-適用于具有均勻、統(tǒng)一背景的照片

局部-用于不同圖片區(qū)域中具有不同亮度級(jí)別的圖像。

郁金香圖像屬于第二類,因?yàn)橛覀?cè)部分比另一半亮得多,使其背景不均勻。我們不能在其上使用全局閾值算法,這就是為什么try_all_threshold中所有算法的性能都很差的原因。

稍后我們將回到郁金香示例和局部閾值,F(xiàn)在,我們將加載另一個(gè)亮度更精確的實(shí)例,并嘗試自動(dòng)設(shè)置閾值:

spiral = imread("images/otsu_example.jpg")

spiral_gray = rgb2gray(spiral)

compare(spiral, spiral_gray)

我們將在Skimage中使用通用的全局閾值算法threshold_otsu:

from skimage.filters import threshold_otsu

# Find optimal threshold with `threshold_otsu`

threshold = threshold_otsu(spiral_gray)

# Binarize

binary_spiral = spiral_gray > threshold

compare(spiral, binary_spiral, "Binarized Image w. Otsu Thresholding")

它工作得更好!

3、閾值-局部

現(xiàn)在,我們將使用局部閾值算法。

局部算法不關(guān)注整個(gè)圖像,而是關(guān)注像素鄰域,以解釋不同區(qū)域的亮度不均勻。skimage中常見(jiàn)的局部算法為threshold_local函數(shù):

from skimage.filters import threshold_local

local_thresh = threshold_local(flower_gray, block_size=3, offset=0.0002)

binary_flower = flower_gray > local_thresh

compare(flower, binary_flower, "Tresholded flower image")

你必須使用offset參數(shù)來(lái)找到符合你需要的最佳圖像。offset是從局部像素鄰域的平均值中減去的常數(shù)。該“像素鄰域”由local_threshold中的block_size參數(shù)確定,該參數(shù)表示算法在每個(gè)方向上圍繞每個(gè)點(diǎn)查看的像素?cái)?shù)。

顯然,同時(shí)調(diào)整offset和block_size是一個(gè)缺點(diǎn),但局部閾值是唯一比手動(dòng)或全局閾值產(chǎn)生更好結(jié)果的選項(xiàng)。

讓我們?cè)倥e一個(gè)例子:

from skimage.filters import threshold_local

handwriting = imread("images/chalk_writing.jpg")

handwriting_gray = rgb2gray(handwriting)

# Find optimal threshold using local

local_thresh = threshold_local(handwriting_gray, offset=0.0003)

# Binarize

binary_h(yuǎn)andwriting = handwriting_gray > local_thresh

compare(handwriting, binary_h(yuǎn)andwriting,

   "Binarized image with local thresholding")

正如你所看到的,經(jīng)過(guò)閾值處理后,黑板上的筆跡更加精細(xì)。

4、邊緣檢測(cè)

邊緣檢測(cè)在很多方面都很有用,例如識(shí)別對(duì)象、從中提取特征、對(duì)其進(jìn)行計(jì)數(shù)等等。

我們將從基本的Sobel濾波器開(kāi)始,它在灰度圖像中查找對(duì)象的邊緣。我們將加載一張硬幣圖片,并對(duì)其使用Sobel濾波器:

from skimage.filters import sobel

coins = imread("images/coins_2.jpg")

coins_gray = rgb2gray(coins)

coins_edge = sobel(coins_gray)

compare(coins, coins_edge, "Images of coins with edges detected")

sobel很直截了當(dāng);你只需在灰色圖像上調(diào)用它即可獲得如上所述的輸出。我們將在后面的部分中看到Sobel的更復(fù)雜版本。

5、平滑

另一種圖像過(guò)濾技術(shù)是平滑。許多像下面的雞一樣的圖像可能包含隨機(jī)噪聲,而對(duì)ML和DL算法沒(méi)有任何有價(jià)值的信息。

例如,雞周圍的毛發(fā)會(huì)給圖像添加噪聲,這可能會(huì)使ML模型的注意力偏離主要對(duì)象本身。在這種情況下,我們使用平滑來(lái)模糊噪聲或邊緣并降低對(duì)比度。

chickens = imread("images/chickens.jpg")

>>> show(chickens)

高斯平滑是最流行和最強(qiáng)大的平滑技術(shù)之一:

from skimage.filters import gaussian

smoothed = gaussian(chickens, multichannel=True, sigma=2)

compare(chickens, smoothed, "An image smoothed with Gaussian smoothing")

你可以通過(guò)調(diào)整sigma參數(shù)來(lái)控制模糊的效果。如果你正在處理RGB圖像,請(qǐng)不要忘記將multichannel設(shè)置為T(mén)rue。

如果圖像分辨率太高,平滑效果可能肉眼看不到,但仍然有效。

       原文標(biāo)題 : 關(guān)于圖像處理和Python深度學(xué)習(xí)的教程:第一部分

聲明: 本文由入駐維科號(hào)的作者撰寫(xiě),觀點(diǎn)僅代表作者本人,不代表OFweek立場(chǎng)。如有侵權(quán)或其他問(wèn)題,請(qǐng)聯(lián)系舉報(bào)。

發(fā)表評(píng)論

0條評(píng)論,0人參與

請(qǐng)輸入評(píng)論內(nèi)容...

請(qǐng)輸入評(píng)論/評(píng)論長(zhǎng)度6~500個(gè)字

您提交的評(píng)論過(guò)于頻繁,請(qǐng)輸入驗(yàn)證碼繼續(xù)

  • 看不清,點(diǎn)擊換一張  刷新

暫無(wú)評(píng)論

暫無(wú)評(píng)論

人工智能 獵頭職位 更多
掃碼關(guān)注公眾號(hào)
OFweek人工智能網(wǎng)
獲取更多精彩內(nèi)容
文章糾錯(cuò)
x
*文字標(biāo)題:
*糾錯(cuò)內(nèi)容:
聯(lián)系郵箱:
*驗(yàn) 證 碼:

粵公網(wǎng)安備 44030502002758號(hào)