Skip to content

Commit b4c8648

Browse files
committed
Few improvements, code cleanup, doc
1 parent c407eb4 commit b4c8648

File tree

1 file changed

+67
-41
lines changed

1 file changed

+67
-41
lines changed

pclines.py

Lines changed: 67 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -4,74 +4,100 @@
44
This package implements the method from
55
Dubska et al, PCLines - Line detection with parallel coordinates, CVPR 2011
66
7+
8+
Module
9+
------
10+
The module provides a high-level function for line detection in image
11+
and also low-level functions for
12+
* accumulation of observations to PCLines space,
13+
* point mapping from PCLines space to homogeneous lines
14+
that can be used to construct a custom PCLines transform of user-defined
15+
edge points.
16+
17+
18+
See also
19+
--------
20+
* pclines.accumulate
21+
* pclines.find_peaks
22+
* pclines.line_parameters
23+
24+
25+
References
26+
----------
27+
[1] Dubska et al, PCLines - Line detection with parallel coordinates, CVPR 2011
28+
29+
730
"""
831

32+
933
import numpy as np
1034
import numba as nb
1135
from skimage.feature import peak_local_max
1236
from skimage.morphology.grey import erosion, dilation
1337

1438

15-
def linear_transform(src, dst):
39+
def _linear_transform(src, dst):
40+
""" Parameters of a linear transform from range specifications """
1641
(s0, s1), (d0,d1) = src, dst
1742
w = (d1 - d0) / (s1 - s0)
1843
b = d0 - w*s0
1944
return w, b
2045

2146

2247
class Normalizer:
48+
"""
49+
Range mapping
50+
"""
2351
def __init__(self, src_range, dst_range=(0,1)):
24-
self.w, self.b = linear_transform(src_range, dst_range)
25-
self.wi, self.bi = linear_transform(dst_range, src_range)
52+
# TODO: check ranges
53+
self.w, self.b = _linear_transform(src_range, dst_range)
54+
self.wi, self.bi = _linear_transform(dst_range, src_range)
2655

2756
def transform(self, x):
28-
""" src -> dst """
57+
""" src -> dst mapping of x """
2958
return self.w * x + self.b
3059

3160
def inverse(self, x):
32-
""" dst -> src """
61+
""" dst -> src mapping of x """
3362
return self.wi * x + self.bi
3463

3564
__call__ = transform
3665

3766

38-
def accumulate(x, bbox=None, d=256):
67+
def accumulate(x, w=None, bbox=None, d=256):
3968
"""
4069
Accumulate observation in PCLines space
4170
4271
bbox : tuple
4372
(x,y,w,h) format
4473
"""
74+
# TODO: Check inputs
75+
76+
4577
# Create accumulator
4678
acc_shape = d,2*d-1
4779
A = np.zeros(acc_shape, "f") # The accumulator
4880

49-
if bbox is None:
50-
# autodetection of bbox
51-
pass
52-
53-
# Normalizers
81+
# Axis normalizers
5482
def normalizers():
5583
x,y,w,h = bbox
5684
shape = (w,h)
5785
ranges = d * np.array(shape)/max(shape)
5886
ofs = (d-ranges) / 2
5987
(x0,y0),(x1,y1) = ofs, (ranges-1)+ofs
60-
print(bbox)
6188
norm0 = Normalizer((y,y+h), (y1, y0))
6289
norm1 = Normalizer((x,x+w), (x0, x1))
6390
norm2 = Normalizer((y,y+h), (y0, y1))
6491
return norm0, norm1, norm2
6592

6693
norm0, norm1, norm2 = normalizers()
6794

68-
x = [
69-
norm0(x[:,1]),
70-
norm1(x[:,0]),
71-
norm2(x[:,1])
72-
]
95+
# Coordinates on parallel axes
96+
x0,x1 = np.split(x,2,axis=1)
97+
x = np.concatenate([norm0(x1), norm1(x0), norm2(x1)], axis=1)
7398

74-
for a,b,c in zip(*x): # remove space wraping
99+
# Rasterize the lines
100+
for a,b,c in x: # remove space wraping
75101
t_part = np.linspace(a,b,d)
76102
s_part = np.linspace(b,c,d)
77103
c = np.arange(2*d-1,dtype="i")
@@ -82,51 +108,51 @@ def normalizers():
82108
return A
83109

84110

85-
def lines_parameters(peaks, d, bbox):
111+
def lines_parameters(peaks, bbox, d):
112+
"""
113+
Get homogeneous line parameters from location in the accumulator
114+
"""
86115
u = peaks[:,1]
87116
v = peaks[:,0]
88-
89117
#centrovanie
90118
u = u - (d - 1)
91-
92119
x,y,w,h = bbox
93120
shape = w,h
94121
m = max(shape) - 1
95122
normV = Normalizer((0,d-1),(-m/2, m/2))
96123
v = normV(v)
97-
98124
f = u < 0
99-
100-
l = np.array([f*(d+u)+(1-f)*(d-u), u, -v*d], "f").T
101-
125+
l = np.array([f*(d+u)+(1-f)*(d-u), u, -v*d], "f").T # TODO: add reference to eq in paper
102126
tx,ty = x+0.5*w, y+0.5*h
103-
104127
l[:,2] -= l[:,0]*tx + l[:,1]*ty
105-
106128
return l
107129

108130

109131

110-
# @nb.njit("(f4[:,:],f4[:,:])")
111-
# def rasterize_lines(lines, acc):
112-
# """
113-
# """
114-
# d = acc.shape[1]
115-
# for i in range(lines.shape[0]):
116-
# y0, y1 = lines[i]
117-
# dy = (y1 - y0) / (d-1)
118-
# y = y0
119-
# for x in range(d):
120-
# acc[x,y] += 1
121-
# y += dy
122-
132+
@nb.njit("(f4[:,:],f4[:,:],i4)")
133+
def rasterize_polylines(lines, acc, d):
134+
"""
135+
"""
123136

124137

125138
def find_peaks(A, t):
139+
"""
140+
Retrieve locations with prominent local maxima in the accumulator
141+
"""
126142
prominence = dilation(A+1)/erosion(A+1)
127143
peaks = peak_local_max(A, threshold_abs=t, min_distance=1)
128144
r,c = peaks[:,0], peaks[:,1]
129145
value = A[r,c]
130146
valid = prominence[r,c] > 1.3
131147
return peaks[valid], value[valid]
132-
148+
149+
150+
def get_lines(image):
151+
"""
152+
PCLines transform of an image
153+
"""
154+
# TODO: Get edges
155+
# TODO: Accumulate
156+
# TODO: Locate peaks
157+
# TODO: Transform peaks to line parameters
158+
pass

0 commit comments

Comments
 (0)