Bạn gần như có thể giảm một nửa thời gian thực hiện bằng cách sử dụng np.any
để giảm các hàng và cột có chứa giá trị khác không để vector 1D, chứ không phải là việc tìm kiếm các chỉ số của tất cả các giá trị khác không sử dụng np.where
:
def bbox1(img):
a = np.where(img != 0)
bbox = np.min(a[0]), np.max(a[0]), np.min(a[1]), np.max(a[1])
return bbox
def bbox2(img):
rows = np.any(img, axis=1)
cols = np.any(img, axis=0)
rmin, rmax = np.where(rows)[0][[0, -1]]
cmin, cmax = np.where(cols)[0][[0, -1]]
return rmin, rmax, cmin, cmax
Một số tiêu chuẩn:
%timeit bbox1(img2)
10000 loops, best of 3: 63.5 µs per loop
%timeit bbox2(img2)
10000 loops, best of 3: 37.1 µs per loop
Mở rộng phương pháp này đối với trường hợp 3D chỉ liên quan đến việc thực hiện giảm cùng mỗi cặp trục:
Thật dễ dàng để khái quát này để N kích thước bằng cách sử dụng itertools.combinations
để lặp qua mỗi sự kết hợp độc đáo của các trục để thực hiện việc giảm hơn:
import itertools
def bbox2_ND(img):
N = img.ndim
out = []
for ax in itertools.combinations(range(N), N - 1):
nonzero = np.any(img, axis=ax)
out.extend(np.where(nonzero)[0][[0, -1]])
return tuple(out)
Nếu bạn biết tọa độ của các góc của hộp giới hạn ban đầu, góc xoay và tâm xoay, bạn có thể nhận được tọa độ của các góc hộp bao phủ được chuyển đổi trực tiếp bằng cách tính affine transformation matrix tương ứng và nằm rải rác nó với đầu vào tọa độ:
def bbox_rotate(bbox_in, angle, centre):
rmin, rmax, cmin, cmax = bbox_in
# bounding box corners in homogeneous coordinates
xyz_in = np.array(([[cmin, cmin, cmax, cmax],
[rmin, rmax, rmin, rmax],
[ 1, 1, 1, 1]]))
# translate centre to origin
cr, cc = centre
cent2ori = np.eye(3)
cent2ori[:2, 2] = -cr, -cc
# rotate about the origin
theta = np.deg2rad(angle)
rmat = np.eye(3)
rmat[:2, :2] = np.array([[ np.cos(theta),-np.sin(theta)],
[ np.sin(theta), np.cos(theta)]])
# translate from origin back to centre
ori2cent = np.eye(3)
ori2cent[:2, 2] = cr, cc
# combine transformations (rightmost matrix is applied first)
xyz_out = ori2cent.dot(rmat).dot(cent2ori).dot(xyz_in)
r, c = xyz_out[:2]
rmin = int(r.min())
rmax = int(r.max())
cmin = int(c.min())
cmax = int(c.max())
return rmin, rmax, cmin, cmax
này hoạt động ra là rất nhẹ nhanh hơn so với sử dụng np.any
ví dụ nhỏ của bạn mảng:
%timeit bbox_rotate([25, 75, 25, 75], 45, (50, 50))
10000 loops, best of 3: 33 µs per loop
Tuy nhiên, do tốc độ của phương thức này độc lập với kích thước của mảng đầu vào, nó có thể nhanh hơn rất nhiều đối với các mảng lớn hơn.
Mở rộng cách tiếp cận chuyển đổi sang 3D phức tạp hơn một chút, trong đó xoay bây giờ có ba thành phần khác nhau (một về trục x, một về trục y và một về trục z), nhưng cơ bản phương pháp là như nhau:
def bbox_rotate_3d(bbox_in, angle_x, angle_y, angle_z, centre):
rmin, rmax, cmin, cmax, zmin, zmax = bbox_in
# bounding box corners in homogeneous coordinates
xyzu_in = np.array(([[cmin, cmin, cmin, cmin, cmax, cmax, cmax, cmax],
[rmin, rmin, rmax, rmax, rmin, rmin, rmax, rmax],
[zmin, zmax, zmin, zmax, zmin, zmax, zmin, zmax],
[ 1, 1, 1, 1, 1, 1, 1, 1]]))
# translate centre to origin
cr, cc, cz = centre
cent2ori = np.eye(4)
cent2ori[:3, 3] = -cr, -cc -cz
# rotation about the x-axis
theta = np.deg2rad(angle_x)
rmat_x = np.eye(4)
rmat_x[1:3, 1:3] = np.array([[ np.cos(theta),-np.sin(theta)],
[ np.sin(theta), np.cos(theta)]])
# rotation about the y-axis
theta = np.deg2rad(angle_y)
rmat_y = np.eye(4)
rmat_y[[0, 0, 2, 2], [0, 2, 0, 2]] = (
np.cos(theta), np.sin(theta), -np.sin(theta), np.cos(theta))
# rotation about the z-axis
theta = np.deg2rad(angle_z)
rmat_z = np.eye(4)
rmat_z[:2, :2] = np.array([[ np.cos(theta),-np.sin(theta)],
[ np.sin(theta), np.cos(theta)]])
# translate from origin back to centre
ori2cent = np.eye(4)
ori2cent[:3, 3] = cr, cc, cz
# combine transformations (rightmost matrix is applied first)
tform = ori2cent.dot(rmat_z).dot(rmat_y).dot(rmat_x).dot(cent2ori)
xyzu_out = tform.dot(xyzu_in)
r, c, z = xyzu_out[:3]
rmin = int(r.min())
rmax = int(r.max())
cmin = int(c.min())
cmax = int(c.max())
zmin = int(z.min())
zmax = int(z.max())
return rmin, rmax, cmin, cmax, zmin, zmax
tôi đã về cơ bản chỉ cần sửa đổi các chức năng trên bằng cách sử dụng biểu thức ma trận xoay từ here - tôi đã không có thời gian để viết một bài kiểm tra hợp cụ thể, vì vậy sử dụng một cách thận trọng.
Tuyệt vời! Làm thế nào tôi có thể mở rộng này vào trường hợp 3D? Tôi vẫn có thể sử dụng np.any bằng cách nào đó? –
Cảm ơn rất nhiều! –
@ali_m: 'bbox2' là giải pháp rất tốt, đặc biệt nếu có số lượng lớn hàng/cột trống, về thứ tự độ lớn nhanh hơn: http://stackoverflow.com/a/4809040/483620, nhưng tôi ' m đoán rằng hiệu suất sẽ tương tự hoặc tệ hơn trong trường hợp cực đoan khi không có hàng/cột khác không. – Benjamin