调用IP摄像头
电脑没有摄像头,想着使用手机链接到电脑上使用OpenCV。首先下载APP,直接搜索IP 摄像头
,找到图标如下图的:
打开软件,点击右上方的设置,找到用户名
和密码
,默认分别是admin
和12345
,可以按照自己需要修改,也可以不修改,使用默认的。
然后点击下方的打开IP摄像头服务器。
然后在下一个页面中将RTSP勾上,可以看到相关链接地址:
这个时候,手机端就操作好了。
打开电脑端写一个Python脚本:
import cv2
"""
这里的链接是在手机上的`rtsp://10.66.208.227:8554/live`的基础上还有用户名和密码
用户名默认为admin, 密码默认为12345, 如果有修改就填写修改后的值。
"""
vid = cv2.VideoCapture('rtsp://admin:12345@10.66.208.227:8554/live')
while True:
rst, frame = vid.read()
if rst:
cv2.imshow('Phone', frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
这样就可以看到已经弹出cv2的窗口了,里面显示的就是手机摄像头的内容。
数据积压问题
在调用摄像头时候,在进行数据操作后,由于操作需要一定的时间花费,导致了数据积压得越来越多,造成程序卡死或者数据非常缓慢。这里实现了一种方式,新建了一个线程的类,一直在获取最新一帧的数据,然后在使用过程中,一直都只使用最新的一帧数据来进行操作,这样数据就不会积压起来。
python示例代码
class CameraBufferCleanerThread(threading.Thread):
def __init__(self, camera, name='camera-buffer-clear-thread'):
self.camera = camera
self.last_frame = None
super(CameraBufferCleanerThread, self).__init__(name=name)
self.start()
def run(self):
while True:
ret, self.last_frame = self.camera.read()
camera = cv2.VideoCapture('rtsp://admin:12345@10.66.208.227:8554/live')
# Start the cleaning thread
cam_cleaner = CameraBufferCleanerThread(camera)
# Use the frame whenever you want
while True:
if cam_cleaner.last_frame is not None:
# DO SOMETHING CODE
cv2.imshow('The last frame', cam_cleaner.last_frame)
cv2.waitKey(10)
C++示例代码
C++版本的代码经过尝试在4.5.0版本中测试成功。需要OpenCV编译的时候支持了ffmpeg
,否则ret = cap.read(data)
的代码读取数据始终为空。
#include "stdafx.h"
#include <iostream>
#include <thread>
#include <atomic>
#include <opencv2\opencv.hpp>
static std::atomic_bool isOpen; // 用于记录视频源是否打开的状态,atomic_数据类型,用于多线程的数据类型,可以不用使用mutex数据安全锁
/*
*************************************************************************************
*func: 刷新视频流的最后一帧到data
*@Param:std::string s,视频源,为IP摄像机地址,若为USB相机需要修改数据类型为int,传入0/1/2等
*@Param: bool &ret,视频流读取状态值,数据将会在主线程使用
*@Param: cv::Mat &data,视屏流的数据
*@Return: None
*@Note:
*creator:busy
*datetime:2021-07-06
*************************************************************************************
*/
void videoFresher(std::string s, bool &ret, cv::Mat &data)
{
cv::VideoCapture cap(s);
while (true)
{
ret = cap.read(data);
cv::waitKey(1);
if (!ret)
{
break;
}
}
cap.release();
isOpen = false;
}
int main(int argc, char* argv[])
{
std::string source="rtsp://admin:12345@10.66.211.9:8554/live";
bool status = false;
isOpen = true;
cv::Mat last_frame;
// 创建一个读取最新数据的线程
std::thread thrd(videoFresher, source, std::ref(status), std::ref(last_frame));
// 开启线程
thrd.detach();
while (true)
{
// 若检查到数据流已经关闭,则结束主线程的循环
if (!isOpen)
{
break;
}
// 获取读取数据流的状态,读取成功时,将最后一帧的数据显示到窗口
if (status)
{
cv::imshow("video", last_frame);
}
cv::waitKey(1);
}
return 0;
}