電腦視覺教學 2:影像基礎

本教程是電腦視覺基礎系列課程的“第2課”;後續還有多節課程將深入探討如何建立基於深度學習的電腦視覺專案。您可以在此處找到完整的課程大綱和目錄

本文主要收穫如下:

  • 從磁碟載入圖像。
  • 獲取圖像的“高度”、“寬度”和“深度”。
  • 查找圖像的R、G和B成分。
  • 使用OpenCV繪圖。

從磁碟載入圖像

在我們對圖像進行任何操作或修改之前,首先需要將選定的圖像載入到磁碟上。我們將使用OpenCV來完成這一操作。載入圖像有兩種方法。一種方法是直接通過OpenCV的“imread”函數傳遞圖像路徑和圖像文件。另一種方法則是通過命令行參數使用Python模塊argparse來傳遞圖像。

Fig 2.1 Loading an Image from Disk by hard coding the image path and name in code.

Python

 

#從磁碟載入圖像

import cv2
image = cv2.imread(“C:/Sample_program/example.jpg”)
cv2.imshow(‘Image’, image)
cv2.waitKey(0)

首先,我們在Notepad++中建立一個名為Loading_image_from_disk.py的文件。第一步是導入OpenCV庫,該庫包含我們的圖像處理函數。我們使用第一行代碼cv2導入庫。第二行代碼是使用OpenCV中的cv2.imread函數讀取圖像,並將圖像的路徑作為參數傳遞;該路徑還應包含帶有其圖像格式擴展名.jpg、.jpeg、.png或.tiff的文件名。

語法// image=cv2.imread(“path/to/your/image.jpg”) //

在指定文件擴展名時必須格外小心。如果我們提供了錯誤的擴展名,很可能會收到以下錯誤。

Python

 

ERROR :

c:\Sample_program>python Loading_image_from_disk.py
Traceback (most recent call last):
File “Loading_image_from_disk.py”, line 4, in <module>
cv2.imshow(‘Image’, image)
cv2.error: OpenCV(4.3.0) C:\projects\opencv-python\opencv\modules\highgui\src\window.cpp:376: error: (-215:Assertion failed) size.width>0 && size.height>0 in function ‘cv::imshow’

第三行代碼是用於實際顯示已加載的圖像。第一個參數是一個字符串,或“窗口名稱”。第二個參數是已加載圖像的對象。

最後,cv2.waitKey的調用會暫停腳本的執行,直到我們在鍵盤上按下一個鍵。使用參數“0”表示任何鍵盤按鍵都會解除暫停執行。請隨意在不包含最後一行代碼的情況下運行您的程序,以查看差異。

Fig 2.2 Loading an Image using Argparse module.

Python

 

#使用Argparse從磁盤讀取圖像

import cv2
import argparse

apr = argparse.ArgumentParser()
apr.add_argument(“-i”, “ — image”, required=True, help=”Path to the image”)
args = vars(apr.parse_args())

image = cv2.imread(args[“image”])
cv2.imshow(‘Image’, image)
cv2.waitKey(0)

知道如何使用命令行參數(argparse)讀取圖像或文件是一項絕對必要的技能。

前兩行代碼是導入必要的庫;在這裡,我們導入OpenCV和Argparse。我們將在整個課程中重複這一操作。

以下三行代碼負責解析命令行參數。我們唯一需要的參數是—image:磁碟上我們圖像的路徑。最後,我們解析這些參數並將它們存儲在一個名為args的字典中。

讓我們花點時間快速討論一下—image開關究竟是什麼。—image“開關”(“開關”是“命令行參數”的同義詞,這兩個術語可以互換使用)是我們在命令行上指定的一個字符串。這個開關告訴我們的Loading_image_from_disk.py腳本,我們想要加載的圖像在磁碟上的位置。

最後三行代碼之前已經討論過;cv2.imread函數將args[“image”]作為參數,這實際上就是我們在命令提示符下提供的圖像。cv2.imshow顯示圖像,該圖像已經在前一行中存儲在圖像對象中。最後一行暫停腳本的執行,直到我們在鍵盤上按下一個鍵。

使用argparse—命令行參數的一個主要優點是,我們將能夠從不同的文件夾位置加載圖像,而無需在程序中動態地傳遞圖像路徑來改變圖像路徑,例如在執行我們的Python程序時,在命令提示符下作為參數傳遞“C:\CV_Material\image\sample.jpg”。

Fig 2.3 Loading Images from different folder locations using Argparse.

c:\Sample_program>python Loading_image_from_disk.py — image C:\CV_Material\session1.JPG

在這裡,我們正在執行Loading_image_from_disk.pyPython文件,從c:\sample_program位置通過傳遞“-image”參數以及圖像路徑C:\CV_Material\session1.JPG.

獲取圖像的‘高度’,‘寬度’和‘深度’

由於圖像以NumPy陣列表示,我們可以簡單地使用`.shape`屬性來檢查圖像的寬度、高度和通道數。

通過對剛載入的圖像物件使用`.shape`屬性,我們可以找到圖像的高度、寬度和深度。如前一課 — 1所述,圖像的高度和寬度可以通過在MS Paint中打開圖像來交叉驗證。請參閱前一課程。我們將在接下來的課程中討論圖像的深度。深度也被稱為圖像的通道。彩色圖像通常是3通道,因為其像素中的RGB組成,而灰度圖像是1通道。這是我們在前一課程-1中討論的內容。

Fig 2.4 Prints the Height, Width, and Depth of the Image.

Python

 

#獲取圖像的高度、寬度和深度

import cv2
import argparse

apr = argparse.ArgumentParser()
apr.add_argument(“-i”, “ — image”, required=True, help=”Path to the image”)
args = vars(apr.parse_args())

#與前一個代碼的唯一區別 — 對圖像物件應用了形狀屬性

print(f’(Height,Width,Depth) of the image is: {image.shape}’)

image = cv2.imread(args[“image”])
cv2.imshow(‘Image’, image)
cv2.waitKey(0)

輸出:

圖像的高度、寬度和深度是:(538, 723, 3)

與前一代碼的唯一區別在於應用了形狀屬性的打印語句到載入的圖像物件上。f’ 是F-字串@格式化字串,它動態地取用變數並打印。

f’ write anything here that you want to see in the print statement: {variables, variables, object, object.attribute,}’

在此,我们使用{object.attribute}在花括号内计算图像对象的高度、宽度和深度。

Python

 

#单独获取高度、宽度和深度

import cv2
import argparse

apr = argparse.ArgumentParser()
apr.add_argument(“-i”, “ — image”, required=True, help=”Path to the image”)
args = vars(apr.parse_args())

image = cv2.imread(args[“image”])

#使用NumPy数组切片单独获取高度、宽度和深度

print(“height: %d pixels” % (image.shape[0]))
print(“width: %d pixels” % (image.shape[1]))
print(“depth: %d” % (image.shape[2]))

cv2.imshow(‘Image’, image)
cv2.waitKey(0)

输出:

宽度: 723像素
高度: 538像素
深度: 3

这里,我们不是作为一个元组整体获取(高度、宽度和深度),而是通过数组切片单独获取图像的高度、宽度和深度。数组的第0个索引包含图像的高度,第1个索引包含图像的宽度,第2个索引包含图像的深度。

查找图像的R、G和B组件

Fig 2.5 BGR value printed after taking the pixel co-ordinate position (y,x).

输出:

图像在位置(321, 308)的蓝绿红组件值为:(238, 242, 253)

注意y值是如何在x值之前传递的——这种语法一开始可能感觉反直觉,但它与我们访问矩阵中值的方式一致:首先指定行号,然后是列号。从那里,我们得到一个元组,代表图像的蓝色、绿色和红色组件。

我们也可以通过反转操作来改变给定位置像素的颜色。

Python

 

#在(x,y)位置查找图像的R、B、G

import cv2
import argparse

apr = argparse.ArgumentParser()
apr.add_argument(“-i”, “ — image”, required=True, help=”Path to the image”)
args = vars(apr.parse_args())

image = cv2.imread(args[“image”])

#从用户接收像素坐标值[y,x],需要计算RGB值
[y,x] = list(int(x.strip()) for x in input().split(‘,’))

#提取接收像素坐标的(蓝,绿,红)值
(b,g,r) = image[y,x]
print(f’The Blue Green Red component value of the image at position {(y,x)} is: {(b,g,r)}’)

cv2.imshow(‘Image’, image)
cv2.waitKey(0)

(b,g,r) = image[y,x] 轉換為 image[y,x] = (b,g,r)

在此,我們將(BGR)顏色分配給圖像像素坐標。嘗試將紅色分配給位置(321,308)的像素,並通過打印該位置的像素BGR來驗證這一點。

Python

 

#反轉操作以將RGB值分配給我們選擇的像素

import cv2
import argparse

apr = argparse.ArgumentParser()
apr.add_argument(“-i”, “ — image”, required=True, help=”Path to the image”)
args = vars(apr.parse_args())

image = cv2.imread(args[“image”])

#從用戶接收像素坐標值[y,x],以計算RGB值
[y,x] = list(int(x.strip()) for x in input().split(‘,’))

#提取接收像素坐標的(藍色,綠色,紅色)值
image[y,x] = (0,0,255)
(b,g,r) = image[y,x]
print(f’The Blue Green Red component value of the image at position {(y,x)} is: {(b,g,r)}’)

cv2.imshow(‘Image’, image)
cv2.waitKey(0)

輸出:

圖像在位置(321, 308)的藍色、綠色和紅色成分值為(0, 0, 255)

在上述代碼中,我們通過命令提示符輸入值來接收像素坐標,如圖2.6所示,並通過分配(0,0,255)即(藍色,綠色,紅色)將紅色分配給像素坐標,並通過打印輸入像素坐標來驗證這一點。

使用OpenCV繪圖

讓我們學習如何使用OpenCV繪製不同形狀,如矩形、正方形和圓形,通過繪製圓形來遮蓋我的眼睛,矩形來遮蓋我的嘴唇,以及矩形來遮蓋我旁邊的mantra-ray魚。

輸出應該如下所示:

Fig 2.6 Masked Photo of me with the mantra-ray fish.

這張照片使用MS Paint遮蓋了形狀;我們將嘗試使用OpenCV通過在我的眼睛周圍繪製圓形和用矩形遮蓋我的嘴唇及旁邊的mantra-ray魚來實現相同效果。

我們使用cv2.rectangle方法在OpenCV中繪製矩形,使用cv2.circle方法繪製圓形。

cv2.rectangle(image, (x1, y1), (x2, y2), (Blue, Green, Red), Thickness)

cv2.rectangle 方法的第一個參數是欲繪製矩形的圖像。由於我們想在已載入的圖像物件上繪製,因此將其傳入該方法。第二個參數是矩形的起始(x1, y1)位置,在此,我們從(156, 340)點開始繪製矩形。接著,必須提供矩形的終止(x2, y2)點,我們決定在(360, 450)結束矩形。下一個參數是欲繪製矩形的顏色;在此例中,我們以BGR格式傳入黑色,即(0,0,0)。最後,傳入的參數是線條的粗細,我們給予-1以繪製實心形狀,如圖2.6所示。

同樣地,我們使用cv2.circle方法來繪製圓形。

cv2.circle(image, (x, y), r, (Blue, Green, Red), Thickness)

cv2.circle方法的第一個參數是欲繪製圓形的圖像。由於我們想在已載入的圖像物件上繪製,因此將其傳入該方法。第二個參數是圓心的(x, y)位置,在此,我們選擇在(343, 243)點繪製圓形。接著的參數是欲繪製圓形的半徑。下一個參數是圓形的顏色;在此例中,我們以BGR格式傳入紅色,即(0,0,255)。最後,傳入的參數是線條的粗細,我們給予-1以繪製實心形狀,如圖2.6所示。

好的!了解這些後,讓我們嘗試完成我們的目標。要繪製圖像中的形狀,我們需要確定遮罩區域的起始和結束(x,y)坐標,以便將其傳遞給相應的方法。

如何做?

我們將再次借助MS Paint。通過將光標放置在遮罩區域的任一坐標(左上角或右下角)上,坐標會在MS Paint的高亮部分顯示,如圖2.7所示。

Fig 2.7 MSPaint to find the co-ordinates of the masking region.

同樣地,我們將獲取所有遮罩區域的坐標(x1,y1)(x2,y2),如圖2.8所示。

Fig 2.8 (x.y) Co-ordinates of masking regions.

Python

 

#使用OpenCV繪製以遮罩眼睛、嘴巴及附近物體

import cv2
import argparse

apr = argparse.ArgumentParser()
apr.add_argument(“-i”, “ — image”, required=True, help=”Path to the image”)
args = vars(apr.parse_args())

image = cv2.imread(args[“image”])

cv2.rectangle(image, (415, 168), (471, 191), (0, 0, 255), -1)
cv2.circle(image, (425, 150), 15, (0, 0, 255), -1)
cv2.circle(image, (457, 154), 15, (0, 0, 255), -1)
cv2.rectangle(image, (156, 340), (360, 450), (0, 0, 0), -1)

#顯示輸出圖像
cv2.imshow(“Output drawing “, image)
cv2.waitKey(0)

結果:



Fig 2.9 Desired Output.

Source:
https://dzone.com/articles/computer-vision-tutorial-2-image-basics