天天看點

opencv學習指南入門篇(一):圖像基本操作

文章目錄

    • 1.在Ubuntu16.04系統上安裝OpenCV和imutils
    • 2.檢視我們opencv項目結構
    • 3.加載并顯示圖像
    • 4.通路單個像素
    • 5.提取感興趣區域(ROI)
    • 6.調整圖像大小
    • 7.旋轉圖像
    • 8.平滑圖像
    • 9.在圖像上繪圖
    • 10.運作腳本

1.在Ubuntu16.04系統上安裝OpenCV和imutils

(1)opencv安裝在我之前的博文上介紹過可以翻閱;

(2)安裝imutils:

pip install imutils
           

如果是使用虛拟環境的話,記得進入虛拟環境後再安裝imutils

簡單介紹一下imutils:它是在opencv的基礎上對一些方法進行了封裝,使得一些圖像處理方法更友善易用

2.檢視我們opencv項目結構

假設我們将下載下傳到的源碼存放在“下載下傳”檔案夾下,執行以下指令:

cd 下載下傳
unzip opencv-tutorial.zip
cd opencv-tutorial
tree
opencv項目結構.png
           

第一個腳本opencv_tutorial_01.py将使用電影《侏羅紀公園》中的圖像(jp.png)進行基本的圖像處理操作。

第二個腳本opencv_tutorial_02.py将介紹如何使用這些圖像處理子產品來建立OpenCV應用程式,以計算Tetris圖像(tetris_blocks.png )中的對象數量。

3.加載并顯示圖像

首先在文本編輯器或IDE中打開opencv_tutorial_01.py:

#導入必要的軟體包
import imutils
import cv2

#加載并顯示圖像尺寸
#将圖像表示為包含h、w、d的多元numpy數組即變量"image"
#形狀參數包括行(height) x 列 (width) x 通道 (depth)
image = cv2.imread("jp.png")
(h, w, d) = image.shape
print("width={}, height={}, depth={}".format(w, h, d))
#在螢幕上顯示圖像,滑鼠要點選到圖像視窗
#按任意鍵繼續執行程式
cv2.imshow("Image", image)
cv2.waitKey(0)
           

深度是通道數——在我們的例子中是3,因為我們正在使用3個顔色通道:藍色,綠色和紅色(RGB)。

print輸出寬、高、深度:

width=600, height=322, depth=3
           

cv2.waitKey(0):等待按鍵,這一點很重要,否則我們的圖像顯示和消失的速度将比我們看到圖像還要快

4.通路單個像素

所有圖像都由像素組成,640 x 480圖像具有640列(寬度)和480行(高度),有640×480 = 307200個像素點

灰階圖像中的每個像素都有一個代表灰階的值,在OpenCV中,有256種灰階(從0到255)。是以,灰階圖像将具有與每個像素關聯的灰階值。

彩色圖像中的像素具有其他資訊,在學習圖像處理時很快就會熟悉幾種色彩空間。為簡單起見,我們僅考慮RGB顔色空間。

在OpenCV彩色圖像中,RGB(紅色,綠色,藍色)顔色空間中的每個像素都有一個3元組(B, G, R) ,注意,順序是BGR而不是RGB。

BGR 3元組中的每個值的範圍為[0, 255] 。OpenCV中RGB圖像中的每個像素有多少種顔色可能性?這很簡單:256×256×256 = 16777216

圖像坐标系規定是左上角為(0,0)

#通路位于x = 50(w),y = 100(h)的RGB像素
#OpenCV以BGR而不是RGB的順序存儲圖像
(B, G, R) = image[100, 50]
print("R={}, G={}, B={}".format(R, G, B))
           

前面已知圖檔尺寸為width=600, height=322, depth=3 。我們可以通過指定坐标來通路數組中的各個像素值,隻要它們在最大寬度和高度之内即可,圖像指定像素點的格式為:image[Y,X]。

在終端列印出該像素的RGB值:

R=41, G=49, B=37
           

5.提取感興趣區域(ROI)

提取“感興趣區域”(ROI)是圖像處理的一項重要技能。

舉例來說,您正在識别電影中的人臉。首先,您将運作人臉檢測算法以查找正在使用的所有幀中人臉的坐标。然後,您需要提取面部ROI,然後儲存它們或對其進行處理。

手動提取ROI通過數組切片來實作:

#從輸入圖像提取一個100*100的感興趣區,
#從x=320,y=60到x=420,y=160,并顯示圖像
roi = image[60:160, 320:420]
cv2.imshow("ROI", roi)
cv2.waitKey(0)
           

數組切片的格式為:image[startY:endY, startX:endX],注意前閉後開

6.調整圖像大小

調整圖像大小很重要,原因有很多。首先,我們可能需要調整大圖像的大小以适合螢幕。在較小的圖像上,圖像處理也更快,因為要處理的像素更少。在深度學習的情況下,我們經常忽略寬高比來調整圖像的大小,以使體積适合網絡,這要求圖像是正方形且具有一定尺寸。

#忽略寬高比,将原始圖像調整為200 x 200像素:
resized = cv2.resize(image, (200, 200))
cv2.imshow("Fixed Resizing", resized)
cv2.waitKey(0)
           

由于忽略了寬高比,得到的圖像已經失真。

opencv學習指南入門篇(一):圖像基本操作

假設要将600像素寬的圖像調整為300像素寬,同時保持寬高比。

#固定大小調整扭曲了寬高比,是以讓我們将寬度調整為300px,
#但根據寬高比得到height
r = 300.0 / w
dim = (300, int(h * r))
resized = cv2.resize(image, dim)
cv2.imshow("Aspect Ratio Resize", resized)
cv2.waitKey(0)
           

我們計算新寬度與舊寬度的比率(恰好是0.5)。

在此,我們指定新圖像的尺寸dim 。我們知道,我們希望有一個300像素寬的圖像,但我們必須乘以該比例計算新高度h。

将dim(圖像的尺寸)輸入到cv2.resize函數中,我們現在獲得了一個名為resized的新圖像,該圖像沒有失真。

opencv學習指南入門篇(一):圖像基本操作

但是,我們是否可以使調整大小時保持寬高比的過程變得更加容易?

使用imutils中的函數:imutils.resize

#手動計算寬高比可能很麻煩,
#是以讓我們使用#imutils庫來代替
resized = imutils.resize(image, width=300)
cv2.imshow("Imutils Resize", resized)
cv2.waitKey(0)
           

這樣保留了寬高比并調整圖像的大小隻需要需要提供圖像的width或height作為參數

opencv學習指南入門篇(一):圖像基本操作

7.旋轉圖像

# 首先計算圖像中心,"//"表示向下取整除
# 構造旋轉矩陣
# 最後應用warpAffine​函數旋轉圖像
center = (w // 2, h // 2)
M = cv2.getRotationMatrix2D(center, -45, 1.0)
rotated = cv2.warpAffine(image, M, (w, h))
cv2.imshow("OpenCV Rotation", rotated)
cv2.waitKey(0)
           

-45表示将圖像順時針旋轉45度。回憶一下中學關于機關圓的資訊,正角是逆時針方向,負角是順時針方向。

opencv學習指南入門篇(一):圖像基本操作
# 使用imutils執行相同的操作
rotated = imutils.rotate(image, -45)
cv2.imshow("Imutils Rotation", rotated)
cv2.waitKey(0)
           

但是以上的操作都使圖像被裁剪,運用imutils.rotate_bound函數使整個圖像保持可見。 :

rotated = imutils.rotate_bound(image, 45)
cv2.imshow("Imutils Bound Rotation", rotated)
cv2.waitKey(0)
           
opencv學習指南入門篇(一):圖像基本操作

8.平滑圖像

在許多圖像處理場合中,我們必須對圖像進行模糊處理以減少高頻噪聲,進而使我們的算法更容易檢測和了解圖像的實際内容,在OpenCV中,對圖像進行模糊處理非常容易,并且有多種方法可以完成圖像處理。

# 将具有11x11核心的高斯模糊應用于圖像以使其平滑,減少高頻噪聲
blurred = cv2.GaussianBlur(image, (11, 11), 0)
cv2.imshow("Blurred", blurred)
cv2.waitKey(0)
           

較大的核心将産生更模糊的圖像,較小的核心将建立較少的模糊圖像。

opencv學習指南入門篇(一):圖像基本操作

9.在圖像上繪圖

我們将在輸入圖像上繪制矩形,圓形和直線,我們還将在圖像上覆寫文本。

在繼續使用OpenCV在圖像上繪圖之前,請注意,在圖像上進行繪圖操作是直接執行的。是以,在每個代碼塊的開頭,我們制作原始圖像的副本,并将副本存儲為output 。然後,我們繼續繪制output的圖像,以免破壞原始圖像。

(1)在伊恩·馬爾科姆(Ian Malcolm)的臉上繪制一個矩形:

# 在男主臉上畫個矩形,線粗為2
output = image.copy()
cv2.rectangle(output, (320, 60), (420, 160), (0, 0, 255), 2)
cv2.imshow("Rectangle", output)
cv2.waitKey(0)
           

在OpenCV中繪制矩形比較簡單,使用預先計算的坐标,向cv2.rectangle函數提供了以下參數:

  • img :要繪制的目标圖像output
  • pt1 :起始像素坐标,在我們的例子中位于左上角,(320, 60)
  • pt2 :結束像素坐标,右下角的像素位于(420, 160)
  • color :BGR元組,紅色(0 , 0, 255)
  • thickness :線粗(負值将形成一個實心矩形),,這裡為2

由于我們使用的是OpenCV的函數而不是NumPy的操作,是以我們可以按(x,y)的順序而不是(y,x)的順序提供坐标,因為我們沒有直接操作或通路NumPy數組為我們處理這些事情。

opencv學習指南入門篇(一):圖像基本操作

(2)在Ellie Sattler博士的臉前放置一個藍色實心圓:

# 畫一個實心藍色圓在x=300,y=150
output = image.copy()
cv2.circle(output, (300, 150), 20, (255, 0, 0), -1)
cv2.imshow("Circle", output)
cv2.waitKey(0)
           
opencv學習指南入門篇(一):圖像基本操作

要繪制圓,需要向cv2.circle提供以下參數 :

  • img :圖像名稱
  • center :圓的中心坐标,這裡是(300, 150)
  • radius :圓半徑(以像素為機關),設定為20個像素值
  • color :圓圈顔色,藍色(255, 0, 0)
  • thickness :線的粗細,使用負值(-1),是以圓圈是實心的

(3)畫一條紅線,這條線穿過Ellie的頭,經過她的眼睛,一直到Ian的手:

# 畫一條線寬為5的紅線從x=60,y=20到x=400,y=200
output = image.copy()
cv2.line(output, (60, 20), (400, 200), (0, 0, 255), 5)
cv2.imshow("Line", output)
cv2.waitKey(0)
           

就像在矩形中一樣,需要兩個參數,顔色和線寬。

opencv學習指南入門篇(一):圖像基本操作

(4)在圖像上覆寫文本:

如果進行人臉識别,則可能需要在該人的臉上方繪制該人的名字

或者如果在計算機視覺事業中取得進步,則可以建構圖像分類器或對象檢測器,需要繪制包含類名和機率的文本。

# 在圖像上繪制文本
output = image.copy()
cv2.putText(output, "OpenCV + Jurassic Park!!!", (10, 25), 
    cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2)
cv2.imshow("Text", output)
cv2.waitKey(0)
           

putText函數的功能負責在圖像上繪制文本,需要的參數:

  • img :圖像名稱
  • text :要在圖像上寫/畫的文本字元串
  • pt :文本的起點
  • font :經常用cv2.FONT_HERSHEY_SIMPLEX字型,可以官網查閱
  • scale :字型大小
  • color :文字顔色
  • thickness :筆劃的粗細(以像素為機關)
    opencv學習指南入門篇(一):圖像基本操作

10.運作腳本

我使用的是vscode,右鍵-在終端中運作即可

最後貼上源代碼:

# USAGE
# python opencv_tutorial_01.py

# import the necessary packages
import imutils
import cv2

# load the input image and show its dimensions, keeping in mind that
# images are represented as a multi-dimensional NumPy array with
# shape no. rows (height) x no. columns (width) x no. channels (depth)
image = cv2.imread("jp.png")
(h, w, d) = image.shape
print("width={}, height={}, depth={}".format(w, h, d))

# display the image to our screen -- we will need to click the window
# open by OpenCV and press a key on our keyboard to continue execution
cv2.imshow("Image", image)
cv2.waitKey(0)

# access the RGB pixel located at x=50, y=100, keepind in mind that
# OpenCV stores images in BGR order rather than RGB
(B, G, R) = image[100, 50]
print("R={}, G={}, B={}".format(R, G, B))

# extract a 100x100 pixel square ROI (Region of Interest) from the
# input image starting at x=320,y=60 at ending at x=420,y=160
roi = image[60:160, 320:420]
cv2.imshow("ROI", roi)
cv2.waitKey(0)

# resize the image to 200x200px, ignoring aspect ratio
resized = cv2.resize(image, (200, 200))
cv2.imshow("Fixed Resizing", resized)
cv2.waitKey(0)

# fixed resizing and distort aspect ratio so let's resize the width
# to be 300px but compute the new height based on the aspect ratio
r = 300.0 / w
dim = (300, int(h * r))
resized = cv2.resize(image, dim)
cv2.imshow("Aspect Ratio Resize", resized)
cv2.waitKey(0)

# manually computing the aspect ratio can be a pain so let's use the
# imutils library instead
resized = imutils.resize(image, width=300)
cv2.imshow("Imutils Resize", resized)
cv2.waitKey(0)

# let's rotate an image 45 degrees clockwise using OpenCV by first
# computing the image center, then constructing the rotation matrix,
# and then finally applying the affine warp
center = (w // 2, h // 2)
M = cv2.getRotationMatrix2D(center, -45, 1.0)
rotated = cv2.warpAffine(image, M, (w, h))
cv2.imshow("OpenCV Rotation", rotated)
cv2.waitKey(0)

# rotation can also be easily accomplished via imutils with less code
rotated = imutils.rotate(image, -45)
cv2.imshow("Imutils Rotation", rotated)
cv2.waitKey(0)

# OpenCV doesn't "care" if our rotated image is clipped after rotation
# so we can instead use another imutils convenience function to help
# us out
rotated = imutils.rotate_bound(image, 45)
cv2.imshow("Imutils Bound Rotation", rotated)
cv2.waitKey(0)

# apply a Gaussian blur with a 11x11 kernel to the image to smooth it,
# useful when reducing high frequency noise
blurred = cv2.GaussianBlur(image, (11, 11), 0)
cv2.imshow("Blurred", blurred)
cv2.waitKey(0)

# draw a 2px thick red rectangle surrounding the face
output = image.copy()
cv2.rectangle(output, (320, 60), (420, 160), (0, 0, 255), 2)
cv2.imshow("Rectangle", output)
cv2.waitKey(0)

# draw a blue 20px (filled in) circle on the image centered at
# x=300,y=150
output = image.copy()
cv2.circle(output, (300, 150), 20, (255, 0, 0), -1)
cv2.imshow("Circle", output)
cv2.waitKey(0)

# draw a 5px thick red line from x=60,y=20 to x=400,y=200
output = image.copy()
cv2.line(output, (60, 20), (400, 200), (0, 0, 255), 5)
cv2.imshow("Line", output)
cv2.waitKey(0)

# draw green text on the image
output = image.copy()
cv2.putText(output, "OpenCV + Jurassic Park!!!", (10, 25), 
    cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2)
cv2.imshow("Text", output)
cv2.waitKey(0)