import time

start_time = time.time()

image = cv2.imread(“0.6/00.pgm”, cv2.COLOR_BGR2GRAY)

IMAGE_THRESHOLD = 0


def count_zero_pixels(image):
zero_pixels = np.count_nonzero(image == 0)
return zero_pixels

def calculate_zero_pixel_percentage(image):
total_pixels = image.size
zero_pixels = count_zero_pixels(image)
zero_percentage = zero_pixels / total_pixels * 100
return zero_percentage


zero_percentage = calculate_zero_pixel_percentage(image)

if zero_percentage > 75:
IMAGE_THRESHOLD = 0

print(f"image_threshold: {IMAGE_THRESHOLD}“)
print(f"Процент зануленных пикселей относительно всех пикселей: {zero_percentage}%”)


def get_coords_by_threshold(
image: np.ndarray, threshold: int = IMAGE_THRESHOLD
) -> tuple:
“”“Gets pixel coords with intensity more then ‘theshold’.”“”
coords = np.where(image > threshold)
return coords


def delete_pixels_by_min_threshold(
image: np.ndarray, min_threshold: int = IMAGE_THRESHOLD
) -> np.ndarray:
“”“Deletes coords from image and returns this image.”“”
anti_coords = np.where(image < min_threshold)
image[anti_coords] = 0
return image


def get_neigh_nums_list(
coords: tuple, kernel_size: int = 7
) -> list:
“”“
Gets list with number of neighborhoods by kernel.
Returns list like [[x1, y1, N1], [x2, y2, N2]],
Where N - neighborhood’s number.
“””
neigh_nums = []
offset = (kernel_size - 1) // 2

for x, y in zip(coords[0], coords[1]):
if x < 0 + offset or x > image.shape[0] - offset:
continue
if y < 0 + offset or y > image.shape[1] - offset:
continue

kernel = image[x-offset:x+offset+1, y-offset:y+offset+1]
step_neigh_num = np.count_nonzero(kernel) - 1
neigh_nums.append([x, y, step_neigh_num])

return neigh_nums


def sort_neight_nums_by_N(neigh_nums: list) -> np.ndarray:
“”“
Sort neigh_nums by N parameter.
Removes N=-1, N=0 and sorts by N desc.
“””
np_neigh_nums = np.array(neigh_nums)

np_neigh_nums = np_neigh_nums[
(np_neigh_nums[:, 2] != -1) & (np_neigh_nums[:, 2] != 0)]

np_neigh_nums = np_neigh_nums[
np.argsort(-np_neigh_nums[:, 2])]

return np_neigh_nums


def get_potential_points_coords(
sorted_niegh_nums: np.ndarray, potential_points_num: int = 80
) -> np.ndarray:
“”“
Gets best candidates, potential points coords only.
Returns np.ndarray like [[x1, y1], [x2, y2]].
“””
sorted_neigh_nums = np.delete(sorted_niegh_nums, 2, axis=1)
return sorted_neigh_nums[:potential_points_num]


def get_best_lines(potential_points: np.ndarray) -> np.ndarray:
“”“
Gets best combinations of lines by all points.
Line y = kx + b.
Returns np.ndarray like [[k1, b1], [k2, b2]].
“””
best_lines = []
num_lines = 0
iterations_num = 1000
threshold_distance = 1
threshold_k = 0.5
threshold_b = 20

while num_lines < 3:
if num_lines == 0:
remaining_points = np.copy(potential_points)
print(f"remaining points: {len(remaining_points)}“)
best_inliers = []
best_line = None

for i in range(iterations_num):
sample_indices = np.random.choice(remaining_points.shape[0], size=3, replace=False)
sample_points = remaining_points[sample_indices]
sample_x = sample_points[:, 1]
sample_y = sample_points[:, 0]
coefficients = np.polyfit(sample_x, sample_y, deg=1)
distances = np.abs(remaining_points[:, 0] - np.matmul(np.vstack((remaining_points[:, 1], np.ones_like(remaining_points[:, 1]))).T, coefficients)) / np.sqrt(coefficients[0] ** 2 + 1)
inliers = np.where(distances < threshold_distance)[0]

is_similar = False
for line in best_lines:
diff_k = abs(coefficients[0] - line[0])
diff_b = abs(coefficients[1] - line[1])

if diff_k <= threshold_k and diff_b <= threshold_b:
is_similar = True
break

if not is_similar and len(inliers) > len(best_inliers):
best_line = coefficients
best_inliers = inliers

if best_line is not None:
best_lines.append(best_line)
# buffer = remaining_points
remaining_points = np.delete(remaining_points, best_inliers, axis=0)
# if len(remaining_points) < 1:
# remaining_points = np.append(remaining_points, buffer[:len(buffer)//2 + 1])

num_lines += 1

return np.array(best_lines)



def __get_best_lines(
self,
potential_points: np.ndarray
) -> np.ndarray:
“””
Gets the best lines using the least squares method.
Line y = kx + b.
Returns np.ndarray like [[k1, b1], [k2, b2]].
“”“
remaining_points = np.copy(potential_points)
best_lines = []
num_lines = 0

while num_lines < 3:
if num_lines == 0:
remaining_points = np.copy(potential_points)
print(f"remaining points: {len(remaining_points)}”)

best_line = None
lowest_residual = float(“inf”)

for i in range(self.iterations_num):
sample_indices = np.random.choice(
remaining_points.shape[0], size=3, replace=False)
sample_points = remaining_points[sample_indices]
sample_x = sample_points[:, 1]
sample_y = sample_points[:, 0]
coefficients = np.polyfit(sample_x, sample_y, deg=1)
predicted_y = np.polyval(coefficients, sample_x)
residual = np.sum((predicted_y - sample_y) ** 2)

if residual < lowest_residual:
best_line = coefficients
lowest_residual = residual

if best_line is not None:
best_lines.append(best_line)
remaining_points = np.delete(remaining_points, np.argmin(lowest_residual))

num_lines += 1

return np.array(best_lines)


# main
# image[image > 0] = 255
def reduce_noise(image, p=0.6):
# Преобразование изображения в массив numpy
img_array = np.array(image)

# Создание маски со случайными значениями от 0 до 1
mask = np.random.rand(*img_array.shape)

# Применение маски к изображению для установки значениями 0
img_array[mask < p] = 0

return img_array


# image = reduce_noise(image, p=0.1)
image[image > 0] = 255
image = cv2.medianBlur(image, 1)

print(“reduce noise”)
plt.imshow(image)
plt.show()



coords = get_coords_by_threshold(image)

# image = delete_pixels_by_min_threshold(image)

neigh_nums = get_neigh_nums_list(coords)

sorted_neigh_nums = sort_neight_nums_by_N(neigh_nums)

potential_points = get_potential_points_coords(sorted_neigh_nums)

best_lines = get_best_lines(potential_points)
print(best_lines)

# Visualization
plt.imshow(image, cmap=“gray”)
plt.scatter(potential_points[:, 1], potential_points[:, 0], color=“red”, marker=“o”)
plt.show()

# Plot the lines on the image
for equation in best_lines:
k, b = equation
x = np.arange(0, image.shape[1])
y = k * x + b
plt.imshow(image, cmap=“gray”)
plt.scatter(potential_points[:, 1], potential_points[:, 0], color=“red”, marker=“o”)
plt.plot(x, y, color=“green”)
plt.scatter(potential_points[:, 1], potential_points[:, 0], color=“red”, marker=“o”)
plt.show()


intersection_points = np.array([
np.linalg.solve(np.array([[best_lines[0][0], -1], [best_lines[1][0], -1]]), np.array([-best_lines[0][1], -best_lines[1][1]])),
np.linalg.solve(np.array([[best_lines[0][0], -1], [best_lines[2][0], -1]]), np.array([-best_lines[0][1], -best_lines[2][1]])),
np.linalg.solve(np.array([[best_lines[1][0], -1], [best_lines[2][0], -1]]), np.array([-best_lines[1][1], -best_lines[2][1]]))
], dtype=np.float32)


print(intersection_points)
end_time = time.time()
elapsed_time = end_time - start_time
print('Elapsed time: ', elapsed_time)

В данном коде мы проходимся ядром по изображению, чтобы посчитать соседей и заносим в новую матрицу число соседей. Перепиши код таким образом, чтобы мы проходились ядром с коэффицентами матрицей размером 5x5. Матрица будет выглядеть так [[-1, -1, -1, -1, -1], [-1, 4, 4, 4, -1 ], [-1, 4, 0, 4, -1], [-1, 4, 4, 4, -1 ], [-1, -1, -1, -1, -1]]. А записывать в новую матрицу мы будем уже не количество соседей, а значение сумму значений произведения интенсивности на коэффицент. ПЕРЕПИШИ ИСПРАВЛЕННЫЙ КОД