項目實戰-可變色畫布¶
概要¶
阿凱帶你從創建一個特定灰度的灰度圖, 到終端輸入灰度的值生成特定灰度的圖片, 然后我們引入了一個新的HighGui組件:Trackbar . 你還會接觸到回調函數(callback)這個概念, 用于響應Trackbar 拖動帶來的影響。
你可以拖動滑條, 動態的看到色塊顏色的改變, 最后阿凱給大家留了一個作業, 制作RGB三通道的帶Trackbar的調色板。
keywords highgui 可變色 畫布 RGB Trackbar
1. 創建統一灰度畫布的函數¶
本期相當于是對CH2.1
作業的解析.
我們創建一個函數createGrayscaleCanvas
用于創建灰度圖的畫布.
CH2.2_GrayCanvas.py
import numpy as np import cv2 # 初始化灰度圖的畫布 def createGrayscaleCanvas(width, height, color=255): canvas = np.ones((height, width), dtype="uint8") canvas[:] = color return canvas # 創建一個顏色為125的灰度圖 canvas = createGrayscaleCanvas(500, 500, color=125) # 展示畫布 cv2.imshow("canvas", canvas) # 中斷 cv2.waitKey(0) # 關閉窗口 cv2.destroyAllWindows()
這里只是做一個課程回顧.
2. 終端輸入灰度 生成灰度圖¶
接下來, 阿凱想通過終端輸入一個特定的數值, 然后生成對應值的灰度圖, 那我們如何來實現呢?
在python中, 類似C語言中的scanf
語句的函數是input
, input
中傳入的字符串是提示.
讀入字符串賦值給gray_value
. 注意這里讀入的是字符串, 不是數值
gvalue_str = input("請輸入灰度值: ")
如果我們想得到整數的數值的話, 需要對其進行強制類型轉換. 使用int()
函數.
gvalue = int(gvalue_str)
接下來, 我們還要判斷, 數值范圍是否合法, 在[0, 255] 區間之內.
我們使用函數is_gvalue_legal
來判斷灰度值是否合法.
# 判斷灰度值是否合法 def is_gvalue_legal(gvalue): return not (gvalue < 0 or gvalue > 255)
如果啰嗦一點的版本, 就是這樣的:
# 判斷灰度值是否合法 def is_gvalue_legal_balabala(gvalue): if gvalue < 0 or gvalue > 255: return False else: return True
讀入gvalue , 如果符合要求的話, 就生成對應的背景. 不合法就要求重新輸入.
# 讀入灰度值 def read_gvalue(): # 是否讀取成功 read_done = False gvalue = None while not read_done: gvalue_str = input("請輸入灰度值: ") gvalue = int(gvalue_str) read_done = is_gvalue_legal(gvalue) # 添加一個溫馨小提示 if not read_done: print("溫馨提示, 數值范圍越界, 灰度圖取值范圍在0到255區間") return gvalue
完整版本的程序見:
CH2.2_GrayCanvasInputFromTerm.py
import numpy as np import cv2 # 初始化灰度圖的畫布 def createGrayscaleCanvas(width, height, color=255): canvas = np.ones((height, width), dtype="uint8") canvas[:] = color return canvas # 判斷灰度值是否合法 def is_gvalue_legal(gvalue): return not (gvalue < 0 or gvalue > 255) # 讀入灰度值 # 如果符合要求的話, 就生成對應的背景. 不合法就要求重新輸入. def read_gvalue(): # 是否讀取成功 read_done = False gvalue = None while not read_done: gvalue_str = input("請輸入灰度值: ") gvalue = int(gvalue_str) read_done = is_gvalue_legal(gvalue) if not read_done: print("溫馨提示, 數值范圍越界, 灰度圖取值范圍在0到255區間") return gvalue gvalue = read_gvalue() canvas = createGrayscaleCanvas(500, 500, color=gvalue) cv2.imshow("canvas", canvas) print("按任意按鍵結束程序") cv2.waitKey(0) cv2.destroyAllWindows()
效果演示
3. 創建滑條-ceateTrackBar¶
用終端的方式, 也有它的弊端, 主要是我沒辦法從交互界面上去規范它輸入的值.
于是我們就用到了我們的TrackBar
組件.
首先我們需要創建一個Trackbar
, 調用createTrackbar
這個函數
cv2.createTrackbar(trackbar_name,window_name,min_value,max_value,callback_func)
依次傳入的函數
-
trackbar_name
滑條的名稱,獲取這個滑條的數值也是通過名稱 -
window_name
滑條所在窗口 (window) 的名稱 -
min_value
滑條最小值 -
max_value
滑條最大值 -
callback_func
回調函數,這個參數其實類似C
語言中的函數指針,我傳入的是函數名稱,每次滑條被拖動的時候,都會執行這個函數.
例如:
# 這個nothing的意思就是啥也不做。 def nothing(x): pass cv2.createTrackbar('gray_value','image',0,255,nothing)
這里的nothing(x)
, 被傳入的x
實際上是滑條的當前取值。
你也可以改成這樣, 看一下x
的值。
# 這個nothing的意思就是啥也不做。 def nothing(x): print(x) cv2.createTrackbar('gray_value','image',0,255,nothing)
x
是我命名的值, 你可以命名為任意名稱。
4. 灰度圖調色板 - V1¶
這里, 我們來演示, 不用回調函數的解決方法。
定時每隔1ms刷新畫面, 這種方式比較低效, 即便值沒有被修改1s也會修改1000次。
CH2.2_GrayCanvasInputFromTrackBarV1.py
''' 滑塊調色板 - v1 比較傻的版本 ''' import cv2 import numpy as np # 初始化灰度圖的畫布 def createGrayscaleCanvas(width, height, color=255): canvas = np.ones((height, width), dtype="uint8") canvas[:] = color return canvas cv2.namedWindow('image') # 函數原型 # createTrackbar(trackbarName, windowName, value, count, onChange) -> None # 解釋 # 在window‘iamge’ 上創建一個滑動條,起名為Channel_XXX, 設定滑動范圍為0-255, # onChange事件回調 啥也不做 def nothing(x): pass cv2.createTrackbar('gray_value','image',0,255,nothing) print("進入Grayscale滑塊實驗, 鍵盤摁e退出程序") img = None # 每隔1ms檢查更新一次。 while(True): # 程序跳出判斷 最多等待1毫秒 k = cv2.waitKey(1) # 如果key是e鍵就退出程序 if k == ord('e'): break # 獲取當前滑條的值 gvalue = cv2.getTrackbarPos('gray_value','image') # 創建新的畫布 img = createGrayscaleCanvas(500, 500, color=gvalue) # 顯示更新后的圖片 cv2.imshow('image',img) cv2.destroyAllWindows()
5. 灰度圖調色板 - V2¶
我們首先創建一個名字叫做gray_value
的trackbar。 這個trackbar在image
窗口上。
最小取值是0, 最大取值是255, 修改時候的回調函數是updateImg
cv2.createTrackbar('gray_value','image',0,255,updateImg)
那我們來看一下updateImg
圖像更新的函數。 每次trackbar修改的時候, 就會給函數updateImg
傳入當前的值gvalue
。
然后我們創建一個新的圖片, 并在image
窗口展示。
# 更新畫布 def updateImg(gvalue): img = createGrayscaleCanvas(500, 500, color=gvalue) # 顯示更新后的圖片 cv2.imshow('image',img)
完整的程序:
CH2.2_GrayCanvasInputFromTrackBarV2.py
''' 滑塊調色板 - v2 回調函數 ''' import cv2 import numpy as np # 初始化灰度圖的畫布 def createGrayscaleCanvas(width, height, color=255): canvas = np.ones((height, width), dtype="uint8") canvas[:] = color return canvas # 更新畫布 def updateImg(gvalue): img = createGrayscaleCanvas(500, 500, color=gvalue) # 顯示更新后的圖片 cv2.imshow('image',img) cv2.namedWindow('image') # 初始化畫布 updateImg(0) cv2.createTrackbar('gray_value','image',0,255,updateImg) print("進入Grayscale滑塊實驗, 鍵盤摁e退出程序") img = None # 接收按鍵事件, 判斷是否退出 while cv2.waitKey(0) != ord('e'): continue cv2.destroyAllWindows()
6. 作業 CH2.2¶
看到這里, 相信你已經掌握了如何創建畫布與HighGUI組件中的Trackbar的使用.
那么阿凱接下來要給你布置的作業就是, 創建一個可以調RGB三通道的調色板.
你需要創建三個TrackBar, 分別記錄三個通道的值. 然后你拖動TrackBar觸發更新當前color的事件, 接下來, 重新渲染畫布. 思路就給這么多. 大家加油.
為了降低難度, 阿凱提供一個代碼模板.
CH2.2_BGRCanvasInputFromTrackBar.py
''' 滑塊調色板 - V2 利用回調更新窗口圖像 ''' import cv2 import numpy as np # 創建一個空白畫布 canvas = np.zeros((300,512,3), np.uint8) # 色塊的顏色 color = (0, 0, 0) # 更新圖像,并且刷新windows def updateImage(): ''' 請填入你的代碼 ''' # 更新顏色 def updateColor(x): ''' 請填入代碼 ''' cv2.namedWindow('image') # 函數原型 # createTrackbar(trackbarName, windowName, value, count, onChange) -> None # 解釋 # 在window‘iamge’ 上創建一個滑動條,起名為Channel_XXX, 設定滑動范圍為0-255, # onChange事件回調 啥也不做 cv2.createTrackbar('Channel_Red','image',0,255,updateColor) cv2.createTrackbar('Channel_Green','image',0,255,updateColor) cv2.createTrackbar('Channel_Blue','image',0,255,updateColor) print("進入RGB滑塊實驗, 鍵盤摁e退出程序") # 首次初始化窗口的色塊 # 后面的更新 都是由getTrackbarPos產生變化而觸發 updateImage() while cv2.waitKey(0) != ord('e'): continue cv2.destroyAllWindows()