【图像处理】根据边缘轮廓求曲率以及方向

文章目录

  • 1. 思路
  • 2. 获取边缘点的坐标
  • 2. 利用离散点求曲率以及方向
  • 3. 运行

1. 思路

  • 遍历轮廓的像素值,求取依次相连的位置
  • 根据离散点求曲率以及曲率点的方向

2. 获取边缘点的坐标

参考链接:https://blog.csdn.net/qq_36614557/article/details/115315449

def findpoint(x_arr, y_arr, x_next, y_next):
	n = len(x_arr)
	f = 1
	for i in range(n):
		if x_arr[i] == x_next and y_arr[i] == y_next:
			f = 0
			break
	return f

# 依次获取边缘轮廓上的点
def getAllPoint(img, img_c3):
	_, bw_img = cv2.threshold(img, 0, 1, cv2.THRESH_BINARY)
	thin_img = morphology.skeletonize(bw_img)
	thin_img = thin_img.astype(np.uint8) * 255

	x = []
	y = []
	sx, sy = np.where(thin_img==255)
	sx_first = sx[0]
	sy_first = sy[0]
	x.append(sx_first)
	y.append(sy_first) 
	dir=[[-1,-1],[-1,0],[-1,1],[0,1],[1,1],[1,0],[1,-1],[0,-1]]
   
	while True:
		f = 0
		for i in range(8):
			if thin_img[sx_first + dir[i][0]][sy_first + dir[i][1]] == 255 and findpoint(x, y, (sx_first + dir[i][0]), (sy_first + dir[i][1])):
				sx_first +=  dir[i][0]
				sy_first +=  dir[i][1]
				f = 1
				break
		if f == 0:
			break
		if sx_first == x[0] and sy_first == y[0]:
			break
		x.append(sx_first)
		y.append(sy_first)

	# for i in range(len(x)):
	# 	cv2.circle(img_c3, (y[i], x[i]), 1, (0, 0, 255), -1)
	# cv2.imshow('img', img_c3)
	# cv2.waitKey(0)
	return x, y

将遍历的点映射到原始图像上,效果图如下:
【图像处理】根据边缘轮廓求曲率以及方向_第1张图片

2. 利用离散点求曲率以及方向

参考:https://zhuanlan.zhihu.com/p/72083902

def PJcurvature(x,y):
    """
    input  : the coordinate of the three point
    output : the curvature and norm direction
    refer to https://github.com/Pjer-zhang/PJCurvature for detail
    """
    t_a = LA.norm([x[1]-x[0],y[1]-y[0]])
    t_b = LA.norm([x[2]-x[1],y[2]-y[1]])
    
    M = np.array([
        [1, -t_a, t_a**2],
        [1, 0,    0     ],
        [1,  t_b, t_b**2]
    ])

    a = np.matmul(LA.inv(M),x)
    b = np.matmul(LA.inv(M),y)
	
    kappa = 2*(a[2]*b[1]-b[2]*a[1])/(a[1]**2.+b[1]**2.)**(1.5)
    norm_direction = [b[1],-a[1]]/np.sqrt(a[1]**2.+b[1]**2.)

    return kappa, norm_direction

3. 运行

img = cv2.imread("ES_img2.png")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
LV_img = copy.deepcopy(gray)
LV_img[LV_img != 255] = 0
LV_img_Gaussian = cv2.GaussianBlur(LV_img, (3, 3), 1)
LV_img_Gaussian[LV_img_Gaussian > 0] = 255
LV_img_uint8 = LV_img_Gaussian.astype("uint8")
LV_edge = cv2.Canny(LV_img_uint8, 1, 1)
# cv2.imwrite("ED.png", LV_edge)

img_c3 = np.zeros_like(img)
img_c3[:, :, 0] = LV_edge
img_c3[:, :, 1] = LV_edge
img_c3[:, :, 2] = LV_edge

# # 计算曲率
arr_x, arr_y = getAllPoint(LV_edge, img_c3)
step_point = 8
j = 0
p = step_point
ka = []
no = []
po = []
for i in range(len(arr_x)):	
	if i <  step_point:
		input_x = None
		input_y = None
		idx_first = len(arr_x) - p
		idx_cur = i
		idx_next = i + step_point
		input_x = [arr_x[idx_first], arr_x[idx_cur], arr_x[idx_next]]
		input_y = [arr_y[idx_first], arr_y[idx_cur], arr_y[idx_next]]
		p -= 1 
	if i <  len(arr_x) - step_point and i >= step_point:
		input_x = None
		input_y = None
		idx_first = i - step_point
		idx_cur = i
		idx_next = i + step_point
		input_x = [arr_x[idx_first], arr_x[idx_cur], arr_x[idx_next]]
		input_y = [arr_y[idx_first], arr_y[idx_cur], arr_y[idx_next]]
	if i >= len(arr_x) - step_point:
		idx_first = i - step_point
		idx_cur = i
		idx_next = j
		input_x = [arr_x[idx_first], arr_x[idx_cur], arr_x[idx_next]]
		input_y = [arr_y[idx_first], arr_y[idx_cur], arr_y[idx_next]]
		j += 1
	kappa, norm_direction = PJcurvature(input_x, input_y)
	if kappa > 0.1:
		po.append([arr_x[idx_cur], arr_y[idx_cur]])
		ka.append(kappa)
		no.append(norm_direction)
		# cv2.circle(img_c3, (arr_y[idx_cur], arr_x[idx_cur]), 1, (0, 0, 255), -1)

# 显示曲率方向
# po = np.array(po)
# no = np.array(no)
# ka = np.array(ka)

# plt.imshow(img_c3)
# plt.quiver(po[:,1], po[:,0], ka*no[:,0],ka*no[:,1], color='r', angles='uv',scale_units='xy',scale=0.01)  # uv表示方向, xy位置参数,此时uv表示其增量
# plt.show()

# cv2.imshow('img', img_c3)
# cv2.waitKey(0)

# 求得每个区率曲率最大的点
x = po[:, 0]
y = po[:, 1]
arr_1 = []
arr_2 = []
arr_3 = []
x1 = x[0]
y1 = y[0]
arr_1.append([x1, y1])
for i in range(1, len(x)):
	x2 = x[i]
	y2 = y[i]
	d = euclidean_Dis(x1, y1, x2, y2)
	if d < 10:
		arr_1.append([x2, y2])
	else:
		arr_2.append([x2, y2])


arr_2 = np.array(arr_2)
array_x = arr_2[:, 0]
array_y = arr_2[:, 1]
arr_4 = []
point_x1 = array_x[0]
point_y1 = array_y[0]
arr_4.append([point_x1, point_y1])
for j in range(1, len(array_x)):
	point_x2 = array_x[j]
	point_y2 = array_y[j]
	d1 = euclidean_Dis(point_x1, point_y1, point_x2, point_y2)
	if d1 < 10:
		arr_4.append([point_x2, point_y2])
	else:
		arr_3.append([point_x2, point_y2])

# 获取三个区域的数组 心尖和二尖瓣
cls_1 = arr_1
cls_2 = arr_3
cls_3 = arr_4

# 找到每个区域中曲率最大的值
cls_1 = np.array(cls_1)
cls_2 = np.array(cls_2)
cls_3 = np.array(cls_3)
cls_1_arrp = []
cls_2_arrp = []
cls_3_arrp = []
cls_1_pos = []
cls_2_pos = []
cls_3_pos = []
for i in range(len(ka)):
	if po[i] in cls_1:
		cls_1_arrp.append(ka[i])
		cls_1_pos.append(po[i])
	if po[i] in cls_2:
		cls_2_arrp.append(ka[i])
		cls_2_pos.append(po[i])
	if po[i] in cls_3:
		cls_3_arrp.append(ka[i])
		cls_3_pos.append(po[i])

cls_1_arrp = np.array(cls_1_arrp)	
cls_2_arrp = np.array(cls_2_arrp)
cls_3_arrp = np.array(cls_3_arrp)
cls_1_maxp = cls_1_arrp.max()
cls_2_maxp = cls_2_arrp.max()
cls_3_maxp = cls_3_arrp.max()
for i in range(len(cls_1_arrp)):
	if cls_1_arrp[i] == cls_1_maxp:
		cls_1_max_pos = cls_1_pos[i]
for i in range(len(cls_2_arrp)):
	if cls_2_arrp[i] == cls_2_maxp:
		cls_2_max_pos = cls_2_pos[i]
for i in range(len(cls_3_arrp)):		
	if cls_3_arrp[i] == cls_3_maxp:
		cls_3_max_pos = cls_3_pos[i]

final_pos = np.array([cls_1_max_pos, cls_2_max_pos, cls_3_max_pos])
for i in range(3):
	final_x, final_y = final_pos[i][0], final_pos[i][1]
	cv2.circle(img_c3, (final_y, final_x), 1, (0, 0, 255), -1)

cv2.imshow('img', img_c3)
cv2.waitKey(0)

运行结果:
【图像处理】根据边缘轮廓求曲率以及方向_第2张图片

你可能感兴趣的:(图像处理,python,opencv)