Python 单通道摄像头移动物体检测后台,Udp发送坐标

首先实现一下单通道摄像头后台

下一篇再实现多通道

主要功能:

透视变换框选感兴趣的区域,然后检测检测画面中移动的物体,并将坐标通过udp发送出去

 

讲一下大致思路

 

1.用到的库文件:

    opencv-python  

    numpy

 

2.首先获取摄像头画面

import cv2
import numpy as np

cap=cv2.VideoCapture(0)
cv2.namedWindow('frame',0)
cv2.resizeWindow('frame',640,480)
while True:
    ret,frame=cap.read()
    if not ret:
        break
    cv2.imshow('frame',frame)
    c=cv2.waitKey(30)
    if c==27:
        break
        
cap.release()
cv2.destroyAllWindows()

 

3.透视变化划出我们感兴趣的区域

#透视变换
#src 为摄像头画面
#x0,y0,...,x3,y3为我们感兴趣区域的四个顶点 分别为左上,右上,左下,右下
def framePerspective(src,x0,y0,x1,y1,x2,y2,x3,y3):
    pts1=np.float32([[x0,y0],[x1,y1],[x2,y2],[x3,y3]])
    pts2=np.float32([[0,0],[640,0],[0,480],[640,480]])

    M=cv2.getPerspectiveTransform(pts1,pts2)

    dst=cv2.warpPerspective(src,M,(640,480))
    dst=cv2.flip(dst,1)
    return dst

 

 

4.剔除背景检测移动物体

  

kernel=cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(5,5))
fgbg=cv2.createBackgroundSubtractorMOG2()

#剔除背景检测移动物体
def bgRemoveObjDetect(src,kernel,fgbg):
    fgmask=fgbg.apply(src)
    mask=cv2.morphologyEx(fgmask,cv2.MORPH_OPEN,kernel)
    contours,_=cv2.findContours(mask.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
    for c in contours:
        if 1000<cv2.contourArea(c)<400000:
            x,y,w,h=cv2.boundingRect(c)
            cv2.rectangle(src,(x,y),(x+w,y+h),(0,0,255),10)
    return  src

 

5.鼠标点击事件,主要用来点击获取感兴趣的区域的四个顶点坐标

  

clickNum=0

x0,y0,x1,y1,x2,y2,x3,y3=0,0,0,0,0,0,0,0 

cv2.setMouseCallback('frame', leftMouseClickEvent)

#鼠标点击事件回调
def leftMouseClickEvent(event,x,y,flags,param):
    global clickNum,x0,y0,x1,y1,x2,y2,x3,y3
    if event==cv2.EVENT_LBUTTONDOWN:
        if clickNum==0:
            x0,y0,x1,y1,x2,y2,x3,y3=0,0,0,0,0,0,0,0
        elif clickNum==1:
            x0, y0 = x, y
        elif clickNum==2:
            x1, y1 = x, y
        elif clickNum==3:
            x2,y2=x,y
        elif clickNum == 4:
            x3, y3 = x, y
            clickNum=0
            return
        clickNum += 1

 

 

6.完整代码,在工程同级目录下,新建一个Config.xml, 用来存储四个点位信息, 然后把完整代码复制过去,插上一个usb摄像头,然后点击四个位置画出感兴趣区域后,即可实现动态物体检测,鼠标再点击一次则为重置画面

<Config>
  <Channel0>
      <pos0>555,240</pos0>
	  <pos1>1479,249</pos1>
	  <pos2>246,792</pos2>
	  <pos3>1308,783</pos3>
  </Channel0>
</Config>
import cv2
import numpy as np
import socket
import xml.etree.cElementTree as ET
import os
import sys
import tkinter

def traverseXml(element):
    if len(element)>0:
        for child in element:
            print(child.tag,'----',child.attrib)
            traverseXml(child)

#鼠标点击事件回调
def leftMouseClickEvent(event,x,y,flags,param):
    global clickNum,x0,y0,x1,y1,x2,y2,x3,y3
    if event==cv2.EVENT_LBUTTONDOWN:
        if clickNum==0:
            x0,y0,x1,y1,x2,y2,x3,y3=0,0,0,0,0,0,0,0
        elif clickNum==1:
            x0, y0 = x, y
        elif clickNum==2:
            x1, y1 = x, y
        elif clickNum==3:
            x2,y2=x,y
        elif clickNum == 4:
            x3, y3 = x, y
            clickNum=0
            updateXml()
            return
        clickNum += 1


#获取摄像头画面
def getCamFrame(cap0):

    _,frame0=cap0.read()
    return frame0

#透视变换
def framePerspective(frame,x0,y0,x1,y1,x2,y2,x3,y3):
    pts1=np.float32([[x0,y0],[x1,y1],[x2,y2],[x3,y3]])
    pts2=np.float32([[0,0],[640,0],[0,480],[640,480]])

    M=cv2.getPerspectiveTransform(pts1,pts2)

    dst=cv2.warpPerspective(frame,M,(640,480))
    dst=cv2.flip(dst,1)
    cv2.imshow('frame',dst)
    return dst

#背景差检测移动物体并通过udp发送
def frameDifferencing():
    global kernel,fgbg,dst,server,ip_port
    fgmask=fgbg.apply(dst)
    mask=cv2.morphologyEx(fgmask,cv2.MORPH_OPEN,kernel)
   # cv2.imshow('mask',mask)
    contours,_=cv2.findContours(mask.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)

    posMsg='v'
    for c in contours:
        if 1000<cv2.contourArea(c)<400000:
            x,y,w,h=cv2.boundingRect(c)
            cv2.rectangle(dst,(x,y),(x+w,y+h),(0,0,255),10)
            posMsg+=str((x+(w/2))/640)+','+str((y+(h/2))/480)+'@'
    cv2.imshow('frame',dst)
    if '@' in posMsg:
        server.sendto(posMsg.encode('utf-8'),('127.0.0.1', 11111))

#读取xml文件
def readXml():
    global x0, y0, x1, y1, x2, y2, x3, y3
    xmlFilePath = os.path.abspath('Config.xml')
    try:
        tree = ET.parse(xmlFilePath)
        print("tree type:", type(tree))
        # 获得根节点
        root = tree.getroot()
    except Exception as e:
        print("parse Config.xml fail!")

    for child in root:
        if child.tag=='Channel0':
            for child1 in child:
               # print(child1.text)
                if child1.tag=='pos0':
                    posArr=child1.text.split(',')
                    x0,y0=posArr[0],posArr[1]
                    print("x0:"+x0+" y0:"+y0)
                elif  child1.tag=='pos1':
                    posArr=child1.text.split(',')
                    x1,y1=posArr[0],posArr[1]
                    print("x1:"+x1+" y1:"+y1)
                elif child1.tag == 'pos2':
                    posArr = child1.text.split(',')
                    x2, y2 = posArr[0], posArr[1]
                    print("x2:" + x2 + " y2:" + y2)
                elif child1.tag == 'pos3':
                    posArr = child1.text.split(',')
                    x3, y3 = posArr[0], posArr[1]
                    print("x1:" + x3 + " y1:" + y3)

#写入xml文件
def updateXml():
    global x0, y0, x1, y1, x2, y2, x3, y3,clickNum
    xmlFilePath = os.path.abspath('Config.xml')
    try:
        tree = ET.parse(xmlFilePath)
        print("tree type:", type(tree))
        # 获得根节点
        root = tree.getroot()
    except Exception as e:
        print("parse Config.xml fail!")

    for child in root:
        if child.tag == 'Channel0':
            for child1 in child:
                # print(child1.text)
                if child1.tag == 'pos0':
                    txt=str(x0)+','+str(y0)
                    child1.text=txt
                elif child1.tag == 'pos1':
                    txt = str(x1) + ',' + str(y1)
                    child1.text = txt
                elif child1.tag == 'pos2':
                    txt = str(x2) + ',' + str(y2)
                    child1.text = txt
                elif child1.tag == 'pos3':
                    txt = str(x3) + ',' + str(y3)
                    child1.text = txt
    tree.write(xmlFilePath)


if __name__=='__main__':

    clickNum=0

    x0,y0,x1,y1,x2,y2,x3,y3=0,0,0,0,0,0,0,0

    readXml()

    ip_port = ('127.0.0.1', 12345)
    server = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
  #  server.bind(ip_port)


    cap0 = cv2.VideoCapture(0)
    cv2.namedWindow('frame', 0)
    cv2.resizeWindow('frame', 640, 480)
    frame = getCamFrame(cap0)
    dst=frame
    cv2.imshow('frame', frame)
    cv2.setMouseCallback('frame', leftMouseClickEvent)

    kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))
    fgbg = cv2.createBackgroundSubtractorMOG2()


    while True:
        frame=getCamFrame(cap0)
        cv2.imshow('frame',frame)
        if  y3!=0 :
            dst= framePerspective(frame, x0,y0,x1,y1,x2,y2,x3,y3)
            frameDifferencing()
        c=cv2.waitKey(1)
        if c==27:
            break;

    cap0.release()
    cv2.destroyAllWindows()


 

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值