參考文章:
- [常用工具] OpenCV獲取網(wǎng)絡(luò)攝像頭實時視頻流_opencv網(wǎng)絡(luò)攝像頭
- [常用工具] OpenCV獲取網(wǎng)絡(luò)攝像頭實時視頻流_opencv網(wǎng)絡(luò)攝像頭_落痕的寒假的博客-CSDN博客
方式一: 使用VideoCapture讀取視頻流
在使用OpenCv處理視頻時,無論是視頻文件還是攝像頭畫面,都要使用VideoCapture類來進行每一幀圖像的處理。當我們使用視頻文件作為參數(shù)時,OpenCv則打開視頻文件,進行每一幀畫面的讀取。當我們傳遞攝像機編號時,OpenCv則打開相機,實時讀取相機畫面。
獲取VideoCaptrue實例:
# 讀取視頻文件
cv2.VideoCapture('video.mp4')
# 打開攝像機
cv2.VideoCapture(0)
使用VideoCapture讀取??礡TSP流
RTSP流
在使用OpenCv進行計算機視覺處理時,我們很多時候需要連接外部相機,如??低?。監(jiān)控相機的常見視頻傳輸協(xié)議有:RTSP、RTMP(以RTSP為主)
RTSP與RTMP比較:
- ??? RTSP:低時延,實現(xiàn)難度大,適合視頻聊天和視頻監(jiān)控
- ??? RTMP:低時延,實現(xiàn)難度大,適合視頻聊天和視頻監(jiān)控
目前市面上的相機大多以RTSP流協(xié)議為主。
在讀取海康相機時,需要使用VideoCapture讀取RTSP流協(xié)議的內(nèi)容,而不是通過相機編號直接讀取。
"""
??迪鄼Crtsp格式:rtsp://[username]:[password]@[ip]:[port]/[codec]/[channel]/[subtype]/av_stream
username: 用戶名。例如admin。
password: 密碼。例如12345。
ip: 為設(shè)備IP。例如 192.0.0.64。
port: 端口號默認為554,若為默認可不填寫。
codec:有h264、MPEG-4、mpeg4這幾種。
channel: 通道號,起始為1。例如通道1,則為ch1。
subtype: 碼流類型,主碼流為main,輔碼流為sub。
"""
使用VideoCapture讀取RTSP流示例:
# 使用rtsp流打開相機
def open_camera(username: str, password: str, ip: str, port: int):
"""
使用rtsp流打開相機
rtsp格式:rtsp://[username]:[password]@[ip]:[port]/[codec]/[channel]/[subtype]/av_stream
username: 用戶名。例如admin。
password: 密碼。例如12345。
ip: 為設(shè)備IP。例如 192.0.0.64。
port: 端口號默認為554,若為默認可不填寫。
codec:有h264、MPEG-4、mpeg4這幾種。
channel: 通道號,起始為1。例如通道1,則為ch1。
subtype: 碼流類型,主碼流為main,輔碼流為sub。
:return:相機是否打開,相機
"""
try:
# 使用rtsp流打開相機
cam = cv2.VideoCapture(f'rtsp://{username}:{password}@{ip}:{port}/h264/ch1/main/av_stream')
return True, cam
except cv2.error:
# 捕獲cv異常
# 打開相機失敗
return False, None
優(yōu)化后代碼:
import queue
import threading
import cv2
class CameraThread(threading.Thread):
# 保存實例化相機,通過實例化相機操作相機
camera = None
# 保存每一幀從rtsp流中讀取到的畫面
queue_image = queue.Queue(maxsize=10)
# 線程體是否循環(huán)執(zhí)行標志
flag_run = False
# 相機線程調(diào)用函數(shù)
def run(self) -> None:
while self.flag_run:
try:
# 捕獲異常,避免讀取視頻操作因異常而退出
# 相機實例存在,判斷相機是否打開
if self.camera.is_opened():
# 相機已打開,讀取相機內(nèi)容
ret, frame = self.camera.read()
if not ret or frame is None:
# 讀取相機內(nèi)容失敗
break
if ret:
# 將內(nèi)容添加到隊列中
# 判斷隊列是否滿
if self.queue_image.full():
# 隊列滿,隊頭出隊
self.queue_image.get()
# 隊尾添加數(shù)據(jù)
self.queue_image.put(frame)
else:
# 隊尾添加數(shù)據(jù)
self.queue_image.put(frame)
except cv2.error as error:
# 捕獲cv異常
# 因為子線程會一直調(diào)用該程序,可對捕獲到的異常不進行處理
print(error)
pass
except Exception as error:
# 捕獲Exception異常
print(error)
pass
# setter:設(shè)置相機的camera對象
def set_camera(self, camera):
"""
設(shè)置相機的camera對象
"""
# 設(shè)置相機的camera
self.camera = camera
# 獲取隊列中的RGB圖像
def get_image(self):
"""
獲取隊列中的RGB圖像
:return: img: RGB圖像
"""
# 讀取隊列中的圖片
img = self.queue_image.get()
# img為None,讀取失敗,隊列還未獲取到圖片
while img is None:
# 一直讀取圖片,直到讀取圖片成功
img = self.queue_image.get()
# 返回讀取到的內(nèi)容
return img
# 停止運行
def run_stop(self):
self.flag_run = False
# 開始運行
def run_start(self):
self.flag_run = True
方式二: 所需要硬件及軟件環(huán)境:
python 3/OpenCV3.4 or C++11/OpenCV3.4
1 RTSP協(xié)議
RTSP (Real Time Streaming Protocol),是一種語法和操作類似 HTTP 協(xié)議,專門用于音頻和視頻的應(yīng)用層協(xié)議。 和 HTTP 類似,RTSP 也使用 URL 地址。同時我們也要了解到攝像機傳輸數(shù)據(jù)用的是碼流,高清網(wǎng)絡(luò)攝像機產(chǎn)品編碼器都會產(chǎn)生兩個編碼格式,稱為主碼流和子碼流。這就叫雙碼流技術(shù)。目的是用于解決監(jiān)控錄像的本地存儲和網(wǎng)絡(luò)傳輸?shù)膱D像的質(zhì)量問題。雙碼流能實現(xiàn)本地和遠程傳輸?shù)膬煞N不同的帶寬碼流需求,本地傳輸可以用主碼流,能獲得更清晰的存儲錄像,遠程傳輸就因為帶寬限制的原因,而使用子碼流來獲得流暢的圖像和錄像。通過RTSP協(xié)議傳輸不同的碼流,但是各大攝像頭廠家的RTSP協(xié)議地址不大一樣。通常你只要知道攝像頭IP地址,用戶名密碼就行了。
??档腞TSP協(xié)議地址如下:
rtsp://[username]:[password]@[ip]:[port]/[codec]/[channel]/[subtype]/av_stream
1) username 用戶名,常用 admin
2) password 密碼,常用 12345
3) ip 攝像頭IP,如 192.0.0.64
4) port 端口號,默認為 554,可以不寫
5) codec 視頻編碼模式,有 h264、MPEG-4、mpeg4 等,可以不寫
6) channel 通道號,起始為1,例如通道1,則為 ch1
7) subtype 碼流類型,主碼流為 main,輔碼流為 sub
大華的RTSP協(xié)議地址如下:?
rtsp://[username]:[password]@[ip]:[port]/cam/realmonitor?[channel=1]&[subtype=1]
1) username、password、ip、port 同上
2) channel 通道號,起始為1,例如通道2,則為 channel=2
3) subtype 碼流類型,主碼流為0(即 subtype=0),輔碼流為1(即 subtype=1)
宇視的RTSP協(xié)議地址如下:
rtsp://{用戶名}:{密碼}@{ip}:{port}/video1/2/3,
1)video1/2/3表示主碼流,子碼流,三碼流(可以不用)
2)其他一樣
2 OpenCV中讀取網(wǎng)絡(luò)攝像頭
OpenCV讀取網(wǎng)絡(luò)攝像頭很簡單,直接用url設(shè)定rtsp地址,用VideoCapture讀取視頻就行了。但是RTSP有些許問題,所以在最后通過TCP傳輸協(xié)議上承載RTSP,保證穩(wěn)定性。就在rtsp地址后面加?tcp
String url = "rtsp://admin:123456@114.114.114.114/ch1-s1?tcp";
//??? //"rtsp://admin:123456@114.114.114.114/ch1-s1?tcp"
//大華
//“rtsp://admin:123456@114.114.114.114/cam/realmonitor?channel=1&subtype=1?tcp”
//宇視
//"rtsp://admin:123456@114.114.114.114/video1?tcp"
VideoCapture cap(url);
Mat frame;
cap>>frame;
但是直接按上面的方法來讀取視頻,會出問題,通常都是error while decoding,讀不了碼流,也就是讀到一半就失敗。這個會導(dǎo)致程序異常。
這是由于OpenCV中FFMPEG Lib對在rtsp協(xié)議中的H264 vidos不支持或者OpenCV版本太低,所以處理辦法就是自己寫兩個不同的線程單獨去處理接收每一幀的圖像,然后另一個線程處理這每一幀的圖像。思路如下:使用隊列,基于pthread類采取先入先出策略,在一個線程中開始接收數(shù)據(jù),在另一個線程中處理逐幀數(shù)據(jù)。
這樣就可以實時獲得網(wǎng)絡(luò)攝像頭數(shù)據(jù)啦,獲得Mat格式圖像,具體代碼如下:
?C++代碼:
?文章來源:http://www.zghlxwxcb.cn/news/detail-428111.html
//并行
#include <thread>
//互斥訪問
#include <mutex>
//是否打開視頻
bool captureOpen = false;
//讀取的每張圖像
Mat image;
VideoCapture capture;
//網(wǎng)絡(luò)鏈接地址
String url = "rtsp://admin:123456@114.114.114.114/ch1-s1?tcp";
//加鎖器
mutex mtx;
//是否讀圖成功
bool imgready = false;
/**
* @brief 讀圖
*
* @return Mat
*/
Mat captureThread()
{
if (captureOpen == false || image.empty())
{
//打開圖像
capture.open(url);
}
while (1)
{
//加鎖
mtx.lock();
capture >> image;
//讀圖成功
imgready = true;
//解鎖
mtx.unlock();
return image;
}
}
/**
* @brief 處理函數(shù)
*
* @param image 輸入圖像
*/
void processingThread(Mat image)
{
//如果讀圖成功
if (imgready)
{
//如果圖像為空
if (image.empty())
{
return;
}
mtx.lock();
//你的處理函數(shù)
//your function
mtx.unlock();
return;
}
}
int main()
{
//讀圖
thread t1(captureThread);
t1.join();
//已經(jīng)讀圖
captureOpen = true;
//并行處理
thread t2(processingThread, image);
t2.join();
return 0;
}
Python代碼:文章來源地址http://www.zghlxwxcb.cn/news/detail-428111.html
import cv2
import queue
import time
import threading
q=queue.Queue()
def Receive():
print("start Reveive")
cap = cv2.VideoCapture("rtsp://admin:admin_123@172.0.0.0")
ret, frame = cap.read()
q.put(frame)
while ret:
ret, frame = cap.read()
q.put(frame)
def Display():
print("Start Displaying")
while True:
if q.empty() !=True:
frame=q.get()
cv2.imshow("frame1", frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
if __name__=='__main__':
p1=threading.Thread(target=Receive)
p2 = threading.Thread(target=Display)
p1.start()
p2.start()
到了這里,關(guān)于OpenCV獲取網(wǎng)絡(luò)攝像頭實時視頻流的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!