Skip to content

Commit

Permalink
update README and add option to disable lane fit feature
Browse files Browse the repository at this point in the history
  • Loading branch information
MaybeShewill-CV committed May 28, 2022
1 parent 5f704c8 commit 3e30757
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 8 deletions.
43 changes: 43 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,49 @@ cd MNN_PROJECT_ROOT_DIR/tools/converter/build
Add lanenet source code into MNN project and modified CMakeList.txt to
compile the executable binary file.

## Recently updates 2022.05.28

Since lots of user have encountered with a empty mask image problem when they do model inference using their own custom
data. For example the user [issue](https://github.com/MaybeShewill-CV/lanenet-lane-detection/issues/382) have encountered
such a problem. I have openend a discussion [here](https://github.com/MaybeShewill-CV/lanenet-lane-detection/discussions/561#discussion-4104802)
to give some advice to solve those problem.

That problem mainly caused by the dbscan cluster's params was not properly adjusted for custom data. For example if I use
the default dbscan param settled [here](https://github.com/MaybeShewill-CV/lanenet-lane-detection/blob/5f704c86759b0b65955fb27c85a42f343c1c8c5c/config/tusimple_lanenet.yaml#L90-L93)
```
POSTPROCESS:
MIN_AREA_THRESHOLD: 100
DBSCAN_EPS: 0.35
DBSCAN_MIN_SAMPLES: 1000
```
The inference result was
![black_mask](./data/source_image/black_mask.png)

When I enlarge the dbscan DBSCAN_EPS param from 0.35 to 0.5 and reduce DBSCAN_MIN_SAMPLES from 1000 to 250. The infer
ence result was
![black_mask_after_adjust](./data/source_image/black_mask_after_adjust.png)

Some more detailed discussion you may find in [discussion module](https://github.com/MaybeShewill-CV/lanenet-lane-detection/discussions/561#discussion-4104802)

The lane fit process in postprocess module was designed for tusimple dataset which means it can not work well on your
custorm data. So I add an option in testing scripts to disable this feature when processing custom data. It will plot
mask image directly upon source image

```
python tools/test_lanenet.py --weights_path /PATH/TO/YOUR/CKPT_FILE_PATH
--image_path ./data/custom_test_image/test.png --with_lane_fit 0
```

Before you test the example custom data remember to adjust dbscan cluster params following instruction above and the test
result should be like
![black_mask_after_adjust](./data/source_image/black_mask_after_adjust.png)

To get better lane detection result on your own local custom data you'd better train your own model on custom dataset rather
directly using the pretrained model.

Hope it helps:)


## TODO
- [x] Add a embedding visualization tools to visualize the embedding feature map
- [x] Add detailed explanation of training the components of lanenet separately.
Expand Down
23 changes: 18 additions & 5 deletions lanenet_model/lanenet_postprocess.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,12 @@

import cv2
import numpy as np
import loguru
from sklearn.cluster import DBSCAN
from sklearn.preprocessing import StandardScaler

LOG = loguru.logger


def _morphological_process(image, kernel_size=5):
"""
Expand Down Expand Up @@ -164,7 +167,7 @@ def _embedding_feats_dbscan_cluster(self, embedding_image_feats):
features = StandardScaler().fit_transform(embedding_image_feats)
db.fit(features)
except Exception as err:
log.error(err)
LOG.error(err)
ret = {
'origin_features': None,
'cluster_nums': 0,
Expand Down Expand Up @@ -199,8 +202,6 @@ def _get_lane_embedding_feats(binary_seg_ret, instance_seg_ret):
"""
idx = np.where(binary_seg_ret == 255)
lane_embedding_feats = instance_seg_ret[idx]
# idx_scale = np.vstack((idx[0] / 256.0, idx[1] / 512.0)).transpose()
# lane_embedding_feats = np.hstack((lane_embedding_feats, idx_scale))
lane_coordinate = np.vstack((idx[1], idx[0])).transpose()

assert lane_embedding_feats.shape[0] == lane_coordinate.shape[0]
Expand Down Expand Up @@ -239,7 +240,6 @@ def apply_lane_feats_cluster(self, binary_seg_result, instance_seg_result):
return None, None

lane_coords = []

for index, label in enumerate(unique_labels.tolist()):
if label == -1:
continue
Expand Down Expand Up @@ -300,13 +300,14 @@ def _load_remap_matrix(self):

def postprocess(self, binary_seg_result, instance_seg_result=None,
min_area_threshold=100, source_image=None,
data_source='tusimple'):
with_lane_fit=True, data_source='tusimple'):
"""
:param binary_seg_result:
:param instance_seg_result:
:param min_area_threshold:
:param source_image:
:param with_lane_fit:
:param data_source:
:return:
"""
Expand Down Expand Up @@ -337,6 +338,18 @@ def postprocess(self, binary_seg_result, instance_seg_result=None,
'fit_params': None,
'source_image': None,
}
if not with_lane_fit:
tmp_mask = cv2.resize(
mask_image,
dsize=(source_image.shape[1], source_image.shape[0]),
interpolation=cv2.INTER_NEAREST
)
source_image = cv2.addWeighted(source_image, 0.6, tmp_mask, 0.4, 0.0, dst=source_image)
return {
'mask_image': mask_image,
'fit_params': None,
'source_image': source_image,
}

# lane line fit
fit_params = []
Expand Down
15 changes: 12 additions & 3 deletions tools/test_lanenet.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ def init_args():
parser = argparse.ArgumentParser()
parser.add_argument('--image_path', type=str, help='The image path or the src image save dir')
parser.add_argument('--weights_path', type=str, help='The model weights path')
parser.add_argument('--with_lane_fit', type=args_str2bool, help='If need to do lane fit', default=True)

return parser.parse_args()

Expand Down Expand Up @@ -67,11 +68,12 @@ def minmax_scale(input_arr):
return output_arr


def test_lanenet(image_path, weights_path):
def test_lanenet(image_path, weights_path, with_lane_fit=True):
"""
:param image_path:
:param weights_path:
:param with_lane_fit:
:return:
"""
assert ops.exists(image_path), '{:s} not exist'.format(image_path)
Expand Down Expand Up @@ -125,9 +127,16 @@ def test_lanenet(image_path, weights_path):
postprocess_result = postprocessor.postprocess(
binary_seg_result=binary_seg_image[0],
instance_seg_result=instance_seg_image[0],
source_image=image_vis
source_image=image_vis,
with_lane_fit=with_lane_fit,
data_source='tusimple'
)
mask_image = postprocess_result['mask_image']
if with_lane_fit:
lane_params = postprocess_result['fit_params']
LOG.info('Model have fitted {:d} lanes'.format(len(lane_params)))
for i in range(len(lane_params)):
LOG.info('Fitted 2-order lane {:d} curve param: {}'.format(i + 1, lane_params[i]))

for i in range(CFG.MODEL.EMBEDDING_FEATS_DIMS):
instance_seg_image[0][:, :, i] = minmax_scale(instance_seg_image[0][:, :, i])
Expand Down Expand Up @@ -155,4 +164,4 @@ def test_lanenet(image_path, weights_path):
# init args
args = init_args()

test_lanenet(args.image_path, args.weights_path)
test_lanenet(args.image_path, args.weights_path, with_lane_fit=args.with_lane_fit)

0 comments on commit 3e30757

Please sign in to comment.