圖像處理?沒有Python可不行

python做爲簡單高效又很強大的一門編程語言,對於圖像的處理天然也是輕鬆拿下,scikit-image是python中處理圖像的一個庫,對大多數的圖像處理算法進行了封裝,用戶只需調用相關的接口便可。python

入門示例

首先使用pip安裝skimage算法

pip install skimage編程

咱們都知道,圖像是由像素構成的,其中彩色圖像還包括不一樣的通道,視頻則是在圖像的基礎上加入時間變量而已。一張圖就像是由像素點構成的表格同樣,skimage正是基於此來進行圖像的處理操做。具體來講,skimage使用numpy做爲圖像的數據類型,numpy不用多說,它可讓你在 Python 中使用向量和數學矩陣(有不瞭解的能夠網上找找教程)。數組

咱們首先來打開一張圖片看看。機器學習

爲了方便,咱們使用skimage自帶的一些圖片,這些圖片放在data模塊下,使用data.<name>導入便可。若是要打開本地文件夾下的圖片,可使用io模塊下的imread方法,保存圖片可使用io.imsave。編程語言

from skimage import data, io
img = data.chelsea()
# 查看圖片,使用io模塊中的imshow方法
io.imshow(img)
# 保存圖片
io.imsave('F:cat.jpg', img)

圖片描述

接下來進行一些簡單的圖像處理。函數

一張圖片在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表示。好比只顯示紅色通道:spa

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庫來進行圖像處理的一些過程,各類算法的具體使用仍是查看官方手冊最爲穩當。

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

相關文章
相關標籤/搜索