用Python opencv调用工业摄像头进行帧差法进行动态跟踪,代码能成功运行但是矩形框画不出来,
import cv2
import numpy as np
import mvsdk
import platform
class Camera(object):
def init(self, DevInfo):
super(Camera, self).init()
self.DevInfo = DevInfo
self.hCamera = 0
self.cap = None
self.pFrameBuffer = 0
def open(self):
if self.hCamera > 0:
return True
# 打开相机
hCamera = 0
try:
hCamera = mvsdk.CameraInit(self.DevInfo, -1, -1)
except mvsdk.CameraException as e:
print("CameraInit Failed({}): {}".format(e.error_code, e.message))
return False
# 获取相机特性描述
cap = mvsdk.CameraGetCapability(hCamera)
# 判断是黑白相机还是彩色相机
monoCamera = (cap.sIspCapacity.bMonoSensor != 0)
# 黑白相机让ISP直接输出MONO数据,而不是扩展成R=G=B的24位灰度
if monoCamera:
mvsdk.CameraSetIspOutFormat(hCamera, mvsdk.CAMERA_MEDIA_TYPE_MONO8)
else:
mvsdk.CameraSetIspOutFormat(hCamera, mvsdk.CAMERA_MEDIA_TYPE_BGR8)
# 计算RGB buffer所需的大小,这里直接按照相机的最大分辨率来分配
FrameBufferSize = cap.sResolutionRange.iWidthMax * cap.sResolutionRange.iHeightMax * (1 if monoCamera else 3)
# 分配RGB buffer,用来存放ISP输出的图像
# 备注:从相机传输到PC端的是RAW数据,在PC端通过软件ISP转为RGB数据(如果是黑白相机就不需要转换格式,但是ISP还有其它处理,所以也需要分配这个buffer)
pFrameBuffer = mvsdk.CameraAlignMalloc(FrameBufferSize, 16)
# 相机模式切换成连续采集
mvsdk.CameraSetTriggerMode(hCamera, 0)
# 手动曝光,曝光时间30ms
mvsdk.CameraSetAeState(hCamera, 0)
mvsdk.CameraSetExposureTime(hCamera, 30 * 1000)
# 让SDK内部取图线程开始工作
mvsdk.CameraPlay(hCamera)
self.hCamera = hCamera
self.pFrameBuffer = pFrameBuffer
self.cap = cap
return True
def close(self):
if self.hCamera > 0:
mvsdk.CameraUnInit(self.hCamera)
self.hCamera = 0
mvsdk.CameraAlignFree(self.pFrameBuffer)
self.pFrameBuffer = 0
def grab(self):
# 从相机取一帧图片
hCamera = self.hCamera
pFrameBuffer = self.pFrameBuffer
try:
pRawData, FrameHead = mvsdk.CameraGetImageBuffer(hCamera, 200)
mvsdk.CameraImageProcess(hCamera, pRawData, pFrameBuffer, FrameHead)
mvsdk.CameraReleaseImageBuffer(hCamera, pRawData)
# windows下取到的图像数据是上下颠倒的,以BMP格式存放。转换成opencv则需要上下翻转成正的
# linux下直接输出正的,不需要上下翻转
if platform.system() == "Windows":
mvsdk.CameraFlipFrameBuffer(pFrameBuffer, FrameHead, 1)
# 此时图片已经存储在pFrameBuffer中,对于彩色相机pFrameBuffer=RGB数据,黑白相机pFrameBuffer=8位灰度数据
# 把pFrameBuffer转换成opencv的图像格式以进行后续算法处理
frame_data = (mvsdk.c_ubyte * FrameHead.uBytes).from_address(pFrameBuffer)
frame = np.frombuffer(frame_data, dtype=np.uint8)
frame = frame.reshape((FrameHead.iHeight, FrameHead.iWidth,
1 if FrameHead.uiMediaType == mvsdk.CAMERA_MEDIA_TYPE_MONO8 else 3))
return frame
except mvsdk.CameraException as e:
if e.error_code != mvsdk.CAMERA_STATUS_TIME_OUT:
print("CameraGetImageBuffer failed({}): {}".format(e.error_code, e.message))
return None
def main_loop():
# 枚举相机
DevList = mvsdk.CameraEnumerateDevice()
nDev = len(DevList)
if nDev < 1:
print("No camera was found!")
return
for i, DevInfo in enumerate(DevList):
print("{}: {} {}".format(i, DevInfo.GetFriendlyName(), DevInfo.GetPortType()))
cams = []
for i in range(2):
cam = Camera(DevList[i])
if cam.open():
cams.append(cam)
while (cv2.waitKey(1) & 0xFF) != ord('q'):
for cam in cams:
frame = cam.grab()
if frame is not None:
frame = cv2.resize(frame, (640, 480), interpolation=cv2.INTER_LINEAR)
frame = process_frame(frame)
cv2.imshow("{} Press q to end".format(cam.DevInfo.GetFriendlyName()), frame)
def process_frame(frame):
es = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (9, 4)) # 返回指定形状和尺寸的结构元素,椭圆形,中心点
kernel = np.ones((5, 5), np.uint8) # 返回矩阵
background = None
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray, (21, 21), 0)
# 将第一帧设置为整个输入的背景
background = gray
# 对于每个从背景之后读取的帧都会计算其与背景之间的差异,并得到一个差分图(different map)。
# 还需要应用阈值来得到一幅黑白图像,并通过下面代码来膨胀(dilate)图像,从而对孔(hole)和缺陷(imperfection)进行归一化处理
diff = cv2.absdiff(background, gray)
diff = cv2.threshold(diff, 148, 255, cv2.THRESH_BINARY)[
1] # 二值化阈值处理黑白,灰度图,对图像进行分类的阈值,最大值,表示如果像素值大于(有时小于)阈值则要给出的值,决定给出不同类型的阈值
diff = cv2.dilate(diff, es, iterations=2) # 形态学膨胀,目标图片,进行操作的内核,默认为3×3的矩阵,腐蚀次数,默认为1
# 显示矩形框
contours, hierarchy = cv2.findContours(diff.copy(), cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE) # 该函数计算一幅图像中目标的轮廓,只返回最外边轮廓,
# contours:返回的轮廓 hierarchy:每条轮廓对应的属性
for c in contours:
if cv2.contourArea(c) < 1500: # 求得轮廓面积 对于矩形区域,只显示大于给定阈值的轮廓,所以一些微小的变化不会显示。对于光照不变和噪声低的摄像头可不设定轮廓最小尺寸的阈值
continue
(x, y, w, h) = cv2.boundingRect(c) # 该函数计算矩形的边界框,x,y是矩阵左上点的坐标,w,h是矩阵的宽和高
cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2)
return frame
def main():
try:
main_loop()
finally:
cv2.destroyAllWindows()
main()
这种只能debug进去看下了,看看是不是你最后找的轮廓没有找到没绘制,还是你找到的轮廓面积全部小于1500所以没进去下面的绘制函数
在怀疑有问题的地方插入
print("变量名: "+str(变量名))
input(“pause”)
辅助调试