计算机视觉P4停车场车位检测代码详解
·
停车场车位检测代码详解
一、代码整体功能说明
该代码基于OpenCV、NumPy和skimage库,实现了对单张停车场图片的车位检测功能。通过加载预训练模型,对预设的车位坐标区域进行分析,判断每个车位是否有车,并在图片上标记结果(红色框表示有车,绿色框表示空闲),最终保存并显示处理结果。
二、代码模块详解
1. 库导入
import cv2 # 用于图像处理和显示
import numpy as np # 用于数值计算
import pickle # 用于加载预训练模型
from skimage.transform import resize # 用于图像缩放
from skimage.color import rgb2gray # 用于将图像转为灰度图
cv2:核心图像处理库,负责读取图片、绘制矩形、保存结果等。numpy:提供数组操作能力,支持图像数据的数值计算。pickle:用于加载通过pickle序列化保存的机器学习模型。skimage:提供专业的图像预处理工具(缩放、灰度转换)。
2. 模型加载
try:
model = pickle.load(open('./model.p', 'rb')) # 加载模型文件
except Exception as e:
print(f"模型加载失败:{e}")
exit() # 加载失败则退出程序
- 作用:加载预训练的车位状态检测模型(需确保
model.p文件在当前目录)。 - 异常处理:若模型文件不存在或损坏,捕获错误并提示,避免程序崩溃。
3. 图片读取与预处理
image_path = './first_frame.jpg' # 图片路径
img = cv2.imread(image_path) # 读取图片(OpenCV默认读取为BGR格式)
if img is None:
print("无法读取图片,请检查路径")
exit() # 图片读取失败则退出
# 打印图像信息(用于调试)
img_height, img_width = img.shape[:2]
print(f"图像尺寸:宽={img_width}, 高={img_height}")
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # 转换为RGB格式(模型可能需要RGB输入)
- 图片读取:通过
cv2.imread读取图片,返回None表示读取失败(路径错误或文件损坏)。 - 格式转换:OpenCV默认读取的图片为BGR格式,需转为RGB格式以匹配模型训练时的输入格式。
4. 车位坐标定义
parking_spots = [
(78, 394, 149, 425),
(78, 426, 149, 457),
# ... 省略中间坐标(共455个车位坐标)
(1776, 920, 1833, 949) # 24
]
- 坐标格式:每个车位用
(x1, y1, x2, y2)表示,其中(x1,y1)是矩形左上角坐标,(x2,y2)是右下角坐标。 - 坐标来源:根据停车场实际布局人工标注或自动生成(代码中坐标按固定间隔递增,符合实际车位排列规律)。
5. 车位坐标处理与过滤
对每个车位坐标进行预处理,确保后续能正确提取车位区域:
valid_count = 0 # 有效坐标计数器
invalid_coords = [] # 无效坐标记录
for i, (x1, y1, x2, y2) in enumerate(parking_spots, 1):
# 修复1:统一坐标顺序(确保x1<x2, y1<y2)
x1, x2 = min(x1, x2), max(x1, x2)
y1, y2 = min(y1, y2), max(y1, y2)
# 修复2:坐标截断到图像范围内(避免超出图片边界)
x1 = max(0, x1)
y1 = max(0, y1)
x2 = min(img_width - 1, x2)
y2 = min(img_height - 1, y2)
# 修复3:过滤无效坐标(尺寸过小的区域无意义)
if x2 - x1 < 5 or y2 - y1 < 5:
invalid_coords.append(f"车位{i}: 尺寸过小 ({x1},{y1},{x2},{y2})")
continue
# 提取车位图像(基于处理后的坐标)
spot_img = img_rgb[y1:y2, x1:x2]
if spot_img.size == 0: # 检查区域是否有效
invalid_coords.append(f"车位{i}: 超出有效范围 ({x1},{y1},{x2},{y2})")
continue
- 坐标修复:确保
x1 < x2和y1 < y2(避免因标注错误导致的负数区域)。 - 边界截断:将坐标限制在图片范围内(避免提取超出图片的无效区域)。
- 无效过滤:排除尺寸过小(宽或高<5像素)或超出图片范围的区域,保证后续处理有效。
6. 模型预测与结果标记
# 预处理和预测
try:
# 缩放为训练时的尺寸(15x15,与模型输入一致)
spot_img_resized = resize(spot_img, (15, 15), anti_aliasing=True)
spot_img_flat = spot_img_resized.flatten().reshape(1, -1) # 展平为一维数组
# 模型预测(1表示有车,0表示空闲)
prediction = model.predict(spot_img_flat)[0]
# 亮度过滤(优化预测结果)
gray_spot = rgb2gray(spot_img) # 转为灰度图
brightness = np.mean(gray_spot) # 计算平均亮度
if brightness > 0.6: # 亮度过高时判定为空闲(可能是阳光直射或无车)
prediction = 0
# 绘制矩形和编号
color = (0, 0, 255) if prediction == 1 else (0, 255, 0) # 红=有车,绿=空闲
cv2.rectangle(img, (x1, y1), (x2, y2), color, 2) # 绘制矩形框(线宽2)
# 显示车位编号(避免重叠)
text_pos = (x1 + 5, y1 + 15) # 编号位置(左上角偏移)
cv2.putText(img, f"{i}", text_pos,
cv2.FONT_HERSHEY_SIMPLEX, 0.4, (255, 255, 255), 1) # 白色文字,字重1
valid_count += 1 # 有效车位计数
except Exception as e:
invalid_coords.append(f"车位{i}: 处理失败 - {str(e)}") # 记录处理失败的车位
- 预处理:将车位区域缩放为15x15(模型训练时的输入尺寸),并展平为一维数组。
- 模型预测:通过加载的模型判断车位状态(1=有车,0=空闲)。
- 亮度优化:当车位区域平均亮度>0.6时,强制判定为空闲(解决强光下模型误判问题)。
- 结果标记:用不同颜色的矩形框标记车位状态,并在框内添加编号(便于对应)。
7. 结果统计与保存
# 结果统计
print(f"原始处理车位数量:{len(parking_spots)}")
print(f"有效标记车位:{valid_count}/{len(parking_spots)}")
if invalid_coords:
print("无效坐标列表:")
for msg in invalid_coords[:10]: # 只显示前10个
print(f"- {msg}")
if len(invalid_coords) > 10:
print(f"- 还有{len(invalid_coords)-10}个无效坐标未显示")
# 保存并显示结果
cv2.imwrite('parking_result.jpg', img) # 保存结果图片
# 缩放显示窗口(避免过大)
display_scale = 0.8
display_img = cv2.resize(img, (int(img_width*display_scale), int(img_height*display_scale)))
cv2.imshow('Parking Detection Result', display_img)
cv2.waitKey(0) # 等待按键后关闭窗口
cv2.destroyAllWindows()
- 统计信息:输出总车位数量、有效标记数量及无效坐标原因(便于调试)。
- 结果保存:将标记后的图片保存为
parking_result.jpg。 - 缩放显示:将图片按0.8倍缩放后显示,避免因原图过大导致窗口超出屏幕。
三、完整代码
import cv2
import numpy as np
import pickle
from skimage.transform import resize
from skimage.color import rgb2gray # 直接导入需要的函数
# 1. 加载模型
try:
model = pickle.load(open('./model.p', 'rb'))
except Exception as e:
print(f"模型加载失败:{e}")
exit()
# 2. 读取图片并转换为RGB
image_path = './first_frame.jpg'
img = cv2.imread(image_path)
if img is None:
print("无法读取图片,请检查路径")
exit()
# 打印图像信息(用于排查)
img_height, img_width = img.shape[:2]
print(f"图像尺寸:宽={img_width}, 高={img_height}")
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
# 3. 车位坐标(完整坐标列表)
parking_spots = [
(78, 394, 149, 425),
(78, 426, 149, 457),
(78, 458, 149, 489),
(78, 490, 149, 521),
(78, 522, 149, 553),
(78, 554, 149, 585),
(78, 586, 149, 617),
(78, 618, 149, 649),
(78, 650, 149, 681),
(78, 682, 149, 713),
(78, 714, 149, 745),
(78, 746, 149, 777),
(78, 778, 149, 809),
(78, 810, 149, 841),
(78, 842, 149, 873),
(78, 874, 149, 905),
(78, 906, 149, 937),
(78, 938, 149, 969),
(78, 970, 149, 1001),
(78, 1002, 149, 1033),
(78, 1034, 149, 1065),
#-------------------------------------
(146, 136, 215, 164), # 1
(146, 168, 215, 196), # 2: 136+32=168, 164+32=196
(146, 200, 215, 228), # 3: 168+32=200, 196+32=228
(146, 232, 215, 260), # 4
(146, 264, 215, 292), # 5
(146, 296, 215, 324), # 6
(146, 328, 215, 356), # 7
(146, 360, 215, 388), # 8
(146, 392, 215, 420), # 9
(146, 424, 215, 452), # 10
(146, 456, 215, 484), # 11
(146, 488, 215, 516), # 12
(146, 520, 215, 548), # 13
(146, 552, 215, 580), # 14
(146, 584, 215, 612), # 15
(146, 616, 215, 644), # 16
(146, 648, 215, 676), # 17
(146, 680, 215, 708), # 18
(146, 712, 215, 740), # 19
(146, 744, 215, 772), # 20
(146, 776, 215, 804), # 21
(146, 808, 215, 836), # 22
(146, 840, 215, 868), # 23
(146, 872, 215, 900), # 24
(146, 904, 215, 932), # 25
(146, 936, 215, 964), # 26
(146, 968, 215, 996), # 27
(146, 1000, 215, 1028), # 28
(146, 1032, 215, 1060), # 29
#----------------------------------------
(308, 134, 371, 164), # 1
(308, 166, 371, 196), # 2: 134+32=166, 164+32=196
(308, 198, 371, 228), # 3: 166+32=198, 196+32=228
(308, 230, 371, 260), # 4
(308, 262, 371, 292), # 5
(308, 294, 371, 324), # 6
(308, 326, 371, 356), # 7
(308, 358, 371, 388), # 8
(308, 390, 371, 420), # 9
(308, 422, 371, 452), # 10
(308, 454, 371, 484), # 11
(308, 486, 371, 516), # 12
(308, 518, 371, 548), # 13
(308, 550, 371, 580), # 14
(308, 582, 371, 612), # 15
(308, 614, 371, 642), # 16
(308, 646, 371, 676), # 17
(308, 678, 371, 708), # 18
(308, 710, 371, 740), # 19
(308, 742, 371, 772), # 20
(308, 774, 371, 804), # 21
(308, 806, 371, 836), # 22
(308, 838, 371, 868), # 23
(308, 870, 371, 900), # 24
(308, 902, 371, 932), # 25
(308, 934, 371, 964), # 26
(308, 966, 371, 996), # 27
(308, 998, 371, 1028), # 28
(308, 1030, 371, 1060), # 29
(308, 1062, 371, 1092), # 30
#----------------------------------------
(386, 134, 448, 162), # 1
(386, 166, 448, 194), # 2: 134+32=166, 162+32=194
(386, 198, 448, 226), # 3: 166+32=198, 194+32=226
(386, 230, 448, 258), # 4
(386, 262, 448, 290), # 5
(386, 294, 448, 322), # 6
(386, 326, 448, 354), # 7
(386, 358, 448, 386), # 8
(386, 390, 448, 418), # 9
(386, 422, 448, 450), # 10
(386, 454, 448, 482), # 11
(386, 486, 448, 514), # 12
(386, 518, 448, 546), # 13
(386, 550, 448, 578), # 14
(386, 582, 448, 610), # 15
(386, 614, 448, 642), # 16
(386, 646, 448, 674), # 17
(386, 678, 448, 706), # 18
(386, 710, 448, 738), # 19
(386, 742, 448, 770), # 20
(386, 774, 448, 802), # 21
(386, 806, 448, 834), # 22
(386, 838, 448, 866), # 23
(386, 870, 448, 898), # 24
(386, 902, 448, 930), # 25
(386, 934, 448, 962), # 26
(386, 966, 448, 994), # 27
(386, 998, 448, 1026), # 28
(386, 1030, 448, 1058), # 29
(386, 1062, 448, 1090), # 30
#--------------------------------------------------
(538, 265, 607, 294), # 1
(538, 297, 607, 326), # 2: 265+32=297, 294+32=326
(538, 329, 607, 358), # 3: 297+32=329, 326+32=358
(538, 361, 607, 390), # 4
(538, 393, 607, 422), # 5
(538, 425, 607, 454), # 6
(538, 457, 607, 486), # 7
(538, 489, 607, 518), # 8
(538, 521, 607, 550), # 9
(538, 553, 607, 582), # 10
(538, 585, 607, 614), # 11
(538, 617, 607, 646), # 12
(538, 649, 607, 678), # 13
(538, 681, 607, 710), # 14
(538, 713, 607, 742), # 15
(538, 745, 607, 774), # 16
(538, 777, 607, 806), # 17
(538, 809, 607, 838), # 18
(538, 841, 607, 870), # 19
(538, 873, 607, 902), # 20
(538, 905, 607, 934), # 21
(538, 937, 607, 966), # 22
(538, 969, 607, 998), # 23
(538, 1001, 607, 1030), # 24
(538, 1033, 607, 1062), # 25
(538, 1065, 607, 1094), # 26
#-------------------------------------
(607, 264, 675, 292), # 1
(607, 296, 675, 324), # 2: 264+32=296, 292+32=324
(607, 328, 675, 356), # 3: 296+32=328, 324+32=356
(607, 360, 675, 388), # 4
(607, 392, 675, 420), # 5
(607, 424, 675, 452), # 6
(607, 456, 675, 484), # 7
(607, 488, 675, 516), # 8
(607, 520, 675, 548), # 9
(607, 552, 675, 580), # 10
(607, 584, 675, 612), # 11
(607, 616, 675, 644), # 12
(607, 648, 675, 676), # 13
(607, 680, 675, 708), # 14
(607, 712, 675, 740), # 15
(607, 744, 675, 772), # 16
(607, 776, 675, 804), # 17
(607, 808, 675, 836), # 18
(607, 840, 675, 868), # 19
(607, 872, 675, 900), # 20
(607, 904, 675, 932), # 21
(607, 936, 675, 964), # 22
(607, 968, 675, 996), # 23
(607, 1000, 675, 1028), # 24
(607, 1032, 675, 1060), # 25
(607, 1064, 675, 1092) # 26
#----------------------------------------
,(770, 162, 836, 192),
(770, 194, 836, 224),
(770, 226, 836, 256),
(770, 258, 836, 288),
(770, 290, 836, 320),
(770, 322, 836, 352),
(770, 354, 836, 384),
(770, 386, 836, 416),
(770, 418, 836, 448),
(770, 450, 836, 480),
(770, 482, 836, 512),
(770, 514, 836, 544),
(770, 546, 836, 576),
(770, 578, 836, 608),
(770, 610, 836, 640),
(770, 642, 836, 672),
(770, 674, 836, 704),
(770, 706, 836, 736),
(770, 738, 836, 768),
(770, 770, 836, 800),
(770, 802, 836, 832),
(770, 834, 836, 864),
(770, 866, 836, 896),
(770, 898, 836, 928),
(770, 930, 836, 960),
(770, 962, 836, 992),
(770, 994, 836, 1024),
(770, 1026, 836, 1056),
(770, 1058, 836, 1088)
#------------------------------------
,(836, 163, 904, 191), # 1
(836, 195, 904, 223), # 2: 163+32=195, 191+32=223
(836, 227, 904, 255), # 3: 195+32=227, 223+32=255
(836, 259, 904, 287), # 4
(836, 291, 904, 319), # 5
(836, 323, 904, 351), # 6
(836, 355, 904, 383), # 7
(836, 387, 904, 415), # 8
(836, 419, 904, 447), # 9
(836, 451, 904, 479), # 10
(836, 483, 904, 511), # 11
(836, 515, 904, 543), # 12
(836, 547, 904, 575), # 13
(836, 579, 904, 607), # 14
(836, 611, 904, 639), # 15
(836, 643, 904, 671), # 16
(836, 675, 904, 703), # 17
(836, 707, 904, 735), # 18
(836, 739, 904, 767), # 19
(836, 771, 904, 799), # 20
(836, 803, 904, 831), # 21
(836, 835, 904, 863), # 22
(836, 867, 904, 895), # 23
(836, 899, 904, 927), # 24
(836, 931, 904, 959), # 25
(836, 963, 904, 991) # 26
#--------------------------------------
,(994, 221, 1060, 248), # 1
(994, 253, 1060, 280), # 2: 221+32=253, 248+32=280
(994, 285, 1060, 312), # 3: 253+32=285, 280+32=312
(994, 317, 1060, 344), # 4
(994, 349, 1060, 376), # 5
(994, 381, 1060, 408), # 6
(994, 413, 1060, 440), # 7
(994, 445, 1060, 472), # 8
(994, 477, 1060, 504), # 9
(994, 509, 1060, 536), # 10
(994, 541, 1060, 568), # 11
(994, 573, 1060, 600), # 12
(994, 605, 1060, 632), # 13
(994, 637, 1060, 664), # 14
(994, 669, 1060, 696), # 15
(994, 701, 1060, 728), # 16
(994, 733, 1060, 760), # 17
(994, 765, 1060, 792), # 18
(994, 797, 1060, 824), # 19
(994, 829, 1060, 856), # 20
(994, 861, 1060, 888), # 21
(994, 893, 1060, 920), # 22
(994, 925, 1060, 952) # 23
#---------------------------------------
,(1065, 220, 1130, 248), # 1
(1065, 252, 1130, 280), # 2: 220+32=252, 248+32=280
(1065, 284, 1130, 312), # 3: 252+32=284, 280+32=312
(1065, 316, 1130, 344), # 4
(1065, 348, 1130, 376), # 5
(1065, 380, 1130, 408), # 6
(1065, 412, 1130, 440), # 7
(1065, 444, 1130, 472), # 8
(1065, 476, 1130, 504), # 9
(1065, 508, 1130, 536), # 10
(1065, 540, 1130, 568), # 11
(1065, 572, 1130, 600), # 12
(1065, 604, 1130, 632), # 13
(1065, 636, 1130, 664), # 14
(1065, 668, 1130, 696), # 15
(1065, 700, 1130, 728), # 16
(1065, 732, 1130, 760), # 17
(1065, 764, 1130, 792), # 18
(1065, 796, 1130, 824), # 19
(1065, 828, 1130, 856), # 20
(1065, 860, 1130, 888), # 21
(1065, 892, 1130, 920), # 22
(1065, 924, 1130, 952) # 23
#-------------------------------------
,(1226, 153, 1287, 184), # 1
(1226, 185, 1287, 216), # 2: 153+32=185, 184+32=216
(1226, 217, 1287, 248), # 3: 185+32=217, 216+32=248
(1226, 249, 1287, 280), # 4
(1226, 281, 1287, 312), # 5
(1226, 313, 1287, 344), # 6
(1226, 345, 1287, 376), # 7
(1226, 377, 1287, 408), # 8
(1226, 409, 1287, 440), # 9
(1226, 441, 1287, 472), # 10
(1226, 473, 1287, 504), # 11
(1226, 505, 1287, 536), # 12
(1226, 537, 1287, 568), # 13
(1226, 569, 1287, 600), # 14
(1226, 601, 1287, 632), # 15
(1226, 633, 1287, 664), # 16
(1226, 665, 1287, 696), # 17
(1226, 697, 1287, 728), # 18
(1226, 729, 1287, 760), # 19
(1226, 761, 1287, 792), # 20
(1226, 793, 1287, 824), # 21
(1226, 825, 1287, 856), # 22
(1226, 857, 1287, 888), # 23
(1226, 889, 1287, 920), # 24
(1226, 921, 1287, 952) # 25
#-------------------------------------------
,(1293, 152, 1344, 183), # 1
(1293, 184, 1344, 215), # 2: 152+32=184, 183+32=215
(1293, 216, 1344, 247), # 3: 184+32=216, 215+32=247
(1293, 248, 1344, 279), # 4
(1293, 280, 1344, 311), # 5
(1293, 312, 1344, 343), # 6
(1293, 344, 1344, 375), # 7
(1293, 376, 1344, 407), # 8
(1293, 408, 1344, 439), # 9
(1293, 440, 1344, 471), # 10
(1293, 472, 1344, 503), # 11
(1293, 504, 1344, 535), # 12
(1293, 536, 1344, 567), # 13
(1293, 568, 1344, 599), # 14
(1293, 600, 1344, 631), # 15
(1293, 632, 1344, 663), # 16
(1293, 664, 1344, 695), # 17
(1293, 696, 1344, 727), # 18
(1293, 728, 1344, 759), # 19
(1293, 760, 1344, 791), # 20
(1293, 792, 1344, 823), # 21
(1293, 824, 1344, 855), # 22
(1293, 856, 1344, 887), # 23
(1293, 888, 1344, 919), # 24
(1293, 920, 1344, 951) # 25
#-------------------------------------------
,(1677, 149, 1738, 179), # 1
(1677, 181, 1738, 211), # 2: 149+32=181, 179+32=211
(1677, 213, 1738, 243), # 3: 181+32=213, 211+32=243
(1677, 245, 1738, 275), # 4
(1677, 277, 1738, 307), # 5
(1677, 309, 1738, 339), # 6
(1677, 341, 1738, 371), # 7
(1677, 373, 1738, 403), # 8
(1677, 405, 1738, 435), # 9
(1677, 437, 1738, 467), # 10
(1677, 469, 1738, 499), # 11
(1677, 501, 1738, 531), # 12
(1677, 533, 1738, 563), # 13
(1677, 565, 1738, 595), # 14
(1677, 597, 1738, 627), # 15
(1677, 629, 1738, 659), # 16
(1677, 661, 1738, 691), # 17
(1677, 693, 1738, 723), # 18
(1677, 725, 1738, 755), # 19
(1677, 757, 1738, 787), # 20
(1677, 789, 1738, 819), # 21
(1677, 821, 1738, 851), # 22
(1677, 853, 1738, 883), # 23
(1677, 885, 1738, 915), # 24
(1677, 917, 1738, 947) # 25
#-------------------------------------------
,(1449, 149, 1514, 182), # 1
(1449, 183, 1514, 216), # 2(y1=149+34=183,y2=182+34=216)
(1449, 217, 1514, 250), # 3(y1=183+34=217,y2=216+34=250)
(1449, 251, 1514, 284), # 4
(1449, 285, 1514, 318), # 5
(1449, 319, 1514, 352), # 6
(1449, 353, 1514, 386), # 7
(1449, 387, 1514, 420), # 8
(1449, 421, 1514, 454), # 9
(1449, 455, 1514, 488), # 10
(1449, 489, 1514, 522), # 11
(1449, 523, 1514, 556), # 12
(1449, 557, 1514, 590), # 13
(1449, 591, 1514, 624), # 14
(1449, 625, 1514, 658), # 15
(1449, 659, 1514, 692), # 16
(1449, 693, 1514, 726), # 17
(1449, 727, 1514, 760), # 18
(1449, 761, 1514, 794), # 19
(1449, 795, 1514, 828), # 20
(1449, 829, 1514, 862), # 21
(1449, 863, 1514, 896), # 22
(1449, 897, 1514, 930), # 23
(1449, 931, 1514, 964), # 24
(1449, 965, 1514, 998), # 25
#---------------------------------------
(1520, 153, 1584, 182), # 1
(1520, 187, 1584, 216), # 2(y1=153+34=187;y2=182+34=216)
(1520, 221, 1584, 250), # 3(y1=187+34=221;y2=216+34=250)
(1520, 255, 1584, 284), # 4
(1520, 289, 1584, 318), # 5
(1520, 323, 1584, 352), # 6
(1520, 357, 1584, 386), # 7
(1520, 391, 1584, 420), # 8
(1520, 425, 1584, 454), # 9
(1520, 459, 1584, 488), # 10
(1520, 493, 1584, 522), # 11
(1520, 527, 1584, 556), # 12
(1520, 561, 1584, 590), # 13
(1520, 595, 1584, 624), # 14
(1520, 629, 1584, 658), # 15
(1520, 663, 1584, 692), # 16
(1520, 697, 1584, 726), # 17
(1520, 731, 1584, 760), # 18
(1520, 765, 1584, 794), # 19
(1520, 799, 1584, 828), # 20
(1520, 833, 1584, 862), # 21
(1520, 867, 1584, 896), # 22
(1520, 901, 1584, 930), # 23
(1520, 935, 1584, 964), # 24
(1520, 969, 1584, 998) # 25
#-----------------------------------------
,(1776, 184, 1833, 213), # 1
(1776, 216, 1833, 245), # 2(y1=184+32=216;y2=213+32=245)
(1776, 248, 1833, 277), # 3(y1=216+32=248;y2=245+32=277)
(1776, 280, 1833, 309), # 4
(1776, 312, 1833, 341), # 5
(1776, 344, 1833, 373), # 6
(1776, 376, 1833, 405), # 7
(1776, 408, 1833, 437), # 8
(1776, 440, 1833, 469), # 9
(1776, 472, 1833, 501), # 10
(1776, 504, 1833, 533), # 11
(1776, 536, 1833, 565), # 12
(1776, 568, 1833, 597), # 13
(1776, 600, 1833, 629), # 14
(1776, 632, 1833, 661), # 15
(1776, 664, 1833, 693), # 16
(1776, 696, 1833, 725), # 17
(1776, 728, 1833, 757), # 18
(1776, 760, 1833, 789), # 19
(1776, 792, 1833, 821), # 20
(1776, 824, 1833, 853), # 21
(1776, 856, 1833, 885), # 22
(1776, 888, 1833, 917), # 23
(1776, 920, 1833, 949) # 24
]
print(f"原始处理车位数量:{len(parking_spots)}")
# 4. 处理每个车位
valid_count = 0 # 有效坐标计数器
invalid_coords = [] # 无效坐标记录
for i, (x1, y1, x2, y2) in enumerate(parking_spots, 1):
# 修复1:统一坐标顺序(确保x1<x2, y1<y2)
x1, x2 = min(x1, x2), max(x1, x2)
y1, y2 = min(y1, y2), max(y1, y2)
# 修复2:坐标截断到图像范围内
x1 = max(0, x1)
y1 = max(0, y1)
x2 = min(img_width - 1, x2)
y2 = min(img_height - 1, y2)
# 修复3:过滤无效坐标(至少保持最小矩形尺寸)
if x2 - x1 < 5 or y2 - y1 < 5:
invalid_coords.append(f"车位{i}: 尺寸过小 ({x1},{y1},{x2},{y2})")
continue
# 提取车位图像
spot_img = img_rgb[y1:y2, x1:x2]
if spot_img.size == 0:
invalid_coords.append(f"车位{i}: 超出有效范围 ({x1},{y1},{x2},{y2})")
continue
# 预处理和预测
try:
# 缩放为训练时的尺寸
spot_img_resized = resize(spot_img, (15, 15), anti_aliasing=True)
spot_img_flat = spot_img_resized.flatten().reshape(1, -1)
# 模型预测
prediction = model.predict(spot_img_flat)[0]
# 亮度过滤
gray_spot = rgb2gray(spot_img)
brightness = np.mean(gray_spot)
if brightness > 0.6:
prediction = 0 # 亮度高判定为空闲
# 绘制矩形和编号
color = (0, 0, 255) if prediction == 1 else (0, 255, 0) # 红=有车,绿=空闲
cv2.rectangle(img, (x1, y1), (x2, y2), color, 2)
# 优化编号显示(避免重叠)
text_pos = (x1 + 5, y1 + 15)
cv2.putText(img, f"{i}", text_pos,
cv2.FONT_HERSHEY_SIMPLEX, 0.4, (255, 255, 255), 1)
valid_count += 1
except Exception as e:
invalid_coords.append(f"车位{i}: 处理失败 - {str(e)}")
# 5. 结果统计
print(f"有效标记车位:{valid_count}/{len(parking_spots)}")
if invalid_coords:
print("无效坐标列表:")
for msg in invalid_coords[:10]: # 只显示前10个
print(f"- {msg}")
if len(invalid_coords) > 10:
print(f"- 还有{len(invalid_coords)-10}个无效坐标未显示")
# 6. 保存并显示(优化显示尺寸)
cv2.imwrite('parking_result.jpg', img)
# 缩放显示窗口(避免过大)
display_scale = 0.8
display_img = cv2.resize(img, (int(img_width*display_scale), int(img_height*display_scale)))
cv2.imshow('Parking Detection', display_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
结果图示:
停车场车位识别系统

更多推荐
所有评论(0)