本系列專欄寫作方式
本系列專欄寫作將采用首創(chuàng)的問(wèn)答式寫作形式墓陈,快速讓你學(xué)習(xí)到 OpenCV 的初級(jí)恶守、中級(jí)第献、高級(jí)知識(shí)。
5. Python OpenCV 中滑動(dòng)條詳細(xì)說(shuō)明與常見問(wèn)題解決方案
滑動(dòng)條在 OpenCV 相關(guān)案例中使用場(chǎng)景非常豐富兔港,很多時(shí)候都需要借助于滑動(dòng)條進(jìn)行相關(guān)參數(shù)的獲取庸毫。
掌握滑動(dòng)條,只需要掌握 <kbd>cv2.createTrackbar</kbd> 與 <kbd>cv2.getTrackbarPos</kbd> 兩個(gè)函數(shù)即可押框。
以上兩個(gè)函數(shù)的原型橡伞,可以直接通過(guò) help 函數(shù)查閱,本系列專欄對(duì)于函數(shù)原型只做簡(jiǎn)單說(shuō)明
createTrackbar(trackbarName, windowName, value, count, onChange) -> None
getTrackbarPos(trackbarname, winname) -> retval
其中 <kbd>cv2.createTrackbar</kbd> 函數(shù)參數(shù)豐富一些崭闲,<kbd>cv2.getTrackbarPos</kbd> 函數(shù)是其子級(jí)。
接下來(lái)通過(guò)一個(gè)簡(jiǎn)單的案例,實(shí)現(xiàn)滑動(dòng)條的基本應(yīng)用,拖動(dòng)改變窗口中某矩形的顏色。
import cv2
import numpy as np
cv2.namedWindow("Trackbar_Demo", cv2.WINDOW_NORMAL)
# 為了在滑動(dòng)條中參數(shù)位置進(jìn)行占位
def nothing():
pass
ret = np.zeros([512, 512, 3], np.uint8)
# 創(chuàng)建一個(gè)滑動(dòng)條
cv2.createTrackbar("color_green", "Trackbar_Demo", 0, 255, nothing)
while 1:
# 獲取滑動(dòng)條的取值
color_green = cv2.getTrackbarPos("color_green", "Trackbar_Demo")
cv2.rectangle(ret, (100, 100), (200, 200), (0, color_green, 0), -1)
cv2.imshow("Trackbar_Demo", ret)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cv2.destroyAllWindows()
如果在代碼編寫過(guò)程中出現(xiàn)了如下 BUG,缺少參數(shù):
TypeError: function takes exactly 5 arguments (4 given)
該 BUG 表示 <kbd>cv2.createTrackbar</kbd> 函數(shù)中缺少了最后一個(gè) <kbd>onChange</kbd> 參數(shù),添加該參數(shù)即可弱左,參數(shù)指向的函數(shù)體可以為空们镜。
代碼運(yùn)行之后的動(dòng)圖效果如下:
<kbd>cv2.createTrackbar</kbd> 函數(shù)中 onChange 參數(shù)相關(guān)問(wèn)題解決方案
在互聯(lián)網(wǎng)上所有的中文資料中進(jìn)行檢索,會(huì)發(fā)現(xiàn)有一個(gè)知識(shí)點(diǎn)在 <kbd>cv2.createTrackbar</kbd> 函數(shù)的應(yīng)用中經(jīng)常被忽略褐鸥,這個(gè)內(nèi)容就是 <kbd>onChange</kbd> 參數(shù)翠霍,該參數(shù)的官方說(shuō)明如下:
Pointer to the function to be called every time the slider changes position. This function should be prototyped as
void Foo(int,void*);
, where the first parameter is the trackbar position and the second parameter is the user data (see the next parameter). If the callback is the NULL pointer, no callbacks are called, but onlyvalue
is updated.
這里要注意一個(gè)細(xì)節(jié)的地方,在 OpenCV C++ 編寫的時(shí)候,這個(gè)函數(shù)里面多一個(gè)參數(shù)掸鹅,叫做 <kbd>userdata</kbd> ,也就是說(shuō) C++ 中此函數(shù)的原型如下:
int createTrackbar(const String& trackbarname, const String& winname, int* value, int count, TrackbarCallback onChange=0, void* userdata=0)
但是 Python 對(duì)其進(jìn)行了整合削咆,通過(guò)一個(gè)參數(shù)完成兩個(gè)數(shù)據(jù)值的操作炊邦,這樣其實(shí)我們?cè)谶M(jìn)行每一次拖動(dòng)滑動(dòng)條的時(shí)候碘菜,都可以對(duì)其進(jìn)行相應(yīng)的操作计雌。
修改代碼如下,篇幅關(guān)系恬口,只修改 <kbd>nothing</kbd> 函數(shù)部分钞螟,運(yùn)行代碼會(huì)出現(xiàn)下圖所示內(nèi)容:
# 滑動(dòng)條每步的回調(diào)函數(shù)
def nothing(x):
print("滑動(dòng)條進(jìn)行操作")
print(x)
[圖片上傳失敗...(image-81b869-1640564856488)]
)
甚至我可以直接調(diào)整代碼邏輯褒链,將繪制矩形的操作放到滾動(dòng)條的回調(diào)函數(shù)中恍箭,具體代碼與說(shuō)明如下:
import cv2
import numpy as np
cv2.namedWindow("Trackbar_Demo", cv2.WINDOW_NORMAL)
# 滑動(dòng)條每步的回調(diào)函數(shù)
def nothing(x):
print("滑動(dòng)條進(jìn)行操作")
cv2.rectangle(ret, (100, 100), (200, 200), (0, x, 0), -1)
ret = np.zeros([512, 512, 3], np.uint8)
# 創(chuàng)建一個(gè)滑動(dòng)條
cv2.createTrackbar("color_green", "Trackbar_Demo", 0, 255, nothing)
# color_green = cv2.getTrackbarPos("color_green", "Trackbar_Demo")
while True:
cv2.imshow("Trackbar_Demo", ret)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cv2.destroyAllWindows()
這種邏輯具備之后,我們就可以將滑動(dòng)條設(shè)計(jì)成一個(gè)開關(guān)伍掀,拖動(dòng)到不同值县好,可以呈現(xiàn)不同的效果缕贡。
更多細(xì)節(jié),可以繼續(xù)取閱讀手冊(cè)相關(guān)內(nèi)容剂跟,訪問(wèn)地址
OpenCV 中拆分滑動(dòng)條與圖片窗口
在實(shí)際編碼過(guò)程中辽剧,建議將滑動(dòng)條窗口與圖片窗口進(jìn)行拆分展示阐斜,便于調(diào)整各參數(shù)为居。
例如下面一個(gè)手動(dòng)調(diào)參實(shí)現(xiàn)二值化的操作(后續(xù)文章會(huì)涉及到)。
import cv2
import numpy as np
def nothing(a):
pass
cv2.namedWindow("HSV",cv2.WINDOW_AUTOSIZE)
cv2.createTrackbar("HUE Min", "HSV", 0, 255, nothing)
cv2.createTrackbar("HUE Max", "HSV", 180, 255, nothing)
cv2.createTrackbar("SAT Min", "HSV", 255, 255, nothing)
cv2.createTrackbar("SAT Max", "HSV", 43, 255, nothing)
cv2.createTrackbar("VALUE Min", "HSV", 255, 255, nothing)
cv2.createTrackbar("VALUE Max", "HSV", 46, 255, nothing)
while True:
img = cv2.imread("./t1.jpg")
imgHsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
h_min = cv2.getTrackbarPos("HUE Min", "HSV")
h_max = cv2.getTrackbarPos("HUE Max", "HSV")
s_min = cv2.getTrackbarPos("SAT Min", "HSV")
s_max = cv2.getTrackbarPos("SAT Max", "HSV")
v_min = cv2.getTrackbarPos("VALUE Min", "HSV")
v_max = cv2.getTrackbarPos("VALUE Max", "HSV")
lower = np.array([h_min, s_min, v_min])
upper = np.array([h_max, s_max, v_max])
mask = cv2.inRange(imgHsv, lower, upper)
result = cv2.bitwise_and(img, img, mask=mask)
mask = cv2.cvtColor(mask, cv2.COLOR_GRAY2BGR)
hStack = np.hstack([img, mask, result])
cv2.imshow('Horizontal Stacking', hStack)
if cv2.waitKey(1) & 0xFF == 27:
break
cv2.destroyAllWindows()
以上代碼運(yùn)行之后,會(huì)呈現(xiàn)一種非常便捷的操作嘉熊,拖動(dòng)一個(gè)窗口遥赚,在另一個(gè)窗口中可以動(dòng)態(tài)的呈現(xiàn)對(duì)應(yīng)變化。
這個(gè)地方編碼的時(shí)候有一個(gè)注意事項(xiàng)阐肤,即 <kbd>cv2.namedWindow("HSV", cv2.WINDOW_AUTOSIZE)</kbd> 函數(shù)部分凫佛,請(qǐng)使用 <kbd>cv2.WINDOW_AUTOSIZE</kbd> 值,如果不使用該值孕惜,很容易造成滑動(dòng)條窗口亂版的情況愧薛,或者窗口參數(shù)分布不均勻情況。
最后再次強(qiáng)調(diào)滑動(dòng)條的另一個(gè)作用衫画,轉(zhuǎn)換按鈕毫炉。畢竟在 OpenCV 中不存在按鈕函數(shù),使用帶有固定值的滑動(dòng)條可以有效的解決該問(wèn)題削罩。
使用代碼如下所示即可:
cv2.createTrackbar(switch,'image',0,1,nothing)
果不使用該值瞄勾,很容易造成滑動(dòng)條窗口亂版的情況,或者窗口參數(shù)分布不均勻情況弥激。
最后再次強(qiáng)調(diào)滑動(dòng)條的另一個(gè)作用进陡,轉(zhuǎn)換按鈕。畢竟在 OpenCV 中不存在按鈕函數(shù)秆撮,使用帶有固定值的滑動(dòng)條可以有效的解決該問(wèn)題四濒。
使用代碼如下所示即可:
```python
cv2.createTrackbar(switch,'image',0,1,nothing)