二、OpenCV-python 之 圖像像素操作

1、像素值操作

OpenCV讀取圖像後,將其作爲numpy存儲,所以大部分的圖像計算都是numpy的工作

px = img[100,100]				# 獲取像素點(100,100)的三通道顏色值
blue = img[100,100,0]			# 獲取像素點(100,100)的藍色通道數值
img[100,100] = [255,255,255]	# 修改像素點(100,100)的三通道顏色值

img.item(10,10,2)				# 獲取像素值的高效方式
img.itemset((10,10,2),100)		# 修改像素值的高效方式

# 圖像屬性
img.shape						# 返回一個tuple,圖像的shape(行,列,通道)
img.size						# 返回圖像的像素數量,其實就是上面tuple的乘積
img.dtype						# 返回圖像像素值的類型,注意不是圖像類型

# 感興趣區域ROI
ball = img[280:340, 330:390]	# 用numpy剪裁圖像
img[273:333, 100:160] = ball	# 指定區域賦值

# 圖像通道
b,g,r = cv.split(img)			# 圖像通道分割,開銷很大,儘量不要直接用,可以的話用numpy代替
img = cv.merge((b,g,r))			# 通道合併

# 複製圖像:將圖像複製到另一目標圖像的中心
cv.copyMakeBorder(
    src,				# 源圖像
    dst,				# 目標圖像
    top,
    bottom, 
    left, 
    right,				# 目標圖像的上下左右不同方向上邊界的寬度,單位爲 px
    borderType,			# 邊界填充方式
    value				# 邊界填充值(如果填充方式是BORDER_CONSTANT)
)

2、圖像算術運算

# 圖像混合,OpenCV中的加法是一個飽和操作,到達峯值255後就處於峯值不變(numpy中超過峯值後會對峯值取餘)
cv.add(src1, src2, dst, mask, dtype)
# 加入權重後的圖像混合,dst=α⋅img1+β⋅img2+γ,
cv.addWeighted(src1, alpha, src2, beta, gamma, dst, dtype)

這裏給出一個圖像位操作的實例,目標是將一張圖像的一個logo摳出來,放到另一張圖像中(指定像素位置的替換操作)。不能直接用加法,因爲會改變像素的值;也不能用混合,會產生透明度。
像素級別的替換操作的思路是:先得到ROI-logo的掩碼,然後摳出logo,將目標位置掏空,然後做加法操作。

# Load two images
img1 = cv.imread('target.jpg')
img2 = cv.imread('logo.png')

# I want to put logo on top-left corner, So I create a ROI
rows, cols, channels = img2.shape
roi = img1[0:rows, 0:cols]

# Now create a mask of logo and create its inverse mask also
img2gray = cv.cvtColor(img2,cv.COLOR_BGR2GRAY)
ret, mask = cv.threshold(img2gray, 10, 255, cv.THRESH_BINARY)       # 置爲二值圖,大於閾值置爲255(白),用於得到logo(非logo位置全爲0)
mask_inv = cv.bitwise_not(mask)                                     # mask反轉,與logo對應的位置爲0(給logo留出位置)

# Now black-out the area of logo in ROI
img1_bg = cv.bitwise_and(roi, roi, mask = mask_inv)                 # 目標圖像中與logo對應的位置騰出來
# Take only region of logo from logo image.
img2_fg = cv.bitwise_and(img2, img2, mask = mask)                   # 像素與操作,根據mask摳出logo

# Put logo in ROI and modify the main image
dst = cv.add(img1_bg,img2_fg)                                       # 相加,注意這裏 ROI 的logo位置已經被掏空了(均爲0),直接相加不會改變logo像素值
img1[0:rows, 0:cols ] = dst                                         # 合併到目標圖像

cv.imshow('res',img1)
cv.waitKey(0)
cv.destroyAllWindows()

cv.bitwise_and(img1, img2,mask)
像素與操作,三個參數的尺寸是一樣的,mask中爲0的位置在輸出圖像中也爲0,非0位置在輸出圖像中的像素值是img1、img2對應位置像素的與操作(這其實就是摳圖)。

最終的效果如下(左邊是logo掩碼):

在這裏插入圖片描述

3、處理性能與優化

OpenCV中對圖像處理、像素計算等做了很多優化(例如SSE2、AVX等),優化開啓與否直接影響到程序執行的性能;它也提供了一些監測模塊(例如time)來幫助觀測代碼的性能。

time 模塊:可以給出代碼執行所耗時間;
profile 模塊:可以給出代碼執行的詳細報告,例如函數佔用的時間、調用次數等。

# 時間監測
e1 = cv.getTickCount()						# 返回在一個引用事件(例如程序開始運行的時刻)之後到調用此函數的時刻的時鐘週期數,其實就是這個時候的時間點
### your code execution ###
e2 = cv.getTickCount()
time = (e2 - e1)/ cv.getTickFrequency()		# cv.getTickFrequency()返回時鐘週期的頻率,或每秒時鐘週期的數量。

# 優化處理
cv.useOptimized()							# 查看是否開啓優化
cv.setUseOptimized(False)					# 設置是否開啓優化,True爲啓動,False爲關閉

通常情況下,OpenCV的處理速度比numpy快得多,所以相同的操作儘量用OpenCV來實現(當然,這也並不是絕對的)。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章