参考
图书馆空位检测(行人+空位对比)
https://www.cnblogs.com/gooutlook/p/16192389.html

使用到的原始图像


1鼠标选择画框
API_draw.py
# -*- coding: utf-8 -*-
import copy
import cv2
import numpy as np
WIN_NAME = 'draw_rect'
from API_XML import *
class Rect(object):
def __init__(self):
self.tl = (0, 0)
self.br = (0, 0)
def regularize(self):
"""
make sure tl = TopLeft point, br = BottomRight point
"""
pt1 = (min(self.tl[0], self.br[0]), min(self.tl[1], self.br[1]))
pt2 = (max(self.tl[0], self.br[0]), max(self.tl[1], self.br[1]))
self.tl = pt1
self.br = pt2
class DrawRects(object):
def __init__(self, image, color, thickness=1):
self.original_image = image
self.image_for_show = image
self.color = color
self.thickness = thickness
self.rects = []
self.current_rect = Rect()
self.left_button_down = False
@staticmethod
def __clip(value, low, high):
"""
clip value between low and high
Parameters
----------
value: a number
value to be clipped
low: a number
low limit
high: a number
high limit
Returns
-------
output: a number
clipped value
"""
output = max(value, low)
output = min(output, high)
return output
def shrink_point(self, x, y):
"""
shrink point (x, y) to inside image_for_show
Parameters
----------
x, y: int, int
coordinate of a point
Returns
-------
x_shrink, y_shrink: int, int
shrinked coordinate
"""
height, width = self.image_for_show.shape[0:2]
x_shrink = self.__clip(x, 0, width)
y_shrink = self.__clip(y, 0, height)
return (x_shrink, y_shrink)
def append(self):
"""
add a rect to rects list
"""
self.rects.append(copy.deepcopy(self.current_rect))
def pop(self):
"""
pop a rect from rects list
"""
rect = Rect()
if self.rects:
rect = self.rects.pop()
return rect
def reset_image(self):
"""
reset image_for_show using original image
"""
self.image_for_show = self.original_image.copy()
def draw(self):
"""
draw rects on image_for_show
"""
for rect in self.rects:
cv2.rectangle(self.image_for_show, rect.tl, rect.br,
color=self.color, thickness=self.thickness)
def draw_current_rect(self):
"""
draw current rect on image_for_show
"""
cv2.rectangle(self.image_for_show,
self.current_rect.tl, self.current_rect.br,
color=self.color, thickness=self.thickness)
def onmouse_draw_rect(event, x, y, flags, draw_rects):
if event == cv2.EVENT_LBUTTONDOWN:
# pick first point of rect
print('pt1: x = %d, y = %d' % (x, y))
draw_rects.left_button_down = True
draw_rects.current_rect.tl = (x, y)
if draw_rects.left_button_down and event == cv2.EVENT_MOUSEMOVE:
# pick second point of rect and draw current rect
draw_rects.current_rect.br = draw_rects.shrink_point(x, y)
draw_rects.reset_image()
draw_rects.draw()
draw_rects.draw_current_rect()
if event == cv2.EVENT_LBUTTONUP:
# finish drawing current rect and append it to rects list
draw_rects.left_button_down = False
draw_rects.current_rect.br = draw_rects.shrink_point(x, y)
print('pt2: x = %d, y = %d' % (draw_rects.current_rect.br[0],
draw_rects.current_rect.br[1]))
draw_rects.current_rect.regularize()
draw_rects.append()
if (not draw_rects.left_button_down) and event == cv2.EVENT_RBUTTONDOWN:
# pop the last rect in rects list
draw_rects.pop()
draw_rects.reset_image()
draw_rects.draw()
if __name__ == '__main__':
#image = np.zeros((256, 256, 3), np.uint8)
image=cv2.imread("map1.png")
draw_rects = DrawRects(image, (0, 255, 0), 2)
cv2.namedWindow(WIN_NAME, 0)
cv2.setMouseCallback(WIN_NAME, onmouse_draw_rect, draw_rects)
while True:
cv2.imshow(WIN_NAME, draw_rects.image_for_show)
key = cv2.waitKey(30)
if key == ord('q') or key == ord('Q') : # ESC
break
elif key == ord('s') or key == ord('S') :
print("===========\n")
i=1
#1创建
# 1.创建DOM树对象
dom=minidom.Document()
API_Creat_Xml_Node1(dom,"root")
for rect in draw_rects.rects:
print("x1",rect.tl[0],"y1",rect.tl[1], "x2",rect.br[0],"y2",rect.br[1])
# 2.1创建次节点
root2_node=API_Creat_Xml_Node2(dom,"zuowei",str(i))
API_Creat_Xml_Node3(dom,root2_node,"xmin",str(rect.tl[0]))
API_Creat_Xml_Node3(dom,root2_node,"ymin",str(rect.tl[1]))
API_Creat_Xml_Node3(dom,root2_node,"xmax",str(rect.br[0]))
API_Creat_Xml_Node3(dom,root2_node,"ymax",str(rect.br[1]))
i=i+1
try:
with open(path_xml,'w',encoding='UTF-8') as fh:
# 4.writexml()第一个参数是目标文件对象,第二个参数是根节点的缩进格式,第三个参数是其他子节点的缩进格式,
# 第四个参数制定了换行格式,第五个参数制定了xml内容的编码。
dom.writexml(fh,indent='',addindent='\t',newl='\n',encoding='UTF-8')
print('写入xml OK!')
except Exception as err:
print('错误信息:{0}'.format(err))
#2读取
#USE_2_1ReadXMLNode(path_xml,"zuowei","xmin")
#访问所有的座位节点
USE_2_2ReadXMLNode(path_xml,"zuowei",["xmin","ymin","xmax","ymax"])
cv2.destroyAllWindows()
API_XML.py
#导入minidom
from xml.dom import minidom
path_xml='config.xml'
# 1.创建DOM树对象
dom=minidom.Document()
def API_Creat_Xml_Node1(dom,root1_Name):
# 1.创建DOM树对象
#dom=minidom.Document()
# 2.创建根节点。每次都要用DOM对象来创建任何节点。
root_node=dom.createElement(root1_Name)
# 3.用DOM对象添加根节点
dom.appendChild(root_node)
# 设置该节点的属性
root_node.setAttribute('info','主节点')
def API_Creat_Xml_Node2(dom,root2_Name,msg):
# 获取根节点
root_node=dom.documentElement
# 节点名称
print(root_node.nodeName)
# 用DOM对象创建元素子节点
root2_node=dom.createElement(root2_Name)
# 用父节点对象添加元素子节点
root_node.appendChild(root2_node)
# 设置该节点的属性
root2_node.setAttribute('info',msg)
return root2_node
def API_Creat_Xml_Node3(dom,root2_node,root3_Name,msg):
root3_node=dom.createElement(root3_Name)
root2_node.appendChild(root3_node)
# 也用DOM创建文本节点,把文本节点(文字内容)看成子节点
name_text=dom.createTextNode(msg)
# 用添加了文本的节点对象(看成文本节点的父节点)添加文本节点
root3_node.appendChild(name_text)
'''
函数功能:创建数据
函数输入:path_xml 文件名字
函数输出:
<?xml version="1.0" encoding="UTF-8"?>
<root info="主节点">
<car info="car1">
<xmin>1</xmin>
<ymin>2</ymin>
<xmax>3</xmax>
<ymax>4</ymax>
</car>
<car info="car2">
<xmin>5</xmin>
<ymin>6</ymin>
<xmax>7</xmax>
<ymax>8</ymax>
</car>
</root>
'''
def USE_1Creat_Xml(path_xml):
# 1.创建DOM树对象
dom=minidom.Document()
API_Creat_Xml_Node1(dom,"root")
# 2.1创建次节点
root2_node=API_Creat_Xml_Node2(dom,"car","car1")
API_Creat_Xml_Node3(dom,root2_node,"xmin","1")
API_Creat_Xml_Node3(dom,root2_node,"ymin","2")
API_Creat_Xml_Node3(dom,root2_node,"xmax","3")
API_Creat_Xml_Node3(dom,root2_node,"ymax","4")
# 2.2创建次节点
root2_node=API_Creat_Xml_Node2(dom,"car","car2")
API_Creat_Xml_Node3(dom,root2_node,"xmin","5")
API_Creat_Xml_Node3(dom,root2_node,"ymin","6")
API_Creat_Xml_Node3(dom,root2_node,"xmax","7")
API_Creat_Xml_Node3(dom,root2_node,"ymax","8")
# 每一个结点对象(包括dom对象本身)都有输出XML内容的方法,如:toxml()--字符串, toprettyxml()--美化树形格式。
try:
with open(path_xml,'w',encoding='UTF-8') as fh:
# 4.writexml()第一个参数是目标文件对象,第二个参数是根节点的缩进格式,第三个参数是其他子节点的缩进格式,
# 第四个参数制定了换行格式,第五个参数制定了xml内容的编码。
dom.writexml(fh,indent='',addindent='\t',newl='\n',encoding='UTF-8')
print('写入xml OK!')
except Exception as err:
print('错误信息:{0}'.format(err))
'''
函数功能:读取数据
函数输入:
path_xml 文件名字
root1_Name 2次节点 car
root2_Name 3次节点 xmin
函数输出:
<?xml version="1.0" encoding="UTF-8"?>
<root info="主节点">
<car info="car1">
<xmin>1</xmin>
<ymin>2</ymin>
<xmax>3</xmax>
<ymax>4</ymax>
</car>
<car info="car2">
<xmin>5</xmin>
<ymin>6</ymin>
<xmax>7</xmax>
<ymax>8</ymax>
</car>
</root>
'''
def USE_2_1ReadXMLNode(path_xml,root1_Name,root2_Name):
#打开文件
with open(path_xml,'r',encoding='utf8') as fh:
# 1 获取根节点
# parse()获取DOM对象
dom=minidom.parse(fh)
# 获取根节点
root=dom.documentElement
# 节点名称
print(root.nodeName)
#2 获取2次节点 root1_Name 是一个列表
change_1Node_all = root.getElementsByTagName(root1_Name) # 所有的 car节点
#循环访问每个次节点
for change_1Node_i in change_1Node_all:
#3 获取2次节点 root1_Name 下面的3次节点 root2_Name 是一个列表
change_2Node = change_1Node_i.getElementsByTagName(root2_Name)[0] #肯恶搞有很多个root2_Name xmin
change_old= change_2Node.childNodes[0].data
print(change_old)
'''
函数功能:访问所有 root1_Name下面的 指定属性root2_NameList
函数输入:
节点root1_Name car
指定属性root2_NameList ["xmin","ymin","xmax","ymax"]
函数输出:
root
节点名字 ['xmin', 'ymin', 'xmax', 'ymax']
相同节点 0 ['33', '42', '106', '90']
相同节点 0 ['80', '139', '167', '195']
相同节点 0 ['150', '87', '217', '141']
'''
def USE_2_2ReadXMLNode(path_xml,root1_Name,root2_NameList):
#打开文件
with open(path_xml,'r',encoding='utf8') as fh:
# 1 获取根节点
# parse()获取DOM对象
dom=minidom.parse(fh)
# 获取根节点
root=dom.documentElement
# 节点名称
print(root.nodeName)
#2 获取2次节点 root1_Name 是一个列表
change_1Node_all = root.getElementsByTagName(root1_Name) # 所有的 car节点
print('节点名字',root1_Name)
print('节点属性',root2_NameList)
i=0
data_msg_all=[]
#循环访问每个次节点
for change_1Node_i in change_1Node_all:
data_msg=[]
for root2_Name_i in root2_NameList:
#3 获取2次节点 root1_Name 下面的3次节点 root2_Name 是一个列表
change_2Node = change_1Node_i.getElementsByTagName(root2_Name_i)[0] #肯恶搞有很多个root2_Name xmin
date= change_2Node.childNodes[0].data
#print(root2_Name_i,date)
data_msg.append(date)
data_msg_all.append(data_msg)
print(root1_Name,'节点',i,data_msg)
i=i+1
print("所有信息",data_msg_all)
return data_msg_all
'''
#1创建
USE_1Creat_Xml(path_xml)
#2读取
USE_2_1ReadXMLNode(path_xml,"car","xmin")
#2-1读取
USE_2_2ReadXMLNode(path_xml,"car",["xmin","ymin","xmax","ymax"])
'''
'''
#1创建
# 1.创建DOM树对象
dom=minidom.Document()
API_Creat_Xml_Node1(dom,"root")
#2循环添加节点
for rect in rects:
print("x1",rect.tl[0],"y1",rect.tl[1], "x2",rect.br[0],"y2",rect.br[1])
# 2.1创建次节点
root2_node=API_Creat_Xml_Node2(dom,"zuowei",str(i))
API_Creat_Xml_Node3(dom,root2_node,"xmin",str(rect.tl[0]))
API_Creat_Xml_Node3(dom,root2_node,"ymin",str(rect.tl[1]))
API_Creat_Xml_Node3(dom,root2_node,"xmax",str(rect.br[0]))
API_Creat_Xml_Node3(dom,root2_node,"ymax",str(rect.br[1]))
i=i+1
try:
with open(path_xml,'w',encoding='UTF-8') as fh:
# 4.writexml()第一个参数是目标文件对象,第二个参数是根节点的缩进格式,第三个参数是其他子节点的缩进格式,
# 第四个参数制定了换行格式,第五个参数制定了xml内容的编码。
dom.writexml(fh,indent='',addindent='\t',newl='\n',encoding='UTF-8')
print('写入xml OK!')
except Exception as err:
print('错误信息:{0}'.format(err))
#2读取
#USE_2_1ReadXMLNode(path_xml,"zuowei","xmin")
#访问所有的座位节点
USE_2_2ReadXMLNode(path_xml,"zuowei",["xmin","ymin","xmax","ymax"])
'''
之后保存了 config文件

<?xml version="1.0" encoding="UTF-8"?> <root info="主节点"> <zuowei info="1"> <xmin>200</xmin> <ymin>79</ymin> <xmax>333</xmax> <ymax>177</ymax> </zuowei> <zuowei info="2"> <xmin>395</xmin> <ymin>81</ymin> <xmax>538</xmax> <ymax>178</ymax> </zuowei> <zuowei info="3"> <xmin>794</xmin> <ymin>76</ymin> <xmax>936</xmax> <ymax>175</ymax> </zuowei> <zuowei info="4"> <xmin>199</xmin> <ymin>308</ymin> <xmax>329</xmax> <ymax>400</ymax> </zuowei> </root>
2 读取xml可视化矩形框
# -*- coding: utf-8 -*-
import copy
import cv2
import numpy as np
WIN_NAME = 'draw_rect'
from API_XML import *
class Rect(object):
def __init__(self):
self.tl = (0, 0)
self.br = (0, 0)
def regularize(self):
"""
make sure tl = TopLeft point, br = BottomRight point
"""
pt1 = (min(self.tl[0], self.br[0]), min(self.tl[1], self.br[1]))
pt2 = (max(self.tl[0], self.br[0]), max(self.tl[1], self.br[1]))
self.tl = pt1
self.br = pt2
class DrawRects(object):
def __init__(self, image, color, thickness=1):
self.original_image = image
self.image_for_show = image
self.color = color
self.thickness = thickness
self.rects = []
self.current_rect = Rect()
self.left_button_down = False
@staticmethod
def __clip(value, low, high):
"""
clip value between low and high
Parameters
----------
value: a number
value to be clipped
low: a number
low limit
high: a number
high limit
Returns
-------
output: a number
clipped value
"""
output = max(value, low)
output = min(output, high)
return output
def shrink_point(self, x, y):
"""
shrink point (x, y) to inside image_for_show
Parameters
----------
x, y: int, int
coordinate of a point
Returns
-------
x_shrink, y_shrink: int, int
shrinked coordinate
"""
height, width = self.image_for_show.shape[0:2]
x_shrink = self.__clip(x, 0, width)
y_shrink = self.__clip(y, 0, height)
return (x_shrink, y_shrink)
def append(self):
"""
add a rect to rects list
"""
self.rects.append(copy.deepcopy(self.current_rect))
def pop(self):
"""
pop a rect from rects list
"""
rect = Rect()
if self.rects:
rect = self.rects.pop()
return rect
def reset_image(self):
"""
reset image_for_show using original image
"""
self.image_for_show = self.original_image.copy()
def draw(self):
"""
draw rects on image_for_show
"""
for rect in self.rects:
cv2.rectangle(self.image_for_show, rect.tl, rect.br,
color=self.color, thickness=self.thickness)
def draw_current_rect(self):
"""
draw current rect on image_for_show
"""
cv2.rectangle(self.image_for_show,
self.current_rect.tl, self.current_rect.br,
color=self.color, thickness=self.thickness)
def onmouse_draw_rect(event, x, y, flags, draw_rects):
if event == cv2.EVENT_LBUTTONDOWN:
# pick first point of rect
print('pt1: x = %d, y = %d' % (x, y))
draw_rects.left_button_down = True
draw_rects.current_rect.tl = (x, y)
if draw_rects.left_button_down and event == cv2.EVENT_MOUSEMOVE:
# pick second point of rect and draw current rect
draw_rects.current_rect.br = draw_rects.shrink_point(x, y)
draw_rects.reset_image()
draw_rects.draw()
draw_rects.draw_current_rect()
if event == cv2.EVENT_LBUTTONUP:
# finish drawing current rect and append it to rects list
draw_rects.left_button_down = False
draw_rects.current_rect.br = draw_rects.shrink_point(x, y)
print('pt2: x = %d, y = %d' % (draw_rects.current_rect.br[0],
draw_rects.current_rect.br[1]))
draw_rects.current_rect.regularize()
draw_rects.append()
if (not draw_rects.left_button_down) and event == cv2.EVENT_RBUTTONDOWN:
# pop the last rect in rects list
draw_rects.pop()
draw_rects.reset_image()
draw_rects.draw()
if __name__ == '__main__':
#image = np.zeros((256, 256, 3), np.uint8)
image=cv2.imread("map1.png")
#2读取
#USE_2_1ReadXMLNode(path_xml,"zuowei","xmin")
#访问所有的座位节点
data_msg_all=USE_2_2ReadXMLNode(path_xml,"zuowei",["xmin","ymin","xmax","ymax"])
for car_i in data_msg_all:
print('数据',car_i)
cv2.rectangle(image, (int(car_i[0]),int(car_i[1])), (int(car_i[2]),int(car_i[3])),
color=(0, 255, 0), thickness=2)
cv2.namedWindow(WIN_NAME, 0)
while True:
cv2.imshow(WIN_NAME,image)
key = cv2.waitKey(1)
if key == ord('q') or key == ord('Q') : # ESC
break
cv2.destroyAllWindows()
3 后期有框占用的计算
API_IOU.py
#!/usr/bin/env python
# encoding: utf-8
import numpy as np
'''
函数说明:计算两个框的重叠面积
输入:
rec1 第一个框xmin ymin xmax ymax
rec2 第二个框xmin ymin xmax ymax
输出:
iouv 重叠比例 0 没有
'''
def compute_iou(rec1, rec2):
# computing area of each rectangles
S_rec1 = (float(rec1[2]) - float(rec1[0])) * (float(rec1[3]) - float(rec1[1])) # H1*W1
S_rec2 = (float(rec2[2]) - float(rec2[0])) * (float(rec2[3]) - float(rec2[1])) # H2*W2
# computing the sum_area
sum_area = S_rec1 + S_rec2 #总面积
# find the each edge of intersect rectangle
left_line = max(float(rec1[0]), float(rec2[0]))
right_line = min(float(rec1[2]), float(rec2[2]))
top_line = max(float(rec1[1]), float(rec2[1]))
bottom_line = min(float(rec1[3]), float(rec2[3]))
# judge if there is an intersect
if left_line >= right_line or top_line >= bottom_line:
#print("没有重合区域")
return 0
else:
#print("有重合区域")
intersect = (right_line - left_line) * (bottom_line - top_line)
#iouv=(float(intersect) / float(sum_area - intersect))*1.0
iouv=(float(intersect) / float(S_rec2))*1.0
return iouv
'''
函数说明:获取两组匹配结果
输入:
rectA 车位
rectB 车辆
threod 重叠面积最小数值界限 默认0.6
输出:
CarUse 一维数组保存是否占用 1 占用 0 没有
'''
def TestCarUse(rectA,rectB,threod=0.6,debug=0):
#threod=0.8#设定最小值
ALength=len(rectA)
BLength=len(rectB)
#创建保存匹配结果的矩阵
recIOU=np.zeros((ALength,BLength),dtype=float,order='C')
#用于记录车位能够使否占用
CarUse=np.zeros((1,ALength),dtype=int,order='C')
for i in range(0,ALength):
for j in range(0,BLength):
iou = compute_iou(rectA[i], rectB[j])
recIOU[i][j]=format(iou,'.3f')
if iou>=threod:
CarUse[0,i]=1 #有一个超过匹配认为车位i被占用
break
if debug==1:
print('----匹配矩阵----')
print(recIOU)
print('----车位占用情况 1占用 0空闲----')
for i in range(0,ALength):
msg='车位编号'+':'+str(i)+"-"+str(CarUse[0][i])
print(msg)
return CarUse
def Use():
#A代表车位
rectA1 = (30, 10, 70, 20)
rectA2 = (70, 10, 80, 20)
rectA =[rectA1,rectA2]
#B代表检测车辆
rectB1 = (20, 10, 35, 20)
rectB2 = (30, 15, 70, 25)
rectB3 = (70, 10, 80, 20)
rectB =[rectB1,rectB2,rectB3]
print(rectB)
#获取车位占用情况 rectA车位 rectB车辆 0.6占面积最小比
CarUse=TestCarUse(rectA,rectB,0.6,1)
print('----车位占用情况----')
for i in range(0,len(CarUse)+1):
msg='车位'+str(i)+"-"+str(CarUse[0][i])
print(msg)
#Use()
浙公网安备 33010602011771号