影象處理?沒有Python可不行

影象處理?沒有Python可不行
1 Star2 Stars3 Stars4 Stars5 Stars 給文章打分!
Loading...

python作為簡單高效又很強大的一門程式語言,對於影象的處理自然也是輕鬆拿下,scikit-image是python中處理影象的一個庫,對大多數的影象處理演算法進行了封裝,使用者只需呼叫相關的介面即可。

入門示例

首先使用pip安裝skimage

pip install skimage

接下來進行一些簡單的影象處理。

一張圖片在skimage中表示為多維陣列的形式,比如img[2:16, 1:10, 0]表示寬度上從第2個畫素點到第16個畫素點,高度上從1到10的畫素點,紅色通道。如果為灰度影象則沒有通道。也可以使用img[2, 3, 0]的形式,表示第二行,第三列,紅色通道。

使用.shape顯示圖片的資訊。如果圖片為彩色圖片,顯示為寬度畫素值,高度畫素值,通道。

print(img.shape)

(300, 451, 3)

我們可以只顯示圖片的某一個通道,其中紅綠藍三個通道分別用數字0,1,2表示。比如只顯示紅色通道:

R = img[:, :, 0]
io.imshow(R)

我們也可以通過只顯示某部分畫素區間來剪裁影象,比如:

img_c = img[80:180, 100:200, :]
io.imshow(img_c)

還可以通過控制畫素把影象二值化,也就是把畫素值轉換為0,1的形式。

from skimage import color
img4 = data.chelsea()
# 將彩色影象轉為灰度影象,用到color模組
img_gray = color.rgb2gray(img4)

# 拆包獲得行列數
rows, cols = img_gray.shape

# 迴圈,如果畫素值小於0.5為0,反之則為1。
for i in range(rows):
    for j in range(cols):
        if img_gray[i, j]<=0.5:
            img_gray[i, j] = 0
        else:
            img_gray[i, j] = 1
io.imshow(img_gray)

影象增強

作為影象處理的一個部分,影象增強用來改善影象的影象的質量,也就是讓圖片更好看。skimage提供了強大的函式支援。

比如通過灰度變換改變圖片的對比度和亮度。常見的演算法有伽馬調整和和log對數調整,在此不深究具體的演算法細節,會用即可。

這裡使用到matplotlib包,這是python中的一個繪圖工具,用來展示影象,繪製統計圖等。

from skimage import exposure, img_as_float
import matplotlib.pyplot as plt

# 把影象的畫素值轉換為浮點數
imge5 = img_as_float(data.moon())

# 使用伽馬調整
# 第二個引數控制亮度,大於1增強亮度,小於1降低。
gam1 = exposure.adjust_gamma(imge5, 2)


# 對數調整
log1 = exposure.adjust_log(imge5, 0.7)


# 用一行兩列來展示影象
plt.subplot(1, 3, 1)
plt.imshow(imge5, plt.cm.gray)

plt.subplot(1, 3, 2)
plt.imshow(gam1, plt.cm.gray)

plt.subplot(1, 3, 3)
plt.imshow(log1, plt.cm.gray)

另一個很有用的影象增強演算法是直方圖均衡化,能有效的改善影象。直方圖均衡化簡單來說就是通過將直方圖變為均勻分佈的來改善對比度。直方圖的橫座標代表某個畫素,縱座標代表該畫素有多少個。

# 直方圖均衡化
import matplotlib.pyplot as plt

img6 = data.moon()
# 指定繪製的大小
plt.figure("hist", figsize=(8, 8))

# 把影象的二維陣列按行轉為一維陣列,這樣才能繪製直方圖
arr = img6.flatten()

plt.subplot(2,2,1)
plt.imshow(img6, plt.cm.gray)
plt.subplot(2,2,2)
# 繪製直方圖
plt.hist(arr, bins=256, normed=1, edgecolor='None',facecolor='red')

# 對直方圖進行均衡化
img_c = exposure.equalize_hist(img6)
arr_c = img_c.flatten()
plt.subplot(2,2,3)
plt.imshow(img_c, plt.cm.gray)
plt.subplot(2,2,4)
plt.hist(arr_c, bins=256, normed=1, edgecolor='None', facecolor='red')

plt.show()

可以明顯的看出,經過直方圖均衡化之後,影象質量改善了許多。

再一個影象增強中常用的演算法就是各種濾波器,像平滑化濾波器,銳化濾波器等。這其中,平滑濾波器可以用來去除噪聲和平滑化處理影象,具體使用到的濾波器為低通濾波和中值濾波。不過低通噪聲去除噪聲的同時也平滑化了邊和尖銳的細節,中值濾波則不會。

除了低通還有高通,除了中值還有最大值,最小值,均值等濾波器,在此不多贅述,查官方手冊即可。

濾波器相關的演算法放在filter模組下,記得匯入。

from skimage import filters
import skimage.morphology as sm
image6 = data.camera()
# 中值濾波
# 第二個引數代表濾波器的形狀,disk代表平面圓形,當然還有什麼正方形,矩形啥的
edges = filters.median(image6, sm.disk(5))

plt.subplot(1, 2, 1)
plt.imshow(image6, plt.cm.gray)

plt.subplot(1, 2, 2)
plt.imshow(edges, plt.cm.gray)

與平滑濾波器正好相反,銳化濾波器可以用來提取邊緣,凸顯某些標誌,突出細節等。其中的演算法包括各種運算元,roberts運算元,prewitt梯度運算元等等,還有微分濾波器等。

比如使用sobel描述影象中物體的邊緣。

img = color.rgb2gray(data.chelsea())
# 使用sobel運算元
edges = filters.sobel(img)

plt.figure("img", figsize=(8,8))
plt.subplot(1,2,1)
plt.imshow(img, plt.cm.gray)
plt.subplot(1,2,2)
plt.title("sobel")
plt.imshow(edges, plt.cm.gray)
plt.show()

影象分割

影象分割主要就是進行特徵提取,從而使別影象中的物體,比如給你一張滿是蘋果的照片,讓你統計照片中一共有多少個蘋果。數出來的可不算。這時候就要用到影象分割中的一些演算法了。

介紹下閾值分割。閾值是什麼意思,比如你有一堆蘋果,為了區分出哪些是好蘋果哪些是不好的,規定尺寸大於75的就是好的,這裡的75就是閾值。簡單來說,閾值分割就是利用影象中要提取的目標區域與其背景在灰度特性上的差異,把影象看作具有不同灰度級的兩類區域(目標區域和背景區域)的組合,選取一個比較合理的閾值,產生二值影象。

看個例子。

img = color.rgb2gray(data.chelsea())
# 基於otsu閥值分割方法
thresh = filters.threshold_otsu(img)
dst = (img<=thresh)*1.0

plt.figure("img", figsize=(8,8))
plt.subplot(1,2,1)
plt.imshow(img, plt.cm.gray)
plt.subplot(1,2,2)
plt.title("otsu")
plt.imshow(dst, plt.cm.gray)
plt.show()

再說下形態學變換,形態學變換包括膨脹處理,腐蝕處理,開閉運算,白黑帽等。膨脹處理的意思是說檢測影象中畫素值為1的點,然後將它周圍某個區域的畫素都變為1。膨脹處理可以擴充邊緣和填充空洞。

看個例子。

img = data.checkerboard()
# 設定結構元素為邊長5的正方形
dst = sm.dilation(img, sm.square(5))
plt.figure('dilation', figsize=(8,8))
plt.subplot(1,2,1)
plt.imshow(img, plt.cm.gray)
plt.subplot(1,2,2)
plt.imshow(dst, plt.cm.gray)

腐蝕處理正好相反,檢測影象中畫素值為0的點,然後將它周圍某個區域的畫素都變為0。

img = data.checkerboard()
# 設定結構元素為邊長5的正方形
dst = sm.erosion(img, sm.square(5))
plt.figure('dilation', figsize=(8,8))
plt.subplot(1,2,1)
plt.imshow(img, plt.cm.gray)
plt.subplot(1,2,2)
plt.imshow(dst, plt.cm.gray)

影象識別

在機器學習和深度學習的推動下,影象識別獲得了很大的發展,識別率節節攀升。如今的影象識別都在用深度學習演算法來進行,所以這部分就不細講了。

skimage中有一些很有用的演算法用來檢測輪廓。比如使用霍夫圓來檢測圓形,橢圓變換來檢測橢圓等等。

import numpy as np
import matplotlib.pyplot as plt
from skimage import data, color,draw,transform,feature,util

image = util.img_as_ubyte(data.coins()[0:95, 70:370]) #裁剪原圖片
edges =feature.canny(image, sigma=3, low_threshold=10, high_threshold=50) #檢測canny邊緣

fig, (ax0,ax1) = plt.subplots(1,2, figsize=(8, 5))

ax0.imshow(edges, cmap=plt.cm.gray)  #顯示canny邊緣
ax0.set_title('original iamge')

hough_radii = np.arange(15, 30, 2)  #半徑範圍
hough_res =transform.hough_circle(edges, hough_radii)  #圓變換 

centers = []  #儲存中心點座標
accums = []   #累積值
radii = []    #半徑

for radius, h in zip(hough_radii, hough_res):
    #每一個半徑值,取出其中兩個圓
    num_peaks = 2
    peaks =feature.peak_local_max(h, num_peaks=num_peaks) #取出峰值
    centers.extend(peaks)
    accums.extend(h[peaks[:, 0], peaks[:, 1]])
    radii.extend([radius] * num_peaks)

#畫出最接近的5個圓
image = color.gray2rgb(image)
for idx in np.argsort(accums)[::-1][:5]:
    center_x, center_y = centers[idx]
    radius = radii[idx]
    cx, cy =draw.circle_perimeter(center_y, center_x, radius)
    image[cy, cx] = (255,0,0)

ax1.imshow(image)
ax1.set_title('detected image')

這篇文章大致介紹了使用skimage庫來進行影象處理的一些過程,各種演算法的具體使用還是檢視官方手冊最為妥當。

本人才疏學淺,上文中難免有些錯誤,還請各位品評指正。

相關文章

程式語言 最新文章