關于圖像處理和Python深度學習的教程:第二部分
我們將以對比度增強開始第二部分。
6、對比度增強
某些類型的圖像(如醫(yī)學分析結果)對比度較低,很難發(fā)現(xiàn)細節(jié),如下所示:
xray = imread("images/xray.jpg")
xray_gray = rgb2gray(xray)
compare(xray, xray_gray)
在這種情況下,我們可以使用對比度增強使細節(jié)更加清晰。有兩種對比度增強算法:
對比度拉伸
直方圖均衡化
我們將在這篇文章中討論直方圖均衡化,它又有三種類型:
標準直方圖均衡化
自適應直方圖均衡化
對比度受限自適應直方圖均衡化(CLAHE)
直方圖均衡化將圖像對比度最高的區(qū)域擴展到亮度較低的區(qū)域,使其均衡。
你可以通過從最高的像素值中減去最低的像素值來計算圖像的對比度。
>>> xray.max() - xray.min()
255
現(xiàn)在,讓我們嘗試exposure模塊中的標準直方圖均衡化:
from skimage.exposure import equalize_hist
enhanced = equalize_hist(xray_gray)
>>> compare(xray, enhanced)
我們已經(jīng)可以更清楚地看到細節(jié)了。
from skimage.exposure import equalize_hist
enhanced = equalize_hist(xray_gray)
>>> compare(xray, enhanced)
接下來,我們將使用CLAHE,它為圖像中的不同像素鄰域計算許多直方圖,即使在最暗的區(qū)域也會得到更詳細的信息:
from skimage.exposure import equalize_adapthist
# Adjust clip_limit
enhanced_adaptive = equalize_adapthist(xray_gray, clip_limit=0.4)
compare(xray, enhanced_adaptive, "Image with contrast enhancement")
這個看起來好多了,因為它可以在背景中顯示細節(jié),在左下角顯示更多缺失的肋骨。你可以調整clip_limit以獲得更多或更少的細節(jié)。
7、變換
數(shù)據(jù)集中的圖像可能有幾個相互沖突的特征,如不同的比例、未對齊的旋轉等。ML和DL算法希望你的圖片具有相同的形狀和尺寸。因此,你需要學習如何修復它們。
旋轉
要旋轉圖像,請使用“transform”模塊中的“rotate”函數(shù)。
from skimage.transform import rotate
clock = imread("images/clock.jpg")
clockwise = rotate(clock, angle=-60)
compare(clock, clockwise, "Clockwise rotated image, use negative angles")
anti_clockwise = rotate(clock, angle=33)
compare(clock, anti_clockwise, "Anticlockwise rotated image, use positive angles")
縮放
另一個標準操作是縮放圖像。
我們對此操作使用rescale函數(shù):
butterflies = imread("images/butterflies.jpg")
>>> butterflies.shape
(720, 1280, 3)
from skimage.transform import rescale
scaled_butterflies = rescale(butterflies, scale=3 / 4, multichannel=True)
compare(
butterflies,
scaled_butterflies,
"Butterflies scaled down by a factor of 3/4",
axis=True,
)
當圖像分辨率較高時,縮小可能會導致質量損失或像素不協(xié)調,從而產(chǎn)生意外的邊或角。要考慮這種影響,可以將anti_aliasing設置為True,它使用高斯平滑:
https://gist.github.com/f7ae272b6eb1bce408189d8de2b71656
與之前一樣,平滑效果并不明顯,但在更細粒度的級別上會更明顯。
調整大小
如果希望圖像具有特定的寬度和高度,而不是按系數(shù)縮放,可以通過提供output_shape來使用resize函數(shù):
from skimage.transform import resize
puppies = imread("images/puppies.jpg")
# Also possible to set anti_aliasing
puppies_600_800 = resize(puppies, output_shape=(600, 800))
compare(puppies, puppies_600_800,
"Puppies image resized 600x800 (height, width)")
圖像恢復和增強
在文件變換、錯誤下載或許多其他情況下,某些圖像可能會失真、損壞或丟失。
在本節(jié)中,我們將討論一些圖像恢復技術,從修復開始。
1、修補
修復算法可以智能地填補圖像中的空白。我找不到損壞的圖片,因此我們將使用此鯨魚圖像并手動在其上放置一些空白:
whale_image = imread("images/00206a224e68de.jpg")
>>> show(whale_image)
>>> whale_image.shape
(428, 1916, 3)
以下函數(shù)創(chuàng)建四個變黑區(qū)域,以模擬圖像上丟失的信息:
def make_mask(image):
"""Create a mask to artificially defect the image."""
mask = np.zeros(image.shape[:-1])
# Make 4 masks
mask[250:300, 1400:1600] = 1
mask[50:100, 300:433] = 1
mask[300:380, 1000:1200] = 1
mask[200:270, 750:950] = 1
return mask.a(chǎn)stype(bool)
# Create the mask
mask = make_mask(whale_image)
# Apply the defect mask on the whale_image
image_defect = whale_image * ~mask[..., np.newaxis]
compare(whale_image, image_defect, "Artifically damaged image of a whale")
我們將使用inpaint模塊中的inpaint_biharmonic函數(shù)來填充空白,并傳遞我們創(chuàng)建的掩碼:
from skimage.restoration import inpaint
restored_image = inpaint.inpaint_biharmonic(
image=image_defect, mask=mask, multichannel=True
)
compare(
image_defect,
restored_image,
"Restored image after defects",
title_original="Faulty Image",
)
正如你所看到的,在看到故障圖像之前,很難判斷缺陷區(qū)域在哪里。
現(xiàn)在,讓我們制造一些噪聲
2、噪聲
如前所述,噪聲在圖像增強和恢復中起著至關重要的作用。
有時,你可能會有意將其添加到如下圖像中:
from skimage.util import random_noise
pup = imread("images/pup.jpg")
noisy_pup = random_noise(pup)
compare(pup, noisy_pup, "Noise puppy image")
我們使用random_noise函數(shù)向圖像噴灑隨機的顏色斑點。因此,這種方法被稱為“鹽和胡椒(salt和 pepper)”技術。
3、降噪-去噪
但是,大多數(shù)情況下,你希望從圖像中移除噪聲,而不是添加噪聲。有幾種類型的去噪算法:
TV濾波器
雙邊去噪
小波降噪
非局部均值去噪
在本文中,我們將只看前兩個。我們先試試TV濾波器
from skimage.restoration import denoise_tv_chambolle
denoised_pup_tv = denoise_tv_chambolle(noisy_pup, weight=0.2, multichannel=True)
compare(
noisy_pup,
denoised_pup_tv,
"Total Variation Filter denoising applied",
title_original="Noisy pup",
)
圖像的分辨率越高,去噪所需的時間就越長?梢允褂脵嘀貐(shù)控制去噪效果。
現(xiàn)在,讓我們嘗試denoise_bilateral:
from skimage.restoration import denoise_bilateral
denoised_pup_bilateral = denoise_bilateral(noisy_pup, multichannel=True)
compare(noisy_pup, denoised_pup_bilateral, "Bilateral denoising applied image")
它不如TV濾波器有效,如下所示:
compare(
denoised_pup_tv,
denoised_pup_bilateral,
"Bilateral filtering",
title_original="TV filtering",
)
4、分割
圖像分割是圖像處理中最基本和最日常的主題之一,它廣泛應用于運動和目標檢測、圖像分類等許多領域。
我們已經(jīng)看到了分割的一個實例—對圖像進行閾值化以從前景中提取背景。
本節(jié)將學習更多內(nèi)容,例如將圖像分割為類似區(qū)域。
要開始分割,我們需要了解超級像素的概念。
一個像素本身只代表一小部分顏色,一旦與圖像分離,單個像素將毫無用處。因此,分割算法使用對比度、顏色或亮度相似的多組像素,它們被稱為超級像素。
一種試圖找到超像素的算法是簡單線性迭代聚類(SLIC),它使用k均值聚類。讓我們看看如何在skimage庫中提供的咖啡圖像上使用它:
from skimage import data
coffee = data.coffee()
>>> show(coffee)
我們將使用segmentation模塊中的slic函數(shù):
from skimage.segmentation import slic
segments = slic(coffee)
>>> show(segments)
默認情況下,slic會查找100個線段或標簽。要將它們放回圖像中,我們使用label2rgb函數(shù):
from skimage.color import label2rgb
final_image = label2rgb(segments, coffee, kind="avg")
>>> show(final_image)
讓我們將此操作包裝在函數(shù)中,并嘗試使用更多段:
from skimage.color import label2rgb
from skimage.segmentation import slic
def segment(image, n_segments=100):
# Obtain superpixels / segments
superpixels = slic(coffee, n_segments=n_segments)
# Put the groups on top of the original image
segmented_image = label2rgb(superpixels, image, kind="avg")
return segmented_image
# Find 500 segments
coffee_segmented_2 = segment(coffee, n_segments=500)
compare(coffee, coffee_segmented_2, "With 500 segments")
分割將使計算機視覺算法更容易從圖像中提取有用的特征。
5、等高線
對象的大部分信息都存在于其形狀中。如果我們能夠檢測出物體的線條或輪廓形狀,我們就可以提取出有價值的數(shù)據(jù)。
讓我們看看如何在實踐中使用多米諾骨牌圖像來尋找輪廓。
dominoes = imread("images/dominoes.jpg")
>>> show(dominoes)
我們將看看是否可以使用skimage中的find_contours函數(shù)來隔離瓷磚和圓。此函數(shù)需要一個二進制(黑白)圖像,因此我們必須先對圖像設置閾值。
from skimage.measure import find_contours
# Convert to grayscale
dominoes_gray = rgb2gray(dominoes)
# Find optimal threshold with treshold_otsu
thresh = threshold_otsu(dominoes_gray)
# Binarize
dominoes_binary = dominoes_gray > thresh
domino_contours = find_contours(dominoes_binary)
生成的數(shù)組是(n,2)個數(shù)組的列表,表示等高線的坐標:
for contour in domino_contours[:5]:
print(contour.shape)
[OUT]:
(371, 2)
(376, 2)
(4226, 2)
(177, 2)
(11, 2)
我們將把操作包裝在一個名為mark_contours的函數(shù)中:
from skimage.filters import threshold_otsu
from skimage.measure import find_contours
def mark_contours(image):
"""A function to find contours from an image"""
gray_image = rgb2gray(image)
# Find optimal threshold
thresh = threshold_otsu(gray_image)
# Mask
binary_image = gray_image > thresh
contours = find_contours(binary_image)
return contours
要在圖像上繪制等高線,我們將創(chuàng)建另一個名為plot_image_contours的函數(shù),該函數(shù)使用上述函數(shù):
def plot_image_contours(image):
fig, ax = plt.subplots()
ax.imshow(image, cmap=plt.cm.gray)
for contour in mark_contours(image):
ax.plot(contour[:, 1], contour[:, 0], linewidth=2, color="red")
ax.a(chǎn)xis("off")
>>> plot_image_contours(dominoes)
正如我們所看到的,我們成功地檢測到了大部分輪廓,但我們?nèi)匀豢梢钥吹街行牡囊恍╇S機波動。
在將多米諾骨牌圖像傳遞到輪廓查找函數(shù)之前,先進行去噪:
dominoes_denoised = denoise_tv_chambolle(dominoes, multichannel=True)
plot_image_contours(dominoes_denoised)
就是這樣!我們消除了大部分噪聲,這些噪聲導致輪廓線不正確!
高級操作1、邊緣檢測
之前,我們使用Sobel算法來檢測對象的邊緣。在這里,我們將使用Canny算法,因為它更快、更準確,所以得到了更廣泛的應用。一如既往,函數(shù)canny需要灰度圖像。
這一次,我們將使用具有更多硬幣的圖像,因此需要檢測更多邊緣:
coins_3 = imread("images/coins_3.jpg")
# Convert to gray
coins_3_gray = rgb2gray(coins_3)
compare(coins_3, coins_3_gray)
要找到邊緣,我們只需將圖像傳遞給canny函數(shù):
from skimage.feature import canny
# Find edges with canny
canny_edges = canny(coins_3_gray)
compare(coins_3, canny_edges, "Edges detected with Canny algorithm")
該算法發(fā)現(xiàn)了幾乎所有硬幣的邊緣,但由于硬幣上的雕刻也被檢測到,因此噪聲非常大。我們可以通過調整sigma參數(shù)來降低canny的靈敏度:
canny_edges_sigma_2 = canny(coins_3_gray, sigma=2.5)
compare(coins_3, canny_edges_sigma_2, "Edges detected with less intensity")
正如你所見,Canny現(xiàn)在只找到了硬幣的大致輪廓。
2、角點檢測
另一種重要的圖像處理技術是角點檢測。角點可以是圖像分類中對象的關鍵特征。
為了找到角點,我們將使用Harris角點檢測算法。讓我們加載一個示例圖像并將其轉換為灰度:
windows = imread("images/windows.jpg")
windows_gray = rgb2gray(windows)
compare(windows, windows_gray)
我們將使用corner_harris函數(shù)生成一個測量圖像,該圖像屏蔽了角點所在的區(qū)域。
from skimage.feature import corner_harris
measured_image = corner_harris(windows_gray)
>>> show(measured_image)
現(xiàn)在,我們將此蒙版度量圖像傳遞給corner_peaks函數(shù),該函數(shù)這次返回角點坐標:
from skimage.feature import corner_peaks
corner_coords = corner_peaks(measured_image, min_distance=50)
>>> len(corner_coords)
79
該函數(shù)找到79個角點。讓我們將操作包裝到函數(shù)中:
def find_corner_coords(image, min_distance=50):
# Convert to gray
gray_image = rgb2gray(image)
# Produce a measure image
measure_image = corner_harris(gray_image)
# Find coords
coords = corner_peaks(measure_image, min_distance=min_distance)
return coords
現(xiàn)在,我們將創(chuàng)建另一個函數(shù),該函數(shù)使用上述函數(shù)生成的坐標繪制每個角點:
def show_image_cornered(image):
# Find coords
coords = find_corner_coords(image)
# Plot them on top of the image
plt.imshow(image, cmap="gray")
plt.plot(coords[:, 1], coords[:, 0], "+b", markersize=15)
plt.a(chǎn)xis("off")
show_image_cornered(windows)
不幸的是,該算法沒有按預期工作。標記放置在磚的交叉處,而不是找到窗角。
這些是噪音,使它們毫無用處。讓我們對圖像進行去噪處理,并再次將其傳遞給函數(shù):
windows_denoised = denoise_tv_chambolle(windows, multichannel=True, weight=0.3)
show_image_cornered(windows_denoised)
現(xiàn)在,這好多了!它找到了大部分窗戶角。
結論
在真正的計算機視覺問題中,你不會同時使用所有這些。正如你可能已經(jīng)注意到的,我們今天學到的東西并不復雜,最多需要幾行代碼。棘手的部分是將它們應用于實際問題,并實際提高模型的性能。
感謝閱讀!
原文標題 : 關于圖像處理和Python深度學習的教程:第二部分
請輸入評論內(nèi)容...
請輸入評論/評論長度6~500個字
最新活動更多
-
10月31日立即下載>> 【限時免費下載】TE暖通空調系統(tǒng)高效可靠的組件解決方案
-
即日-11.13立即報名>>> 【在線會議】多物理場仿真助跑新能源汽車
-
11月28日立即報名>>> 2024工程師系列—工業(yè)電子技術在線會議
-
12月19日立即報名>> 【線下會議】OFweek 2024(第九屆)物聯(lián)網(wǎng)產(chǎn)業(yè)大會
-
即日-12.26火熱報名中>> OFweek2024中國智造CIO在線峰會
-
即日-2025.8.1立即下載>> 《2024智能制造產(chǎn)業(yè)高端化、智能化、綠色化發(fā)展藍皮書》
推薦專題
- 高級軟件工程師 廣東省/深圳市
- 自動化高級工程師 廣東省/深圳市
- 光器件研發(fā)工程師 福建省/福州市
- 銷售總監(jiān)(光器件) 北京市/海淀區(qū)
- 激光器高級銷售經(jīng)理 上海市/虹口區(qū)
- 光器件物理工程師 北京市/海淀區(qū)
- 激光研發(fā)工程師 北京市/昌平區(qū)
- 技術專家 廣東省/江門市
- 封裝工程師 北京市/海淀區(qū)
- 結構工程師