關(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í)的教程:第一部分
發(fā)表評(píng)論
請(qǐng)輸入評(píng)論內(nèi)容...
請(qǐng)輸入評(píng)論/評(píng)論長(zhǎng)度6~500個(gè)字
最新活動(dòng)更多
-
10月31日立即下載>> 【限時(shí)免費(fèi)下載】TE暖通空調(diào)系統(tǒng)高效可靠的組件解決方案
-
即日-11.13立即報(bào)名>>> 【在線會(huì)議】多物理場(chǎng)仿真助跑新能源汽車
-
11月28日立即報(bào)名>>> 2024工程師系列—工業(yè)電子技術(shù)在線會(huì)議
-
12月19日立即報(bào)名>> 【線下會(huì)議】OFweek 2024(第九屆)物聯(lián)網(wǎng)產(chǎn)業(yè)大會(huì)
-
即日-12.26火熱報(bào)名中>> OFweek2024中國(guó)智造CIO在線峰會(huì)
-
即日-2025.8.1立即下載>> 《2024智能制造產(chǎn)業(yè)高端化、智能化、綠色化發(fā)展藍(lán)皮書(shū)》
推薦專題
- 1 【一周車話】沒(méi)有方向盤(pán)和踏板的車,你敢坐嗎?
- 2 特斯拉發(fā)布無(wú)人駕駛車,還未迎來(lái)“Chatgpt時(shí)刻”
- 3 特斯拉股價(jià)大跌15%:Robotaxi離落地還差一個(gè)蘿卜快跑
- 4 馬斯克給的“驚喜”夠嗎?
- 5 大模型“新星”開(kāi)啟變現(xiàn)競(jìng)速
- 6 海信給AI電視打樣,12大AI智能體全面升級(jí)大屏體驗(yàn)
- 7 打完“價(jià)格戰(zhàn)”,大模型還要比什么?
- 8 馬斯克致敬“國(guó)產(chǎn)蘿卜”?
- 9 神經(jīng)網(wǎng)絡(luò),誰(shuí)是盈利最強(qiáng)企業(yè)?
- 10 比蘋(píng)果偉大100倍!真正改寫(xiě)人類歷史的智能產(chǎn)品降臨
- 高級(jí)軟件工程師 廣東省/深圳市
- 自動(dòng)化高級(jí)工程師 廣東省/深圳市
- 光器件研發(fā)工程師 福建省/福州市
- 銷售總監(jiān)(光器件) 北京市/海淀區(qū)
- 激光器高級(jí)銷售經(jīng)理 上海市/虹口區(qū)
- 光器件物理工程師 北京市/海淀區(qū)
- 激光研發(fā)工程師 北京市/昌平區(qū)
- 技術(shù)專家 廣東省/江門(mén)市
- 封裝工程師 北京市/海淀區(qū)
- 結(jié)構(gòu)工程師 廣東省/深圳市