Вот грубый способ решить эту проблему.Я решил это с помощью Python, но все те же правила применяются к Java.
Я начинаю с того, что получаю тестовый набор для работы с точками, которые имеют пробел и некоторую случайность.
w, h = 1000, 1000
spacing = 25
blast_size = 100
def distance(p1, p2):
return math.sqrt(math.pow(p1[0] - p2[0], 2) + math.pow(p1[1] - p2[1], 2))
def keep_point(p):
if p[0] < 0 or p[0] >= w or p[1] < 0 or p[1] >= h:
return False
d = distance(p, (w/2, h/2))
if d > blast_size:
return True
return False
grid = [
(i + random.randint(-spacing, spacing), j + random.randint(-spacing, spacing))
for i in range(spacing, w, spacing*2)
for j in range(spacing, h, spacing*2)
]
grid = list(filter(keep_point, grid))
initial = np.zeros((h, w), np.uint8)
for i, j in grid:
image[i, j] = 255
cv2.imshow("Initial", initial)
cv2.waitKey()
Далее я вычисляю минимальное расстояние, которое каждая точка имеет до соседа.Наибольшее минимальное расстояние будет использовано как радиус нашей свертки.После завершения свертки разрыв будет очень заметным.Чтобы получить центр разрыва после свертки, я беру среднее из контуров.Если у вас может быть несколько пропусков, вам нужно будет обнаружить капли в этом месте.
# Don't include self as a neighbor
def distance_non_equal(p1, p2):
if p1 == p2:
return float('inf')
return distance(p1, p2)
min_distance = [
min(map(lambda p2: distance_non_equal(p1, p2), grid))
for p1 in grid
]
radius = int(max(min_distance))
kernel = np.zeros((2*radius+1, 2*radius+1), np.uint8)
y,x = np.ogrid[-radius:radius+1, -radius:radius+1]
mask = x**2 + y**2 <= radius**2
kernel[mask] = 255
convolution = cv2.filter2D(image, cv2.CV_8U, kernel)
contours = cv2.findContours(convolution, 0, 2)
avg = np.mean(contours[0],axis=1)
x = int(round(avg[0,0,0]))
y = int(round(avg[0,0,1]))
convolution[x, y] = 255
cv2.imshow("Convolution", convolution)
cv2.waitKey()
Теперь, когда у нас есть центрразрыв, мы можем приблизить границу.Это очень грубый алгоритм для определения границы.Я делю точки на зоны в зависимости от их угла к центральной точке.Для каждой зоны я считаю ближайшую точку частью границы.В конце я окрашиваю границы точек по-разному.
def get_angle(p):
angle = math.degrees(math.atan2(y - p[1], x - p[0]))
if angle < 0:
angle += 360
return angle
angles = list(map(get_angle, grid))
zones = [
[
p
for angle, p in zip(angles, grid)
if i < angle < i + 360//12
]
for i in range(0,360,360//12)
]
closest = [
min(zone, key=lambda p2: distance((x,y), p2))
for zone in zones
]
final = np.zeros((h, w, 3), np.uint8)
for i, j in grid:
final[i, j] = [100,100,100]
for i, j in closest:
final[i, j] = [255,255,255]
cv2.imshow("final", final)
cv2.waitKey()