[关闭]
@zsh-o 2020-02-14T03:56:51.000000Z 字数 11498 阅读 948

centerline by snake

UII


  1. %matplotlib inline
  2. import numpy as np
  3. from matplotlib import pyplot as plt
  1. im_demo = plt.imread('demo1.png')
  2. im_demo = 1 - im_demo
  1. plt.imshow(im_demo)
<matplotlib.image.AxesImage at 0x1b0bccb6cf8>

png](output_2_1.png)![output_2_1.png-4.2kB

  1. plt.subplot(1,3,1)
  2. plt.imshow(im_demo[:,:,0], cmap=plt.cm.gray)
  3. plt.subplot(1,3,2)
  4. plt.imshow(im_demo[:,:,1], cmap=plt.cm.gray)
  5. plt.subplot(1,3,3)
  6. plt.imshow(im_demo[:,:,2], cmap=plt.cm.gray)
<matplotlib.image.AxesImage at 0x1b0bcdab4e0>

png](output_3_1.png)![output_3_1.png-3.5kB

  1. im_mask = (im_demo[:, :, 2] > 0).astype(np.uint8)
  1. plt.imshow(im_mask, cmap=plt.cm.gray)
<matplotlib.image.AxesImage at 0x1b0bce2e0f0>

png](output_5_1.png)![output_5_1.png-3.8kB

  1. im_centerline = np.logical_and(np.logical_or(im_demo[:, :, 0] < 1, im_demo[:, :, 1] < 1), im_demo[:, :, 2] > 0).astype(np.uint8)
  1. plt.imshow(im_centerline, cmap=plt.cm.gray)
<matplotlib.image.AxesImage at 0x1b0bce85eb8>

png](output_7_1.png)![output_7_1.png-3.8kB

  1. im_start = np.logical_and(im_demo[:, :, 1] < 1, im_demo[:, :, 2] > 0).astype(np.uint8)
  1. plt.imshow(im_start, cmap=plt.cm.gray)
<matplotlib.image.AxesImage at 0x1b0bcee7a58>

png](output_9_1.png)![output_9_1.png-3.3kB

Some Utils

  1. def get_rotation_matrix(vector_from, vector_to):
  2. if isinstance(vector_from, list) is True:
  3. vector_from = np.array(vector_from)
  4. if isinstance(vector_to, list) is True:
  5. vector_to = np.array(vector_to)
  6. vector_from = np.array([vector_from[0], vector_from[1], 0])
  7. vector_from = vector_from / np.sqrt(np.sum(vector_from ** 2))
  8. vector_to = np.array([vector_to[0], vector_to[1], 0])
  9. vector_to = vector_to / np.sqrt(np.sum(vector_to ** 2))
  10. vector_rotation = np.cross(vector_from, vector_to)
  11. angle = np.arccos(np.dot(vector_from, vector_to))
  12. if vector_rotation[2] > 0:
  13. return np.array([
  14. [np.cos(angle), -np.sin(angle)],
  15. [np.sin(angle), np.cos(angle)]
  16. ])
  17. else:
  18. return np.array([
  19. [np.cos(angle), np.sin(angle)],
  20. [-np.sin(angle), np.cos(angle)]
  21. ])
  1. np.dot(get_rotation_matrix([0,1], [0,-1]), np.array([-1, 0]))
array([1.0000000e+00, 1.2246468e-16])
  1. def resample_nn(im, coordinate, resample_ratio=0):
  2. width = im.shape[0]
  3. height = im.shape[1]
  4. if isinstance(coordinate, list):
  5. coordinate = np.array(coordinate)
  6. if coordinate[0] < 0 or coordinate[1] >= width:
  7. return 0
  8. if coordinate[1] < 0 or coordinate[1] >= height:
  9. return 0
  10. coordinate = coordinate + 0.5 - resample_ratio / 2
  11. coordinate_floor = np.floor(coordinate)
  12. is_larger = (coordinate - coordinate_floor) > 0.5
  13. larger_x, larger_y = is_larger[0], is_larger[1]
  14. x, y = int(coordinate_floor[0] + 0.1), int(coordinate_floor[1] + 0.1)
  15. if larger_x is True:
  16. x += 1
  17. x = min(x, width - 1)
  18. if larger_y is True:
  19. y += 1
  20. y = min(y, height - 1)
  21. return im[x, y]
  1. resample_nn(im_mask, [40, 20])
1
  1. def resample_line_by_center(im, center, direction, step=0.15, size=51):
  2. assert size % 2 != 0
  3. if isinstance(center, list):
  4. center = np.array(center)
  5. if isinstance(direction, list):
  6. direction = np.array(direction)
  7. center = center.astype(np.float)
  8. line = []
  9. i = 0
  10. curr = center.copy()
  11. while i < size // 2:
  12. curr = center - (direction * step * (size // 2 - i))
  13. line.append(resample_nn(im, curr, step))
  14. i += 1
  15. line.append(resample_nn(im, center, step))
  16. i = 0
  17. curr = center.copy()
  18. while i < size // 2:
  19. curr = center + (direction * step * (i + 1))
  20. line.append(resample_nn(im, curr, step))
  21. i += 1
  22. return np.array(line)
  23. def resample_line_by_center_debug(im, center, direction, step=0.15, size=51):
  24. assert size % 2 != 0
  25. if isinstance(center, list):
  26. center = np.array(center)
  27. if isinstance(direction, list):
  28. direction = np.array(direction)
  29. center = center.astype(np.float)
  30. line = []
  31. i = 0
  32. curr = center.copy()
  33. while i < size // 2:
  34. curr = center - (direction * step * (size // 2 - i))
  35. line.append(curr)
  36. i += 1
  37. line.append(center)
  38. i = 0
  39. curr = center.copy()
  40. while i < size // 2:
  41. curr = center + (direction * step * (i + 1))
  42. line.append(curr)
  43. i += 1
  44. return np.vstack(line)

resample parameters

  1. resample_ratio = 0.15
  2. resample_size = 51
  1. line = resample_line_by_center(im_mask, [50, 20], [0, 1], resample_ratio, resample_size)
  2. line
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
       1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
       0, 0, 0, 0, 0, 0, 0], dtype=uint8)
  1. plt.imshow(line.reshape((1, -1)), cmap=plt.cm.gray)
<matplotlib.image.AxesImage at 0x1b0bcf4cc88>

png](output_19_1.png)![output_19_1.png-1.7kB

  1. plt.imshow(im_mask, cmap=plt.cm.gray)
  2. plt.scatter(20, 50)
  3. line_debug = resample_line_by_center_debug(im_mask, [50, 20], [0, 1], resample_ratio, resample_size)
  4. plt.plot(line_debug[:, 1], line_debug[:, 0])
[<matplotlib.lines.Line2D at 0x1b0bcf99f60>]

png](output_20_1.png)![output_20_1.png-4kB

  1. def get_centerline(im_centerline, im_start):
  2. im_centerline = im_centerline.copy()
  3. width = im_centerline.shape[0]
  4. height = im_centerline.shape[1]
  5. centerline = []
  6. point_start = np.vstack(np.where(im_start > 0)).T
  7. curr = point_start
  8. while True:
  9. centerline.append(curr)
  10. x, y = curr[0, 0], curr[0, 1]
  11. im_centerline[x, y] = 0
  12. found = False
  13. for dx in range(-1, 2):
  14. nx = x + dx
  15. if nx < 0 or nx >= width:
  16. continue
  17. for dy in range(-1, 2):
  18. ny = y + dy
  19. if ny < 0 or ny >= height:
  20. continue
  21. if im_centerline[nx, ny] > 0:
  22. found = True
  23. curr = np.array([[nx, ny]])
  24. break
  25. if found is True:
  26. break
  27. if found is not True:
  28. break
  29. return np.concatenate(centerline, axis=0)
  1. centerline = get_centerline(im_centerline, im_start)
  2. centerline.shape
(164, 2)
  1. im_centerline_copy = np.zeros(im_centerline.shape, dtype=np.uint8)
  1. for i in range(centerline.shape[0]):
  2. point = centerline[i]
  3. im_centerline_copy[point[0], point[1]] = 1
  1. plt.subplot(1, 2, 1)
  2. plt.imshow(im_centerline, cmap=plt.cm.gray)
  3. plt.subplot(1, 2, 2)
  4. plt.imshow(im_centerline_copy, cmap=plt.cm.gray)
<matplotlib.image.AxesImage at 0x1b0bd039a58>

png](output_25_1.png)![output_25_1.png-4kB

  1. # smooth
  2. from scipy.interpolate import splprep, splev
  1. tck, u = splprep([centerline[:, 0], centerline[:, 1]], s=5)
  2. unew = np.arange(0, 1, 1 / 200)
  3. centerline = np.vstack(splev(unew, tck)).T
  1. plt.imshow(im_mask, cmap=plt.cm.gray)
  2. plt.plot(centerline[:,1], centerline[:, 0])
[<matplotlib.lines.Line2D at 0x1b0bd97c2b0>]

png](output_28_1.png)![output_28_1.png-10.1kB

  1. def get_norm(centerline):
  2. assert centerline.shape[0] >= 2
  3. diff = []
  4. for i in range(centerline.shape[0]):
  5. if i == 0:
  6. left = centerline[i]
  7. else:
  8. left = centerline[i - 1]
  9. if i == centerline.shape[0] - 1:
  10. right = centerline[i]
  11. else:
  12. right = centerline[i + 1]
  13. d = right - left
  14. d = d / np.sqrt(np.sum(d ** 2))
  15. diff.append(d.reshape(1, -1))
  16. return np.concatenate(diff, axis=0)
  1. norms = get_norm(centerline)
  1. index = 175
  1. point = centerline[index]
  2. norm = norms[index]
  3. point, norm
(array([ 7.98154137, 48.3591225 ]), array([0.04317411, 0.99906756]))
  1. rotation_matrix = get_rotation_matrix([0, 1], norm)
  1. rotation_matrix
array([[ 0.99906756,  0.04317411],
       [-0.04317411,  0.99906756]])
  1. direction = np.dot(rotation_matrix, np.array([1, 0]))
  1. direction
array([ 0.99906756, -0.04317411])
  1. line_debug = resample_line_by_center_debug(im_mask, point, direction, resample_ratio, resample_size)
  1. plt.imshow(im_mask, cmap=plt.cm.gray)
  2. plt.plot(centerline[:,1], centerline[:, 0])
  3. plt.plot(line_debug[:, 1], line_debug[:, 0])
[<matplotlib.lines.Line2D at 0x1b0bda0acf8>]

png](output_38_1.png)![output_38_1.png-10.3kB

  1. line = resample_line_by_center(im_mask, point, direction, resample_ratio, resample_size)
  2. line
array([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,
       1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0,
       0, 0, 0, 0, 0, 0, 0], dtype=uint8)
  1. plt.imshow(line.reshape((1, -1)), cmap=plt.cm.gray)
<matplotlib.image.AxesImage at 0x1b0bda6db00>

png](output_40_1.png)![output_40_1.png-1.7kB

  1. def get_mass(line, center):
  2. if line[center] == 0:
  3. return 0
  4. L = line.shape[0]
  5. ret = [0]
  6. sum = 0
  7. N = 1
  8. i = 1
  9. while i + center < L:
  10. if line[i + center] > 0:
  11. sum += i
  12. N += 1
  13. else:
  14. break
  15. i += 1
  16. i = -1
  17. while i + center >= 0:
  18. if line[i + center] > 0:
  19. sum += i
  20. N += 1
  21. else:
  22. break
  23. i -= 1
  24. return sum / N
  1. mass = get_mass(line, (resample_size + 1) // 2 - 1)
  2. mass
0.5
  1. plt.imshow(line.reshape((1, -1)), cmap=plt.cm.gray)
  2. c = (resample_size + 1) // 2 - 1
  3. plt.scatter(c, 0, c='r')
  4. plt.scatter(c + mass, 0, c='g')
<matplotlib.collections.PathCollection at 0x1b0bea960f0>

png](output_43_1.png)![output_43_1.png-1.9kB

  1. def get_refine_center(im_mask, centerpoint, norm, ratio=0.15, size=51):
  2. rotation_matrix = get_rotation_matrix([0, 1], norm)
  3. direction = np.dot(rotation_matrix, np.array([1, 0]))
  4. line = resample_line_by_center(im_mask, centerpoint, direction, ratio, size)
  5. mass = get_mass(line, (size + 1) // 2 - 1)
  6. refinepoint = centerpoint + direction * mass * ratio
  7. return refinepoint
  1. get_refine_center(im_mask, point, norm, resample_ratio, resample_size)
array([ 8.05647143, 48.35588444])
  1. def get_refine_centerline(im, centerline, resmaple_ratio=0.15, resample_size=51):
  2. norms = get_norm(centerline)
  3. ret = []
  4. for i in range(centerline.shape[0]):
  5. r = get_refine_center(im, centerline[i], norms[i], resample_ratio, resample_size)
  6. ret.append(r.reshape(1, -1))
  7. return np.concatenate(ret)
  1. refine_centerline = get_refine_centerline(im_mask, centerline, resample_ratio, resample_size)
  1. plt.imshow(im_mask, cmap=plt.cm.gray)
  2. plt.plot(centerline[:,1], centerline[:, 0])
  3. plt.plot(refine_centerline[:,1], refine_centerline[:, 0])
  4. plt.plot(line_debug[:, 1], line_debug[:, 0])
[<matplotlib.lines.Line2D at 0x1b0beaf5f60>]

png](output_48_1.png)![output_48_1.png-12.9kB

Snake

  1. alpha = 0.1
  2. beta = 0.5
  3. omega = 0.1
  4. gamma = 5
  5. iters = 50
  1. def build_A(alpha, beta, N):
  2. A = np.zeros((N, N))
  3. for i in range(N):
  4. if i == 0 or i == 1 or i == N - 1 or i == N - 2:
  5. continue
  6. A[i, i-2] = -beta
  7. A[i, i-1] = alpha + 4 * beta
  8. A[i, i] = -2 * alpha - 6 * beta
  9. A[i, i+1] = alpha + 4 * beta
  10. A[i, i+2] = -beta
  11. return A
  1. A = build_A(alpha, beta, centerline.shape[0])
  1. A
array([[ 0. ,  0. ,  0. , ...,  0. ,  0. ,  0. ],
       [ 0. ,  0. ,  0. , ...,  0. ,  0. ,  0. ],
       [-0.5,  2.1, -3.2, ...,  0. ,  0. ,  0. ],
       ...,
       [ 0. ,  0. ,  0. , ..., -3.2,  2.1, -0.5],
       [ 0. ,  0. ,  0. , ...,  0. ,  0. ,  0. ],
       [ 0. ,  0. ,  0. , ...,  0. ,  0. ,  0. ]])
  1. IA = np.linalg.inv(np.eye(centerline.shape[0]) - A * gamma)
  2. IA
array([[ 1.00000000e+00,  7.10542736e-16,  0.00000000e+00, ...,
         9.27301538e-70, -2.22552369e-68,  0.00000000e+00],
       [ 2.64338815e-16,  1.00000000e+00,  0.00000000e+00, ...,
         1.65589560e-68, -9.71458754e-68,  8.83144322e-69],
       [-2.92482759e-01,  9.50440213e-01,  1.16993104e-01, ...,
         1.79323709e-54, -2.19623057e-53, -4.48309274e-54],
       ...,
       [-4.48309274e-54, -2.19623057e-53,  1.79323709e-54, ...,
         1.16993104e-01,  9.50440213e-01, -2.92482759e-01],
       [ 0.00000000e+00,  0.00000000e+00,  0.00000000e+00, ...,
         0.00000000e+00,  1.00000000e+00,  0.00000000e+00],
       [ 0.00000000e+00,  0.00000000e+00,  0.00000000e+00, ...,
         0.00000000e+00,  0.00000000e+00,  1.00000000e+00]])
  1. curr_centerline = centerline.copy()
  2. History = [centerline]
  3. for i in range(iters):
  4. refine_centerline = get_refine_centerline(im_mask, curr_centerline, resample_ratio, resample_size)
  5. centerline_diff = refine_centerline - curr_centerline
  6. curr_centerline = np.dot(IA, curr_centerline + centerline_diff * gamma * omega)
  7. History.append(curr_centerline)
  1. final_centerline = History[-1]
  2. origin_centerline = History[0]
  3. plt.figure(figsize=(5,10), dpi=100)
  4. plt.subplot(1, 2, 1)
  5. plt.imshow(im_mask, cmap=plt.cm.gray)
  6. plt.plot(origin_centerline[:, 1], origin_centerline[:, 0])
  7. plt.subplot(1, 2, 2)
  8. plt.imshow(im_mask, cmap=plt.cm.gray)
  9. plt.plot(final_centerline[:,1], final_centerline[:, 0])
[<matplotlib.lines.Line2D at 0x1b0beb9eb00>]

png](output_56_1.png)![output_56_1.png-14.8kB

  1. plt.figure(figsize=(10, 10), dpi=100)
  2. plt.imshow(im_mask, cmap=plt.cm.gray)
  3. plt.plot(final_centerline[:,1], final_centerline[:, 0])
[<matplotlib.lines.Line2D at 0x1b0bedd1dd8>]

png](output_57_1.png)![output_57_1.png-31.8kB

final centerline and its refine centerline for debug

  1. final_refine = get_refine_centerline(im_mask, final_centerline)
  1. plt.imshow(im_mask, cmap=plt.cm.gray)
  2. plt.plot(final_centerline[:, 1], final_centerline[:, 0])
  3. plt.plot(final_refine[:,1], final_refine[:, 0])
[<matplotlib.lines.Line2D at 0x1b0bec2f5c0>]

png](output_60_1.png)![output_60_1.png-10.5kB

  1. final_norms = get_norm(final_centerline)
  2. point = final_centerline[index]
  3. norm = final_norms[index]
  4. rotation_matrix = get_rotation_matrix([0, 1], norm)
  5. direction = np.dot(rotation_matrix, np.array([1, 0]))
  6. final_line_debug = resample_line_by_center_debug(im_mask, point, direction, resample_ratio, resample_size)
  1. plt.imshow(im_mask, cmap=plt.cm.gray)
  2. plt.plot(final_centerline[:,1], final_centerline[:, 0])
  3. plt.plot(final_line_debug[:, 1], final_line_debug[:, 0])
[<matplotlib.lines.Line2D at 0x1b0bec91400>]

png](output_62_1.png)![output_62_1.png-9.9kB

  1. final_line = resample_line_by_center(im_mask, point, direction, resample_ratio, resample_size)
  2. mass = get_mass(final_line, (resample_size + 1) // 2 - 1)
  1. plt.imshow(final_line.reshape((1, -1)), cmap=plt.cm.gray)
  2. c = (resample_size + 1) // 2 - 1
  3. plt.scatter(c, 0, c='r')
  4. plt.scatter(c + mass, 0, c='g')
<matplotlib.collections.PathCollection at 0x1b0becfa160>

png](output_64_1.png)![output_64_1.png-1.9kB

源码

centerline.zip388kB

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注