参考
图书馆空位检测(行人+空位对比)
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 onm ouse_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, onm ouse_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 onm ouse_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()
标签:xml,draw,dom,python,self,矩形框,rects,节点,rect From: https://www.cnblogs.com/gooutlook/p/16777205.html