訂閱
糾錯
加入自媒體

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

我們將以對比度增強(qiáng)開始第二部分。

6、對比度增強(qiáng)

某些類型的圖像(如醫(yī)學(xué)分析結(jié)果)對比度較低,很難發(fā)現(xiàn)細(xì)節(jié),如下所示:

 xray = imread("images/xray.jpg")
        xray_gray = rgb2gray(xray)
        compare(xray, xray_gray)

在這種情況下,我們可以使用對比度增強(qiáng)使細(xì)節(jié)更加清晰。有兩種對比度增強(qiáng)算法:

對比度拉伸

直方圖均衡化

我們將在這篇文章中討論直方圖均衡化,它又有三種類型:

標(biāo)準(zhǔn)直方圖均衡化

自適應(yīng)直方圖均衡化

對比度受限自適應(yīng)直方圖均衡化(CLAHE)

直方圖均衡化將圖像對比度最高的區(qū)域擴(kuò)展到亮度較低的區(qū)域,使其均衡。

你可以通過從最高的像素值中減去最低的像素值來計(jì)算圖像的對比度。

>>> xray.max() - xray.min()
       255

現(xiàn)在,讓我們嘗試exposure模塊中的標(biāo)準(zhǔn)直方圖均衡化:

from skimage.exposure import equalize_h(yuǎn)ist
       enhanced = equalize_h(yuǎn)ist(xray_gray)
       >>> compare(xray, enhanced)

我們已經(jīng)可以更清楚地看到細(xì)節(jié)了。

from skimage.exposure import equalize_h(yuǎn)ist
       enhanced = equalize_h(yuǎn)ist(xray_gray)
       >>> compare(xray, enhanced)

接下來,我們將使用CLAHE,它為圖像中的不同像素鄰域計(jì)算許多直方圖,即使在最暗的區(qū)域也會得到更詳細(xì)的信息:

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")

這個看起來好多了,因?yàn)樗梢栽诒尘爸酗@示細(xì)節(jié),在左下角顯示更多缺失的肋骨。你可以調(diào)整clip_limit以獲得更多或更少的細(xì)節(jié)。

7、變換

數(shù)據(jù)集中的圖像可能有幾個相互沖突的特征,如不同的比例、未對齊的旋轉(zhuǎn)等。ML和DL算法希望你的圖片具有相同的形狀和尺寸。因此,你需要學(xué)習(xí)如何修復(fù)它們。

旋轉(zhuǎn)

要旋轉(zhuǎn)圖像,請使用“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")

縮放

另一個標(biāo)準(zhǔn)操作是縮放圖像。

我們對此操作使用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,
        )

當(dāng)圖像分辨率較高時,縮小可能會導(dǎo)致質(zhì)量損失或像素不協(xié)調(diào),從而產(chǎn)生意外的邊或角。要考慮這種影響,可以將anti_aliasing設(shè)置為True,它使用高斯平滑:

https://gist.github.com/f7ae272b6eb1bce408189d8de2b71656

與之前一樣,平滑效果并不明顯,但在更細(xì)粒度的級別上會更明顯。

調(diào)整大小

如果希望圖像具有特定的寬度和高度,而不是按系數(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)")

圖像恢復(fù)和增強(qiáng)

在文件變換、錯誤下載或許多其他情況下,某些圖像可能會失真、損壞或丟失。

在本節(jié)中,我們將討論一些圖像恢復(fù)技術(shù),從修復(fù)開始。

1、修補(bǔ)

修復(fù)算法可以智能地填補(bǔ)圖像中的空白。我找不到損壞的圖片,因此我們將使用此鯨魚圖像并手動在其上放置一些空白:

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、噪聲

如前所述,噪聲在圖像增強(qiáng)和恢復(fù)中起著至關(guān)重要的作用。

有時,你可能會有意將其添加到如下圖像中:

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ù)向圖像噴灑隨機(jī)的顏色斑點(diǎn)。因此,這種方法被稱為“鹽和胡椒(salt和 pepper)”技術(shù)。

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",
        )

圖像的分辨率越高,去噪所需的時間就越長。可以使用權(quán)重參數(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、分割

圖像分割是圖像處理中最基本和最日常的主題之一,它廣泛應(yīng)用于運(yùn)動和目標(biāo)檢測、圖像分類等許多領(lǐng)域。

我們已經(jīng)看到了分割的一個實(shí)例—對圖像進(jìn)行閾值化以從前景中提取背景。

本節(jié)將學(xué)習(xí)更多內(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)

默認(rèn)情況下,slic會查找100個線段或標(biāo)簽。要將它們放回圖像中,我們使用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")

分割將使計(jì)算機(jī)視覺算法更容易從圖像中提取有用的特征。

5、等高線

對象的大部分信息都存在于其形狀中。如果我們能夠檢測出物體的線條或輪廓形狀,我們就可以提取出有價(jià)值的數(shù)據(jù)。

讓我們看看如何在實(shí)踐中使用多米諾骨牌圖像來尋找輪廓。

dominoes = imread("images/dominoes.jpg")
        >>> show(dominoes)

我們將看看是否可以使用skimage中的find_contours函數(shù)來隔離瓷磚和圓。此函數(shù)需要一個二進(jìn)制(黑白)圖像,因此我們必須先對圖像設(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ù)組的列表,表示等高線的坐標(biāo):

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機(jī)波動。

在將多米諾骨牌圖像傳遞到輪廓查找函數(shù)之前,先進(jìn)行去噪:

dominoes_denoised = denoise_tv_chambolle(dominoes, multichannel=True)
        plot_image_contours(dominoes_denoised)

就是這樣!我們消除了大部分噪聲,這些噪聲導(dǎo)致輪廓線不正確!

高級操作1、邊緣檢測

之前,我們使用Sobel算法來檢測對象的邊緣。在這里,我們將使用Canny算法,因?yàn)樗、更?zhǔn)確,所以得到了更廣泛的應(yīng)用。一如既往,函數(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)了幾乎所有硬幣的邊緣,但由于硬幣上的雕刻也被檢測到,因此噪聲非常大。我們可以通過調(diào)整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、角點(diǎn)檢測

另一種重要的圖像處理技術(shù)是角點(diǎn)檢測。角點(diǎn)可以是圖像分類中對象的關(guān)鍵特征。

為了找到角點(diǎn),我們將使用Harris角點(diǎn)檢測算法。讓我們加載一個示例圖像并將其轉(zhuǎn)換為灰度:

windows = imread("images/windows.jpg")
       windows_gray = rgb2gray(windows)
       compare(windows, windows_gray)

我們將使用corner_h(yuǎn)arris函數(shù)生成一個測量圖像,該圖像屏蔽了角點(diǎn)所在的區(qū)域。

from skimage.feature import corner_h(yuǎn)arris
       measured_image = corner_h(yuǎn)arris(windows_gray)
       >>> show(measured_image)

現(xiàn)在,我們將此蒙版度量圖像傳遞給corner_peaks函數(shù),該函數(shù)這次返回角點(diǎn)坐標(biāo):

from skimage.feature import corner_peaks
       corner_coords = corner_peaks(measured_image, min_distance=50)
       >>> len(corner_coords)
       79

該函數(shù)找到79個角點(diǎn)。讓我們將操作包裝到函數(shù)中:

def find_corner_coords(image, min_distance=50):
   
       # Convert to gray
   
       gray_image = rgb2gray(image)
   
       # Produce a measure image
   
       measure_image = corner_h(yuǎn)arris(gray_image)
       # Find coords
   
       coords = corner_peaks(measure_image, min_distance=min_distance)
       return coords

現(xiàn)在,我們將創(chuàng)建另一個函數(shù),該函數(shù)使用上述函數(shù)生成的坐標(biāo)繪制每個角點(diǎn):

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)

不幸的是,該算法沒有按預(yù)期工作。標(biāo)記放置在磚的交叉處,而不是找到窗角。

這些是噪音,使它們毫無用處。讓我們對圖像進(jìn)行去噪處理,并再次將其傳遞給函數(shù):

windows_denoised = denoise_tv_chambolle(windows, multichannel=True, weight=0.3)
       show_image_cornered(windows_denoised)

現(xiàn)在,這好多了!它找到了大部分窗戶角。

結(jié)論

在真正的計(jì)算機(jī)視覺問題中,你不會同時使用所有這些。正如你可能已經(jīng)注意到的,我們今天學(xué)到的東西并不復(fù)雜,最多需要幾行代碼。棘手的部分是將它們應(yīng)用于實(shí)際問題,并實(shí)際提高模型的性能。

感謝閱讀!


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

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

發(fā)表評論

0條評論,0人參與

請輸入評論內(nèi)容...

請輸入評論/評論長度6~500個字

您提交的評論過于頻繁,請輸入驗(yàn)證碼繼續(xù)

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

暫無評論

暫無評論

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

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