海康威视网络摄像头Python SDK+移动物体位置检测
注意:摄像头要在镜头上贴红外滤光片 过滤掉可见光
效果展示,已经过滤到大部分波长可见光,手在镜头前来回移动,红框即检测到移动物体的位置,并框出来(海康威视的摄像头可见光好像不能完全被滤光片过滤掉,但是可以过滤到投影机的画面或者屏幕的画面,不影响使用)
目录
1.将海康威视的C++ sdk 转化为 Python sdk
2.调用海康威视Python SDK
3.调用多个海康威视摄像头
4. 将多个摄像头画面拼接成一个
5.挨个摄像头透视变换
6. 透视变换完后再在拼接后的画面上做动态物体检测,参考博客
1.将海康威视的C++ sdk 转化为 Python sdk (本文已经处理完了)
如果最后一步Python调用时遇到报错,尝试将所有相关的文件全部复制到Python工程的路径下
环境:
1. windows10 64位
2. opecv
3. python3
4.海康威视网络摄像头64位 C++ sdk
https://www.hikvision.com/cn/download_61.html
下载SDK_Win64
5.其他库文件:
5.1 opencv-python
5.2 numpy
5.3 multiprocessing (多进程使用)
本文已将海康威视C++ sdk转为Python sdk处理好,可以直接下载使用,文末网址分享
如果HKIPCamera 一直报错,找不到模块 ,首先 python 和 opencv要安装好,并且设置好环境变量,如果还是报错:
一般是缺少VC++库的运行时组件,两个方案:
1. 从微软官网下载VC++库的运行时组件:
此组件也可以解决其他项目上的很多疑难杂症
官网链接: https://visualstudio.microsoft.com/zh-hans/downloads/
2、下载一个DirectX修复工具
链接:https://pan.baidu.com/s/1thfI2SyCpQoToBxuwFnxuA 提取码:8aza
打开后点击 工具----> 选项---->扩展---->开始扩展
扩展完了以后,此时会默认选中同时更新C++,点击检测并修复,
如果缺少组件就会自动安装,如果已经安装了但是不是最新的,会自动更新,
等修复完了,再尝试运行Python程序
如果还是一直存在问题,请回头参考博文一步一步重新操作
2.调用海康威视Python SDK
import cv2
import numpy as np
import HKIPcamera
def get_cam_frame(ip, account, password):
ip = str(ip) # 摄像头IP地址,要和本机IP在同一局域网
name = str(account) # 管理员用户名
pw = str(password) # 管理员密码
HKIPcamera.init(ip, name, pw)
while(True):
fram = HKIPcamera.getframe()
frame = np.array(fram)
cv2.imshow('frame',frame)
c = cv2.waitKey(10)
if c == 27:
break;
HKIPcamera.release()
if __name__ == '__main__':
get_cam_frame('192.168.1.64', 'admin', '123456')
3.调用多个海康威视摄像头
多进程,多线程不起作用
在第一步的代码基础上修改一下
import cv2
import numpy as np
import HKIPcamera
from multiprocessing import Process, Queue
def get_cam_frame(frameName, ip, account, password):
ip = str(ip) # 摄像头IP地址,要和本机IP在同一局域网
name = str(account) # 管理员用户名
pw = str(password) # 管理员密码
HKIPcamera.init(ip, name, pw)
while True:
fram = HKIPcamera.getframe()
frame = np.array(fram)
cv2.imshow(frameName, frame)
c = cv2.waitKey(10)
if c == 27:
break;
HKIPcamera.release()
if __name__ == '__main__':
p0 = Process(target=get_cam_frame, args=('frame0', '192.168.1.64', 'admin', '123456',))
p0.start()
p1 = Process(target=get_cam_frame, args=('frame1', '192.168.1.65', 'admin', '123456',))
p1.start()
# 以此类推 p2 p3 ... pn
4. 将多个摄像头画面拼接成一个
再在上述的代码基础上修改
import cv2
import numpy as np
import HKIPcamera
from multiprocessing import Process, Queue
import os
import signal
def get_cam_frame(frameName, ip, account, password, n):
ip = str(ip) # 摄像头IP地址,要和本机IP在同一局域网
name = str(account) # 管理员用户名
pw = str(password) # 管理员密码
HKIPcamera.init(ip, name, pw)
while True:
fram = HKIPcamera.getframe()
frame = np.array(fram)
# 由于摄像头画面是1920*1080,多个拼接的话,画面会非常大,所有重置一下每个摄像头的画面
frame = cv2.resize(frame, (768, 540), interpolation=cv2.INTER_CUBIC)
n.put(frame)
cv2.imshow(frameName, frame)
c = cv2.waitKey(10)
if c == 27:
break;
HKIPcamera.release()
if __name__ == '__main__':
q0 = Queue(3)
p0 = Process(target=get_cam_frame, args=('frame0', '192.168.1.64', 'admin', '123456', q0,))
p0.start()
q1 = Queue(3)
p1 = Process(target=get_cam_frame, args=('frame1', '192.168.1.65', 'admin', '12345', q1,))
p1.start()
while True:
if p0.is_alive() and p1.is_alive():
frame0 = q0.get()
frame1 = q1.get()
# 横着拼
full_frame = np.hstack([frame0, frame1])
# 竖着拼
# full_frame = np.vstack([frame0, frame1])
cv2.imshow('full_frame', full_frame)
c = cv2.waitKey(10)
if c==27:
os.kill(p0.pid, signal.SIGTERM)
os.kill(p1.pid, signal.SIGTERM)
break;
5.挨个摄像头透视变换
如果不了解opencv-python透视变换函数的参数,请先看下此博客的透视变换函数介绍,链接如下:
import cv2
import numpy as np
import HKIPcamera
from multiprocessing import Process, Queue
import os
import signal
def get_cam_frame(frameName, ip, account, password, n):
ip = str(ip) # 摄像头IP地址,要和本机IP在同一局域网
name = str(account) # 管理员用户名
pw = str(password) # 管理员密码
HKIPcamera.init(ip, name, pw)
while True:
fram = HKIPcamera.getframe()
frame = np.array(fram)
# 由于摄像头画面是1920*1080,多个拼接的话,画面会非常大,所有重置一下每个摄像头的画面
frame = cv2.resize(frame, (768, 540), interpolation=cv2.INTER_CUBIC)
n.put(frame)
cv2.imshow(frameName, frame)
c = cv2.waitKey(10)
if c == 27:
break;
HKIPcamera.release()
#第一个摄像头透视变化的四个点
frame0_x0, frame0_y0, frame0_x1, frame0_y1, frame0_x2, frame0_y2, frame0_x3, frame0_y3 = 0, 0, 0, 0, 0, 0, 0, 0
#第二个摄像头透视变化的四个点
frame1_x0, frame1_y0, frame1_x1, frame1_y1, frame1_x2, frame1_y2, frame1_x3, frame1_y3 = 0, 0, 0, 0, 0, 0, 0, 0
#简单来写,按照从第一个摄像头开始,鼠标每点击一次,获取一个点
#例如鼠标第一次点击,就等于给坐标frame0_x0, frame0_y0 赋值, 第二次点击就是给坐标frame0_x1, frame0_y1赋值,以此类推
clickNum = 0
def draw_point(event, x, y, flags, param):
global frame0_x0, frame0_y0, frame0_x1, frame0_y1, frame0_x2, frame0_y2, frame0_x3, frame0_y3
global frame1_x0, frame1_y0, frame1_x1, frame1_y1, frame1_x2, frame1_y2, frame1_x3, frame1_y3, clickNum
if event == cv2.EVENT_LBUTTONDOWN:
if clickNum == 0:
frame0_x0 = x
frame0_y0 = y
elif clickNum == 1:
frame0_x1 = x
frame0_y1 = y
elif clickNum == 2:
frame0_x2 = x
frame0_y2 = y
elif clickNum == 3:
frame0_x3 = x
frame0_y3 = y
elif clickNum == 4:
frame1_x0 = x
frame1_y0 = y
elif clickNum == 5:
frame1_x1 = x
frame1_y1 = y
elif clickNum == 6:
frame1_x2 = x
frame1_y2 = y
elif clickNum == 7:
frame1_x3 = x
frame1_y3 = y
clickNum += 1
# 透视变换
def perspective_transform():
global frame0, frame1, clickNum
global frame0_x0, frame0_y0, frame0_x1, frame0_y1, frame0_x2, frame0_y2, frame0_x3, frame0_y3
global frame1_x0, frame1_y0, frame1_x1, frame1_y1, frame1_x2, frame1_y2, frame1_x3, frame1_y3
if clickNum==8:
W_cols, H_rows = frame0.shape[:2]
pts0_1 = np.float32(
[[frame0_x0, frame0_y0], [frame0_x1, frame0_y1],
[frame0_x2, frame0_y2], [frame0_x3, frame0_y3]])
pts0_2 = np.float32([[0, 0], [W_cols, 0], [0, H_rows], [W_cols, H_rows]])
M0 = cv2.getPerspectiveTransform(pts0_1, pts0_2)
frame0 = cv2.warpPerspective(frame0, M0, (W_cols, H_rows))
# 这里的变换需要减去第一个摄像头的画面的宽度,768
pts1_1 = np.float32(
[[frame1_x0-768, frame1_y0], [frame1_x1-768, frame1_y1],
[frame1_x2-768, frame1_y2], [frame1_x3-768, frame1_y3]])
pts1_2 = np.float32([[0, 0], [W_cols, 0], [0, H_rows], [W_cols, H_rows]])
M1 = cv2.getPerspectiveTransform(pts1_1, pts1_2)
frame1 = cv2.warpPerspective(frame1, M1, (W_cols, H_rows))
if __name__ == '__main__':
q0 = Queue(3)
p0 = Process(target=get_cam_frame, args=('frame0', '192.168.1.64', 'admin', '123456', q0,))
p0.start()
q1 = Queue(3)
p1 = Process(target=get_cam_frame, args=('frame1', '192.168.1.65', 'admin', '123456', q1,))
p1.start()
cv2.namedWindow('full_frame')
# 鼠标点击事件
cv2.setMouseCallback('full_frame', draw_point)
while True:
if p0.is_alive() and p1.is_alive():
frame0 = q0.get()
frame1 = q1.get()
# 透视变换
perspective_transform()
# 透视变换完再拼接
# 横着拼
full_frame = np.hstack([frame0, frame1])
# 竖着拼
#full_frame = np.vstack([frame0, frame1])
cv2.imshow('full_frame', full_frame)
c = cv2.waitKey(10)
if c==27:
os.kill(p0.pid, signal.SIGTERM)
os.kill(p1.pid, signal.SIGTERM)
break;
6. 透视变换完后再在拼接后的画面上做动态物体检测,参考博客
import cv2
import numpy as np
import HKIPcamera
from multiprocessing import Process, Queue
import os
import signal
def get_cam_frame(frameName, ip, account, password, n):
ip = str(ip) # 摄像头IP地址,要和本机IP在同一局域网
name = str(account) # 管理员用户名
pw = str(password) # 管理员密码
HKIPcamera.init(ip, name, pw)
while True:
fram = HKIPcamera.getframe()
frame = np.array(fram)
# 由于摄像头画面是1920*1080,多个拼接的话,画面会非常大,所有重置一下每个摄像头的画面
frame = cv2.resize(frame, (768, 540), interpolation=cv2.INTER_CUBIC)
n.put(frame)
cv2.imshow(frameName, frame)
c = cv2.waitKey(10)
if c == 27:
break;
HKIPcamera.release()
#第一个摄像头透视变化的四个点
frame0_x0, frame0_y0, frame0_x1, frame0_y1, frame0_x2, frame0_y2, frame0_x3, frame0_y3 = 0, 0, 0, 0, 0, 0, 0, 0
#第二个摄像头透视变化的四个点
frame1_x0, frame1_y0, frame1_x1, frame1_y1, frame1_x2, frame1_y2, frame1_x3, frame1_y3 = 0, 0, 0, 0, 0, 0, 0, 0
#简单来写,按照从第一个摄像头开始,鼠标每点击一次,获取一个点
#例如鼠标第一次点击,就等于给坐标frame0_x0, frame0_y0 赋值, 第二次点击就是给坐标frame0_x1, frame0_y1赋值,以此类推
clickNum = 0
def draw_point(event, x, y, flags, param):
global frame0_x0, frame0_y0, frame0_x1, frame0_y1, frame0_x2, frame0_y2, frame0_x3, frame0_y3
global frame1_x0, frame1_y0, frame1_x1, frame1_y1, frame1_x2, frame1_y2, frame1_x3, frame1_y3, clickNum
if event == cv2.EVENT_LBUTTONDOWN:
if clickNum == 0:
frame0_x0 = x
frame0_y0 = y
elif clickNum == 1:
frame0_x1 = x
frame0_y1 = y
elif clickNum == 2:
frame0_x2 = x
frame0_y2 = y
elif clickNum == 3:
frame0_x3 = x
frame0_y3 = y
elif clickNum == 4:
frame1_x0 = x
frame1_y0 = y
elif clickNum == 5:
frame1_x1 = x
frame1_y1 = y
elif clickNum == 6:
frame1_x2 = x
frame1_y2 = y
elif clickNum == 7:
frame1_x3 = x
frame1_y3 = y
clickNum += 1
# 透视变换
def perspective_transform():
global frame0, frame1, clickNum
global frame0_x0, frame0_y0, frame0_x1, frame0_y1, frame0_x2, frame0_y2, frame0_x3, frame0_y3
global frame1_x0, frame1_y0, frame1_x1, frame1_y1, frame1_x2, frame1_y2, frame1_x3, frame1_y3
if clickNum==8:
W_cols, H_rows = frame0.shape[:2]
pts0_1 = np.float32(
[[frame0_x0, frame0_y0], [frame0_x1, frame0_y1],
[frame0_x2, frame0_y2], [frame0_x3, frame0_y3]])
pts0_2 = np.float32([[0, 0], [W_cols, 0], [0, H_rows], [W_cols, H_rows]])
M0 = cv2.getPerspectiveTransform(pts0_1, pts0_2)
frame0 = cv2.warpPerspective(frame0, M0, (W_cols, H_rows))
# 这里的变换需要减去第一个摄像头的画面的宽度,768
pts1_1 = np.float32(
[[frame1_x0-768, frame1_y0], [frame1_x1-768, frame1_y1],
[frame1_x2-768, frame1_y2], [frame1_x3-768, frame1_y3]])
pts1_2 = np.float32([[0, 0], [W_cols, 0], [0, H_rows], [W_cols, H_rows]])
M1 = cv2.getPerspectiveTransform(pts1_1, pts1_2)
frame1 = cv2.warpPerspective(frame1, M1, (W_cols, H_rows))
if __name__ == '__main__':
q0 = Queue(3)
p0 = Process(target=get_cam_frame, args=('frame0', '192.168.1.64', 'admin', '123456', q0,))
p0.start()
q1 = Queue(3)
p1 = Process(target=get_cam_frame, args=('frame1', '192.168.1.65', 'admin', '123456', q1,))
p1.start()
cv2.namedWindow('full_frame')
# 鼠标点击事件
cv2.setMouseCallback('full_frame', draw_point)
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))
fgbg = cv2.createBackgroundSubtractorMOG2()
while True:
if p0.is_alive() and p1.is_alive():
frame0 = q0.get()
frame1 = q1.get()
# 透视变换
perspective_transform()
# 透视变换完再拼接
# 横着拼
full_frame = np.hstack([frame0, frame1])
# 竖着拼
#full_frame = np.vstack([frame0, frame1])
fgmask = fgbg.apply(full_frame)
mask = cv2.morphologyEx(fgmask, cv2.MORPH_OPEN, kernel)
contours, _ = cv2.findContours(fgmask.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for c in contours:
if 100 < cv2.contourArea(c) < 40000:
x, y, w, h = cv2.boundingRect(c)
cv2.rectangle(full_frame, (x, y), (x + w, y + h), (0, 0, 255))
cv2.imshow('full_frame', full_frame)
c = cv2.waitKey(10)
if c==27:
os.kill(p0.pid, signal.SIGTERM)
os.kill(p1.pid, signal.SIGTERM)
break;