OpenCV计算机视觉实战(Python)| 14、项目实战:停车场车位识别

简介

本节为《OpenCV计算机视觉实战(Python)》版第14讲,项目实战:停车场车位识别,的总结。

总结

1、项目介绍

统计:

  1. 有多少停车位
  2. 哪些个停车位被占据,哪些个停车位没有被占据
    在这里插入图片描述

2、步骤

  1. 选取区域:人工选择停车场所在的位置,只保存停车场所在的区域图像
  2. 预处理:灰度、边缘、霍夫
  3. 微调:针对实际的项目,由于背景是没变的,当结果不正确时,可以人为给定数据对结果进行微调
  4. 分类:以簇的形式,将每一列的停车场数据保存,保存每一列矩阵的坐标点
  5. 分割:以实际项目选取合适的值,将每一列分割成一个个小块,每一个小块代表一个停车场的位置
  6. 深度训练:以空停车位做分类训练,判断停车场某个停车位上有没有车;

3、程序

Parking.py:

class Parking:

	def cv_show(name, image):
		cv2.imshow(name, image)
		cv2.waitKey(0)
		cv2.destroyAllWindows()
	
	def select_rgb_white_yellow(self, image):
		# 过滤掉背景
		lower = np.uint8([120, 120, 120])
		upper = np.uint8([255, 255, 255])
		# lower_red和高于upper_red的部分分别变成0,lower_red-upper_red之间的值变成255,相当于过滤背景
		white_mask = cv2.inRange(image, lower, upper)
		self.cv_show('white_mask', white_mask)
		
		masked = cv2.bitwise_and(image, image, mask=white_mask)
		self.cv_show('masked', masked)
		return masked
	
	def convert_gray_scale(self, image):
		return cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
	def detect_edges(self, image, low_threshold=50, high_threshold=200):
		return cv2.Canny(image, low_threshold, high_threshold)
	
	def filter_region(self, image, vertices):
		 """
		 剔除掉不需要的地方
		 """
		 mask = np.zeros_like(image)
		 if len(mask.shape)==2:
		 	cv2.fillPoly(mask, vertices, 255)
		 	self.cv_show('mask', mask)
		 return cv2.bitwise_and(image, mask)
		
	def select_region(self, image):
		"""
		手动选择区域
		"""	
		# first, define the polygon by vertices
		rows, cols = image.shape[:2]
		pt_1 = [cols*0.05, rows * 0.90]
		pt_2 = [cols*0.05, rows * 0.70]
		pt_3 = [cols*0.30, rows * 0.55]
		pt_4 = [cols*0.6, rows * 0.15]
		pt_5 = [cols*0.90, rows * 0.15]
		pt_6 = [cols*0.90, rows * 0.90]
	
		vertices = np.array([[pt_1, pt_2, pt_3, pt_4, pt_5, pt_6]], dtype=np.int32)
		point_img = img.copy()
		point_img = cv2.cvtcolor(point_img, cv2.COLOR_GRAY2RGB)
		for point in vertices[0]:
			cv2.circle(point_img, (point[0], point[1]), 10, (0,0.255), 4)
		self.cv_show('point_img', point_img)
		return self.filter_region(image, vertices)
	
	def hough_lines(self, image):
		#阈值越大,直线越少
		return cv2.HoughLinesP(image, rho=0.1, theta=np.pi/10, threshold=15, minLineLength=0, maxLineGap=4)
	def draw_lines(self, image, lines, color=[255, 0, 0], thickness=2, make_cope=True):
		# 过滤霍夫变换坚持到到直线
		if make_copy:
			image = np.copy(image)
		cleaned = []
		for line in lines:
			for x1,y1,x2,y2 in line:
				if abs(y2-y1) <=1 and abs(x2-x1)>25 and abs(x2-x1)<=55:
					cleaned.append((x1, y1, x2, y2))
					cv2.line(image, (x1,y1), (x2,y2), color, thickness)
		print('No lines detected:', len(cleaned))
		return image
	
	def identify_blocks(self, image, lines, make_copy=TRUE):
		if make_copy:
			new_image = np.copy(image)
		# step1:过滤部分直线
		cleaned = []
		for line in lines:
			for x1, y1, x2, y2 in line:
				if abs(y2-y1)<=1 and abs(x2-x1)>=25 and abs(x2-x1)<=55:
					cleaned.append((x1,y1,x2,y2))
		# Step2:对直线按照x1进行排序
		import operator
		list1 = sorted(cleaned, key=operator.itemgetter(0,1))
	
		# Step3: 找到多个列,相当于每列是一排车
		clusters = {}
		dIndex = 0
		clus_dist = 10
		
		for i in range(len(list1) - 1):
			distance = abs(list1[i+1][0] - list1[i][0])
			if distance <= clus_dist:
				if not dIndex in clusters.keys():clusters[dIndex] = []
				clusters[dIndex].append(list1[i])
				clusters[dIndex].append(list1[i+1])
			else:
				dIndex +=1
		# Step4:得到坐标
		rects = {}
		i = 0
		for key in clusters:
			all_list = clusters[key]
			cleaned = list(set(all_list))
			if len(cleaned) > 5:
				cleaned = sorted(cleaned, key = lambda tup:tup[1])
				avg_y1 = cleaned[0][1]
				avg_y2 = cleaned[-1][1]
				avg_x1 = 0
				avg_x2 = 0
				for tup in cleaned:
					avg_x1 += tup[0]
					avg_x2 += tup[2]
				avg_x1 = avg_x1/len(cleaned)
				avg_x2 = avg_x2/len(cleaned)
				rects[i] = (avg_x1, avg_y1, avg_x2, avg_y2)
				i +=1
		print('Num parking Lanes:', len(rects))
		# Step5:得到坐标
		rects = {}
		i = 0
		for key in clusters:
			all_list=cluseters[kye]
			cleaned = list(set(all_list))
			if len(cleaned) > 5:
				cleaned = sorted(cleaned, key=lambda tup:tup[1])
				avg_y1 = cleaned[0][1]
				avg_y2 = cleaned[-1][1]
				avg_x1 = 0
				avg_x2 = 0
				for tup in cleaned:
					avg_x1 += tup[0]
					avg_x2 += tup[2]
				avg_x1 = avg_x1/len(cleaned)
				avg_x2 = avg_x2/len(cleaned)
				rects[i] = (avg_x1, avg_y1, avg_x2, avg_y2)
				i+=1
		print('Num Parking Lanes:', len(rects))
		# Step5: 把列矩形给画出来
		buff = 7
		for key in rects:
			tup_topLeft = (int(rects[key][0] - buff), int(rects[key][1]))
			tup_botRight = (int(rects[key][2] + buff), int(rects[key][3]))
			cv2.rectangle(new_image, tup_topLeft, tup_botRight, (0,255,0),3)
		return new_image, rects
	def draw_parking(self, image, rects, make_copy=True,, color=[255,0,0], thickness=2,save=True):
		if make_copy:
			new_image = np.copy(image)
		gap = 15.5
		spot_dict = {} # 字典:一个车位对应一个位置
		tot_spots = 0
		#微调
		adj_y1 = {0:20, 1:-10, 2:0, 3:-11, 4:28, 5:5, 6:-15, 7:-15, 8:-10, 9:-30, 10:9, 11:-32}
		adj_y2 = {0:30, 1:50, 2:15, 3:10, 4:-15, 5:15, 6:15, 7:-20, 8:15, 9:15, 10:0, 11:30}
		adj_x1 = {}
		adj_x2 = {}
		for key in rects:
			tup = rects[key]
			x1 = int(tup[0]+adj_x1[key])
			x2 = int(tup[2] + adj_x2[key])
			y1 = int(tup[1] + adj_y1[key])
			y2 = int(tup[3] + adj_y2[key])
			cv2.rectangle(new_image, (x1,y1), (x2, y2), (0,255,0), 2)
			num_splits = int(abs(y2-y1)//gap)
			for in in range(0, num_splits +1):
				y = int(y1 + i*gap)
				cv2.line(new_image, (x1, y), (x2, y), color, thickness)
			if key>0 and key<len(rects)-1:
				# 竖直线
				x = int((x1+x2)/2
				cv.line(new_image, (x, y1), (x,y2), color, thickness)
			# 计算数量
			if key == 0 or key == (len(rects) -1):
				tot_spots += num_splits +1
			else:
				tot_spots += 2*(num_splits + 1)
			# 字典对应好
			if key ==9 or key == len(rects) -1):
				for i in range(0, num_splits +1):
					cur_len = len(spot_dict)
					y = int(y1 + i * gap)
					spot_dict[(x1, y, x2, y+gap)] = cur_len + 1
			else:
				for i in range(0, num_splits +1):
					cur_len  = len(spot_dict)
					y = int(y1 + i * gap)
					x = int((x1 + x2)/2)
					spot_dict[(x1, y, x, y+gap)] = cur_len + 1
					spot_dict[(x, y, x2, y+gap)] = cur_len + 2
		print('total parking spaces:', tot_spots, cur_len)
		if save:
			filename = 'with_parking.jpg'
			cv2.imwrite(filename, new_image)
		return new_image, splt_dict
	def save_images_for_cnn(self, image, spot_dict, folder_name = 'cnn_data'):
		for spot in spot_dict.keys():
			(x1, y1, x2, y2) = spot
			(x1, y1, x2, y2) = (int(x1), int(y1), int(x2), int(y2))
			#裁剪
			spot_img = image[y1:y2, x1:x2]
			spot_img = cv2.resize(spot_img, (0,0), fx=2.0, fy=2.0)
			spot_id = spot_dict[spot]
			
			filename = 'spot' + str(spot_id) + '.jpg'
			print(spot_img.shape, filename, (x1,x2, y1, y2))
			cv2.imwrite(os.path.join(folder_name, filename), spot_img)
			

train.py:(神经网络训练文件,此处略去)

import numpy as np
...

main.py:(主程序)

from __future__ import division
import matplotlib.pyplot as plt
import cv2
import os,glob
import numpy as np
from PIL import Image
from keras.applications.imagenet_utils import preprocess_input
from keras.models import image
from keras.preprocessing import image
from Parking import Parking
import pickle

cwd = os.getcwd()

def img_process(test_images, park):

	white_yellow_images = list(map(park.select_rgb_white_yellow, test_images))
	park.show_images(white_yellow_images)
	
	gray_images = list(map(park.convert_gray_scale, white_yellow_images))
	park.show_images(gray_images)

	edge_images = list(map(lambda image:park.detect_edges(image), gray_images))
	park.show_images(edge_images)

	roi_images = list(map(park.select_region, edge_images))
	park.show_images(roi_images)

	list_of_lines = list(map(park.hough_lines, roi_images))
	
	line_images = []
	for image, lines in zip(test_images, list_of_lines):
		line_images.append(park.draw_lines(image, lines))
	park.show_images(lien_images)

	rect_images = []
	rect_coords = []
	for image, lines in zip(test_images, list_of_lines):
		new_image, rects = park.identify_blocks(image, lines)
		rect_images.append(new_image)
		rect_coords.append(rects)
	park.show_images(rect_images)

	delineated = []
	spot_pos = []
	for image, rects in zip(test_images, rect_coords):
		new_image, spot_dict = park.draw_parking(image, rects)
		delineated.append(new_image)
		spot_pos.append(spot_dict)
	
	park.show_images(delineated)
	final_spot_dict = spot_pos[1]
	print(len(final_spot_dict)
	
	with open('spot_dict.pickle', 'wb') as handle:
		pickle.dump(final_spot_dict, handle, protocol=pickle.HIGHEST_PROTOCOL)
	
	park.save_images_for_cnn(test_images[0], final_spot_dict)
	return final_spot_dict
def keras_model(weights_path):
	model = load_model(weights_path)
	return model
def img_test(test_images, final_spot_dict, model, class_dictionary):
	for i in range(len(test_images)):
		predicted_images = park.predict_on_image(test_images[i], final_spot_dict, class_dictionary)


if __name__ == '__main__':
	test_images = [plt.imread(path) for path in glob.glob('test_images/*.jpg')]
	weights_path = 'car1.h5'
	video_name = 'parking_video.mp4'
	class_dictionary[0] = 'empty'
	class_dictionary[1] = 'occupied'
	park = Parking()
	park.show_images(test_images)
	final_spot_dict = img_process(test_images, park)

	# 本文所附录出的程序代码仅到img_process处,往下的这些代码没有给出,感兴趣的可以自行看课程
	model = keras_model(weights_path)
	img_test(test_images, final_spot_dict, model, class_dictionary)
	video_test(video_name, final_spot_dict, model, class_dictionary)
	
	
  • 4
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值