forked from tjiiv-cprg/SPFCN-ParkingSlotDetection
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit b3c0e00
Showing
21 changed files
with
1,249 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
# Auto detect text files and perform LF normalization | ||
* text=auto |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
# Byte-compiled / optimized / DLL files | ||
__pycache__/ | ||
*.py[cod] | ||
*$py.class | ||
|
||
# C extensions | ||
*.so | ||
|
||
# Distribution / packaging | ||
.Python | ||
build/ | ||
develop-eggs/ | ||
dist/ | ||
downloads/ | ||
eggs/ | ||
.eggs/ | ||
lib/ | ||
lib64/ | ||
parts/ | ||
sdist/ | ||
var/ | ||
wheels/ | ||
pip-wheel-metadata/ | ||
share/python-wheels/ | ||
*.egg-info/ | ||
.installed.cfg | ||
*.egg | ||
MANIFEST | ||
|
||
# PyInstaller | ||
# Usually these files are written by a python script from a template | ||
# before PyInstaller builds the exe, so as to inject date/other infos into it. | ||
*.manifest | ||
*.spec | ||
|
||
# Installer logs | ||
pip-log.txt | ||
pip-delete-this-directory.txt | ||
|
||
# Unit test / coverage reports | ||
htmlcov/ | ||
.tox/ | ||
.nox/ | ||
.coverage | ||
.coverage.* | ||
.cache | ||
nosetests.xml | ||
coverage.xml | ||
*.cover | ||
*.py,cover | ||
.hypothesis/ | ||
.pytest_cache/ | ||
|
||
# Translations | ||
*.mo | ||
*.pot | ||
|
||
# Django stuff: | ||
*.log | ||
local_settings.py | ||
db.sqlite3 | ||
db.sqlite3-journal | ||
|
||
# Flask stuff: | ||
instance/ | ||
.webassets-cache | ||
|
||
# Scrapy stuff: | ||
.scrapy | ||
|
||
# Sphinx documentation | ||
docs/_build/ | ||
|
||
# PyBuilder | ||
target/ | ||
|
||
# Jupyter Notebook | ||
.ipynb_checkpoints | ||
|
||
# IPython | ||
profile_default/ | ||
ipython_config.py | ||
|
||
# pyenv | ||
.python-version | ||
|
||
# pipenv | ||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. | ||
# However, in case of collaboration, if having platform-specific dependencies or dependencies | ||
# having no cross-platform support, pipenv may install dependencies that don't work, or not | ||
# install all needed dependencies. | ||
#Pipfile.lock | ||
|
||
# celery beat schedule file | ||
celerybeat-schedule | ||
|
||
# SageMath parsed files | ||
*.sage.py | ||
|
||
# Environments | ||
.env | ||
.venv | ||
env/ | ||
venv/ | ||
ENV/ | ||
env.bak/ | ||
venv.bak/ | ||
|
||
# Spyder project settings | ||
.spyderproject | ||
.spyproject | ||
|
||
# Rope project settings | ||
.ropeproject | ||
|
||
# mkdocs documentation | ||
/site | ||
|
||
# mypy | ||
.mypy_cache/ | ||
.dmypy.json | ||
dmypy.json | ||
|
||
# Pyre type checker | ||
.pyre/ | ||
|
||
.idea |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
# SPFCN: Select and Prune the Fully Convolutional Networks for Real-time Parking Slot Detection | ||
|
||
The pytorch implement of the real-time parking slot detection method SPFCN. | ||
|
||
Paper link: https://arxiv.org/abs/2003.11337 | ||
|
||
## Table of Content | ||
- [Abstract](#Abstract) | ||
- [Usage](#Usage) | ||
- [Performance](#Performance) | ||
- [Demo](#Demo) | ||
|
||
## Abstract | ||
For passenger cars equipped with automatic parking function, convolutional neural networks(CNN) are employed to detect parking slots on the panoramic surround view, which is an overhead image synthesized by four calibrated fish-eye images, The accuracy is obtained at the price of low speed or expensive computation equipments, which are sensitive for many car manufacturers. In this paper, the same accuracy is challenged by the proposed parking slot detector, which leverages deep convolutional networks for the faster speed and smaller model while keep the accuracy by simultaneously training and pruning it. To achieve the optimal trade-off, we developed a strategy to select the best receptive fields and prune the redundant channels automatically during training. The proposed model is capable of jointly detecting corners and line features of parking slots while running efficiently in real time on average CPU. Even without any specific computing devices, the model outperforms existing counterparts, at a frame rate of about 30 FPS on a 2.3 GHz CPU core, getting parking slot corner localization error of 1.51±2.14 cm (std. err.) and slot detection accuracy of 98%, generally satisfying the requirements in both speed and accuracy on on-board mobile terminals. | ||
|
||
## Usage | ||
Detailed instructions will be given soon. | ||
|
||
## Performance | ||
The training and test data set is https://cslinzhang.github.io/deepps/ | ||
| Method | Allowable deviation/cm | Parameter size/MB | Precision | Recall | | ||
| :------: | :------: | :------:| :------: | :------: | | ||
| PSD\_L| 16 | 8.38 | 0.9855 | 0.8464 | | ||
| DeepPS| 16 | 255 | **0.9954** | **0.9889** | | ||
| SPFCN(ours)| 6 |**2.39** | 0.9801 | 0.9731 | | ||
|
||
## Demo | ||
![image](https://github.com/LoyalBlanc/SPFCN-ParkingSlotDetection/blob/master/Demo/SPFCN-5s.gif) | ||
|
||
A one-minute demo video can be seen in Demo/IV2020_SPFCN.mp4 | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import torch | ||
from torch.backends import cudnn | ||
|
||
from .dataset import get_training_set, get_validating_set | ||
from .model.network import SlotNetwork | ||
from .train import auto_train, auto_validate | ||
|
||
|
||
def setup(seed): | ||
torch.manual_seed(seed) | ||
torch.cuda.manual_seed(seed) | ||
cudnn.benchmark = True | ||
cudnn.deterministic = True | ||
|
||
|
||
def slot_network_training(device_id=1): | ||
# Initial | ||
setup(19960229) | ||
net = SlotNetwork([32, 44, 64, 92, 128], device_id=device_id) | ||
|
||
# Train | ||
auto_train(get_training_set(6535, 50, 224, device_id), net, device_id=device_id, | ||
epoch_limit=1000, save_path="parameters/") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import torch | ||
from torch.utils.data import DataLoader | ||
|
||
from .dataset import VisionParkingSlotDataset | ||
from .prefetcher import DataPrefetcher | ||
|
||
|
||
def get_training_set(data_size: int, | ||
batch_size: int, | ||
resolution: int = 224, | ||
device_id: int = 0): | ||
assert 0 < data_size < 6596 and 0 < batch_size and 0 < resolution | ||
|
||
vps_set = VisionParkingSlotDataset( | ||
image_path="/mnt/Airdrop/ps_zhanglin/training/", | ||
label_path="/mnt/Airdrop/ps_zhanglin/training_raw_label/", | ||
data_size=data_size, | ||
resolution=resolution) | ||
if device_id < 0: | ||
return DataLoader(dataset=vps_set, shuffle=True, batch_size=batch_size, num_workers=4) | ||
else: | ||
return DataPrefetcher(device=torch.device('cuda:%d' % device_id), | ||
dataset=vps_set, batch_size=batch_size, shuffle=True) | ||
|
||
|
||
def get_validating_set(data_size: int, | ||
batch_size: int, | ||
resolution: int = 224, | ||
device_id: int = 0): | ||
assert 0 < data_size < 1538 and 0 < batch_size and 0 < resolution | ||
vps_set = VisionParkingSlotDataset( | ||
image_path="/mnt/Airdrop/ps_zhanglin/testing/all/all/", | ||
label_path="/mnt/Airdrop/ps_zhanglin/testing/all/raw_label/", | ||
data_size=data_size, | ||
resolution=resolution) | ||
if device_id < 0: | ||
return DataLoader(dataset=vps_set, shuffle=True, batch_size=batch_size, num_workers=4) | ||
else: | ||
return DataPrefetcher(device=torch.device('cuda:%d' % device_id), | ||
dataset=vps_set, batch_size=batch_size, shuffle=False) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
import os | ||
|
||
import cv2 | ||
import numpy as np | ||
from scipy.io import loadmat | ||
from torch.utils.data import Dataset | ||
|
||
GAUSSIAN_VALUE = np.array([[0.0111, 0.0388, 0.0821, 0.1054, 0.0821, 0.0388, 0.0111], | ||
[0.0388, 0.1353, 0.2865, 0.3679, 0.2865, 0.1353, 0.0388], | ||
[0.0821, 0.2865, 0.6065, 0.7788, 0.6065, 0.2865, 0.0821], | ||
[0.1054, 0.3679, 0.7788, 1.0000, 0.7788, 0.3679, 0.1054], | ||
[0.0821, 0.2865, 0.6065, 0.7788, 0.6065, 0.2865, 0.0821], | ||
[0.0388, 0.1353, 0.2865, 0.3679, 0.2865, 0.1353, 0.0388], | ||
[0.0111, 0.0388, 0.0821, 0.1054, 0.0821, 0.0388, 0.0111]]) | ||
|
||
|
||
class VisionParkingSlotDataset(Dataset): | ||
def __init__(self, image_path, label_path, data_size, resolution): | ||
self.length = data_size | ||
self.image_list = [] | ||
self.label_list = [] | ||
index = 0 | ||
for item_name in os.listdir(image_path): | ||
item_label = loadmat("%s%s.mat" % (label_path, item_name[:-4])) | ||
slots = item_label['slots'] | ||
if len(slots) > 0: | ||
item_image = cv2.resize(cv2.imread(image_path + item_name), (resolution, resolution)) | ||
item_image = np.transpose(item_image, (2, 0, 1)) | ||
self.image_list.append(item_image) | ||
|
||
marks = item_label['marks'] | ||
mark_label = self._get_mark_label(marks, slots, resolution) | ||
slot_label = np.zeros([3, resolution, resolution]) | ||
for mark in mark_label: | ||
slot_label[0, mark[1] - 3:mark[1] + 4, mark[0] - 3:mark[0] + 4] += GAUSSIAN_VALUE | ||
slot_label[1, mark[1] - 3:mark[1] + 4, mark[0] - 3:mark[0] + 4] += mark[2] | ||
slot_label[2, mark[1] - 3:mark[1] + 4, mark[0] - 3:mark[0] + 4] += mark[3] | ||
self.label_list.append(slot_label) | ||
|
||
index += 1 | ||
if index == data_size: | ||
break | ||
|
||
@staticmethod | ||
def _get_mark_label(marks, slots, resolution): | ||
""" | ||
:param marks: x, y | ||
:param slots: pt1, pt2, _, rotate_angle | ||
:param resolution: 224x224 | ||
:return: | ||
""" | ||
temp_mark_label = [] | ||
for mark in marks: | ||
mark_x_re, mark_y_re = mark[0] * resolution / 600, mark[1] * resolution / 600 | ||
temp_mark_label.append([mark_x_re, mark_y_re, [], []]) | ||
|
||
for slot in slots: | ||
mark_vector = marks[slot[1] - 1] - marks[slot[0] - 1] | ||
mark_vector_length = np.sqrt(mark_vector[0] ** 2 + mark_vector[1] ** 2) | ||
if mark_vector[0] > 0: | ||
mark_direction = np.arcsin(mark_vector[1] / mark_vector_length) | ||
else: | ||
mark_direction = np.pi - np.arcsin(mark_vector[1] / mark_vector_length) | ||
slot_direction = mark_direction - slot[3] * np.pi / 180 | ||
slot_cos = np.cos(slot_direction) | ||
slot_sin = np.sin(slot_direction) | ||
|
||
temp_mark_label[slot[0] - 1][2].append(slot_cos) | ||
temp_mark_label[slot[0] - 1][3].append(slot_sin) | ||
temp_mark_label[slot[1] - 1][2].append(slot_cos) | ||
temp_mark_label[slot[1] - 1][3].append(slot_sin) | ||
|
||
mark_label = [] | ||
for mark in temp_mark_label: | ||
if len(mark[2]) > 0: | ||
mark_cos = np.mean(mark[2]) | ||
mark_sin = np.mean(mark[3]) | ||
mark_angle_base = np.sqrt(mark_cos ** 2 + mark_sin ** 2) | ||
mark_cos = mark_cos / mark_angle_base | ||
mark_sin = mark_sin / mark_angle_base | ||
mark_label.append([int(round(mark[0])), int(round(mark[1])), mark_cos, mark_sin]) | ||
return mark_label | ||
|
||
def __getitem__(self, item): | ||
return self.image_list[item], self.label_list[item] | ||
|
||
def __len__(self): | ||
return self.length |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import torch | ||
from torch.utils.data import DataLoader | ||
|
||
|
||
class DataPrefetcher(object): | ||
def __init__(self, dataset, batch_size, shuffle, device): | ||
self.stream = torch.cuda.Stream(device=device) | ||
self.device = device | ||
|
||
self.loader = DataLoader(dataset=dataset, shuffle=shuffle, batch_size=batch_size, | ||
num_workers=4, pin_memory=True) | ||
self.fetcher = None | ||
self.next_images = None | ||
self.next_labels = None | ||
|
||
def refresh(self): | ||
self.fetcher = iter(self.loader) | ||
self.preload() | ||
|
||
def preload(self): | ||
try: | ||
self.next_images, self.next_labels = next(self.fetcher) | ||
except StopIteration: | ||
self.next_images = None | ||
self.next_labels = None | ||
else: | ||
with torch.cuda.stream(self.stream): | ||
self.next_images = self.next_images.to(self.device).float() | ||
self.next_labels = self.next_labels.to(self.device).float() | ||
|
||
def next(self): | ||
torch.cuda.current_stream(device=self.device).wait_stream(self.stream) | ||
current_images = self.next_images | ||
current_labels = self.next_labels | ||
if current_images is not None: | ||
current_images.record_stream(torch.cuda.current_stream(device=self.device)) | ||
current_labels.record_stream(torch.cuda.current_stream(device=self.device)) | ||
self.preload() | ||
return current_images, current_labels |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
from .network import SlotNetwork |
Oops, something went wrong.