使用Python+opencv進行圖像處理(一)

使用Python+opencv進行圖像處理(一) | 視覺入門

計算機視覺是人工智能最熱門的應用領域之一。人工智能技術推動了汽車自動駕駛、機器人以及各種照片處理類軟件的巨大發展。目標檢測技術也在穩步推進。生成對抗網絡(GANs)同樣也是人們最近比較關注的一個問題。這些都在向我們展示未來計算機視覺領域的發展前景是多麼的不可限量。

讓我們一起登上人工智能發展的高速列車。從本文開始,我們將有一系列關於圖像處理和目標檢測基礎知識的教程。本篇是OpenCV入門教程第一部分,完整的系列教程如下:

  1. 理解顏色模型與在圖像上繪製圖形(圖像處理基本操作)。
  2. 基本的圖像處理與過濾。
  3. 從特徵檢測到人臉檢測(TBU)

本系列的第一部分將從Opencv的安裝,結合代碼實戰講解顏色模型與圖形繪製講起。本教程的完整代碼已經放在Github上,方便大家使用。

1、 OpenCV簡介

圖像處理是指對圖像執行一些操作以達到預期效果的過程。可以類比數據分析工作,在數據分析時我們需要做一些數據預處和特徵工程。圖像處理也是一樣的。我們通過圖像處理來處理圖片從而可以從中提取處一些更加有用的特徵。我們可以通過圖像處理減少圖像噪聲調整圖像亮度、顏色或者對比度等等。

OpenCV是Open Source Computer Vision的縮寫,由英特爾公司於1999年推出。它最初是用C/ C++編寫的,所以你可能會看到更多用C語言而不是Python編寫的教程。但現在它在Python中也被廣泛用於計算機視覺。首先,讓我們為使用OpenCV配置環境。安裝過程如下:

pip install opencv-python==3.4.2
pip install opencv-contrib-python==3.3.1

安裝完成後,可以通過下方兩條命令測試其是否正常工作。如果沒有任何報錯,那麼就可以開始使用了!

import cv2
cv2.__version__

我們使用用OpenCV做的第一步就是導入一個圖像,如下方所示。

import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
# Import the image
img = cv2.imread('burano.jpg')
plt.imshow(img)
使用Python+opencv進行圖像處理(一) | 視覺入門

上圖是在意大利最美麗的島嶼之一布拉諾所拍攝的。如果你去過這個地方,你可能會注意到這幅圖裡有些不同。這確實和我們通常看到的布拉諾的照片有點不同。這是因為OpenCV中顏色模式的默認設置順序是BGR,不同與Matplotlib。因此,要在RGB模式下查看圖像,我們需要將它從BGR轉換為RGB,如下所示。

# Convert the image into RGB
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
plt.imshow(img_rgb)
使用Python+opencv進行圖像處理(一) | 視覺入門

這張圖就是真正的布拉諾了,多麼美麗!

2、 不只是RGB

我們再來談談顏色模型。顏色模型是一個使用原色構建全系列顏色的系統。這裡先介紹這兩種不同的顏色模型:"加色模型"和"減色模型"。加色模型使用光代表計算機屏幕上的顏色,而減色模型使用墨水在紙上打印這些數字圖像。前者的原色由紅色、綠色和藍色(RGB)組成,後者有藍色、品紅、黃色和黑色(CMYK)四種原色組成。我們在圖像上看到的所有其他顏色都是由這些原色組合或混合而成的。所以當分別用RGB、CMYK表示一張圖像時,圖像可以有著略微不同地表達。如下圖所示。

使用Python+opencv進行圖像處理(一) | 視覺入門

日常生活中見到最多的就是這兩種顏色模型。然而,在彩色模型的世界裡不僅僅只有這兩種顏色模型。眾多的顏色模型中,灰度(grayscale)、HSV和HLS也是你會在計算機視覺任務中經常看到的。

灰度(grayscale)很簡單。它通過黑白的強度來表示圖像和形態,這也意味著它只有一個通道。要查看灰度圖像,我們需要將顏色模型轉換為灰色,就像前面對BGR圖像所做的操作那樣。

# Convert the image into gray scale
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
plt.imshow(img_gray, cmap = 'gray')
使用Python+opencv進行圖像處理(一) | 視覺入門

實際上,RGB圖像是由三個通道疊加而成的:R, G, b。所以如果我們把每個通道一個一個的描繪出來,我們就可以理解顏色通道是如何構成的了!

# Plot the three channels of the image
fig, axs = plt.subplots(nrows = 1, ncols = 3, figsize = (20, 20))
for i in range(0, 3):
ax = axs[i]
ax.imshow(img_rgb[:, :, i], cmap = 'gray')
plt.show()
使用Python+opencv進行圖像處理(一) | 視覺入門

觀察上面的圖片。這三幅圖像展示了每個通道是如何組成的。在R通道圖中,紅色飽和度高的部分看起來是白色的。這是由於紅色部分中的值接近255。在灰度模式下,值越高顏色就越白。你還可以使用G或B通道來檢查這一點,並比較某些部分之間的差異。

使用Python+opencv進行圖像處理(一) | 視覺入門

HSV和HLS有一些不同。正如在上圖看到的那樣,他們有一個三維的表達,更類似於人類的感知方式。HSV代表色調、飽和度和色值。HSL代表色調、飽和度和亮度。HSV的中軸是色值,HSL的中軸是光量。沿著中心軸的角度,有色調和實際的顏色。與中心軸的距離屬於飽和度。轉換顏色模型的方法如下。

# Transform the image into HSV and HLS models
img_hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
img_hls = cv2.cvtColor(img, cv2.COLOR_BGR2HLS)
# Plot the converted images
fig, (ax1, ax2) = plt.subplots(nrows = 1, ncols = 2, figsize = (20, 20))

ax1.imshow(img_hsv)
ax2.imshow(img_hls)
plt.show()
使用Python+opencv進行圖像處理(一) | 視覺入門

但是為什麼要變換顏色?這些有什麼用處?一個很典型的例子--車道檢測。觀察下圖,不同顏色模式下的車道線。在計算機視覺任務中,我們利用掩膜(masking)進行多色模式轉換。

使用Python+opencv進行圖像處理(一) | 視覺入門

圖像處理是就是對圖像數據進行預處理。它可以減少噪音,提取有用的顏色模型,從而簡化分類和檢測任務。因此,所有上述技術,包括我們稍後將討論的技術,都是為了幫助模型更容易地實現檢測。

3、 在圖像上繪製圖形

讓我們在圖像上添加一些圖形。咱們這次代碼示例中使用的圖片來自巴黎"愛的牆"。上面用各種國際語言寫滿了"我愛你"。我們要做的是找到語言中的單詞並用矩形標記它們。假如我們要定位韓語版本"我愛你"。首先, 複製原始圖像並用cv2.rectangle()函數繪製一個矩形,同時給出左上角和右下角的座標值。如下:

# Copy the image
img_copy = img.copy()
# Draw a rectangle
cv2.rectangle(img_copy, pt1 = (800, 470), pt2 = (980, 530),
color = (255, 0, 0), thickness = 5)
plt.imshow(img_copy)
使用Python+opencv進行圖像處理(一) | 視覺入門

使用cv2.circle()函數,畫一個圓,圈出更多的韓語單詞。我們需要指定它的圓心的點和半徑的長度。

# Draw a circle
cv2.circle(img_copy, center = (950, 50), radius = 50,
color = (0, 0, 255), thickness = 5)
plt.imshow(img_copy)
使用Python+opencv進行圖像處理(一) | 視覺入門

我們還可以將文本數據放在圖像上。使用cv2.putText()函數,我們可以指定文本的位置、字體樣式和大小。

# Add text
cv2.putText(img_copy, text = "the Wall of Love",
org = (250, 250),
fontFace = cv2.FONT_HERSHEY_DUPLEX,
fontScale = 2,
color = (0, 255, 0),
thickness = 2,
lineType = cv2.LINE_AA)
plt.imshow(img_copy)

4、 不止是圖像

在上邊的介紹中,我們選取意大利和法國的兩張風景圖作為示例。假如,我們想要畫張地圖把這些地方標出來。那麼,首先我們要創建一個窗口並繪製圖形。不一樣的是這裡不是通過指定點繪製圖形而是通過點擊響應。先試試繪製圓圈。首先創建一個函數,它將用位置和鼠標點擊的數據繪製一個圓圈。

# Step 1. Define callback function
def draw_circle(event, x, y, flags, param):
if event == cv2.EVENT_LBUTTONDOWN:
cv2.circle(img, center = (x, y), radius = 5,
color = (87, 184, 237), thickness = -1)
elif event == cv2.EVENT_RBUTTONDOWN:
cv2.circle(img, center = (x, y), radius = 10,
color = (87, 184, 237), thickness = 1)

按下鼠標點擊按鈕時,使用cv2.EVENT_LBUTTONDOWN或cv2.EVENT_RBUTTONDOWN記錄位置數據。把鼠標的位置設置為圓心(x, y),並繪製圓圈。

# Step 2. Call the window
img = cv2.imread('map.png')
cv2.namedWindow(winname = 'my_drawing')
cv2.setMouseCallback('my_drawing', draw_circle)

設置一個地圖作為窗口的背景,並將窗口命名為my_drawing。使用cv2.setMouseCallback()函數,在窗口和我們在步驟1中創建的函數draw_circle之間建立了一個連接。

# Step 3. Execution
while True:
cv2.imshow('my_drawing',img)
if cv2.waitKey(10) & 0xFF == 27:
break
cv2.destroyAllWindows()

現在我們使用while循環執行窗口。if子句的執行條件是,當我們按下鍵盤上的ESC時,將窗口設置為關閉。

使用Python+opencv進行圖像處理(一) | 視覺入門

接下來嘗試繪製一個矩形。由於在cv2.rectangle()函數中,矩形需要兩個點來表示pt1和pt2,所以我們需要一個額外的步驟來設置第一個點擊點為pt1,最後一個點擊點為pt2。我們要用cv2.EVENT_MOUSEMOVE和cv2.EVENT_LBUTTONUP來檢測鼠標的移動。

我們首先將drawing = False定義為默認值。當按下左鍵時,繪圖變為true,我們將第一個位置設為pt1。如果正在繪圖,它將以當前點為pt2,並在移動鼠標時繼續繪製矩形。就像數字重疊一樣。當左鍵打開時,繪圖變為false,它將鼠標的最後一個位置作為pt2的最後一個點。

# Initialization
drawing = False
ix = -1
iy = -1
# create a drawing function
def draw_rectangle(event, x, y, flags, params):
global ix, iy, drawing
if event == cv2.EVENT_LBUTTONDOWN:
drawing = True
ix, iy = x, y
elif event == cv2.EVENT_MOUSEMOVE:
if drawing == True:
cv2.rectangle(img, pt1=(ix, iy), pt2=(x, y),
color = (87, 184, 237), thickness = -1)
elif event == cv2.EVENT_LBUTTONUP:
drawing = False
cv2.rectangle(img, pt1=(ix, iy), pt2=(x, y),
color = (87, 184, 237), thickness = -1)

在步驟1中將draw_circle函數替換為draw_rectangle。請不要忘記在回調函數cv2.setMouseCallback()中進行更改。因此,整個代碼腳本將如下所示。

import cv2 

import numpy as np

# Step 1. Define callback function
drawing = False
ix = -1
iy = -1

def draw_rectangle(event, x, y, flags, params):

global ix, iy, drawing

if event == cv2.EVENT_LBUTTONDOWN:
drawing = True
ix, iy = x, y

elif event == cv2.EVENT_MOUSEMOVE:
if drawing == True:
cv2.rectangle(img, pt1 = (ix, iy), pt2 = (x, y),
color = (87, 184, 237), thickness = -1)

elif event == cv2.EVENT_LBUTTONUP:
drawing = False
cv2.rectangle(img, pt1 = (ix, iy), pt2 = (x, y),
color = (87, 184, 237), thickness = -1)


# Step 2. Call the window
img = cv2.imread('map.png')

cv2.namedWindow(winname = 'my_drawing')
cv2.setMouseCallback('my_drawing', draw_rectangle)


# Step 3. Execution
while True:
cv2.imshow('my_drawing', img)
if cv2.waitKey(10) & 0xFF == 27:
break

cv2.destroyAllWindows()

5、 總結與展望

本篇文章介紹了Opencv的安裝、圖像顏色模型的轉換與圖形繪製。下次,將介紹圖像輪廓提出與目標檢測等技術。敬請期待!


分享到:


相關文章: