Curve tracing or curve fitting in Python
I have split contours in a image and I want to connect them somehow. I was considering some curve fitting or curve tracing - but I do not know, how can I implement it.
I have exactly 1 px wide split contours:
import itertools
import cv2
# Get all pixel directions
directions = list(itertools.product([-1, 0, 1], repeat=2))
directions.remove((0, 0))
# Load image
img = cv2.imread("image.png", cv2.IMREAD_COLOR)
gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
cv2.imshow("Input", img)
# Find contours
_, thresh = cv2.threshold(gray, 25, 255, cv2.THRESH_BINARY)
contours, _ = cv2.findContours(thresh, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)
I know, where are ends of all contours:
for cnt in contours:
ends = []
# Get ends of contour
# - first pixel is not always the first pixel of open contour
# - last pixel is not mostly the last pixel in contour
for pix in cnt:
pixel = tuple(pix[0])
pixel_x, pixel_y = pixel
total_neighbours = 0
# Count pixel neighbours
for plus_x, plus_y in directions:
current_x = pixel_x + plus_x
current_y = pixel_y + plus_y
if current_y < 0 or current_y >= gray.shape[0]:
continue
if current_x < 0 or current_x >= gray.shape[1]:
continue
if gray[current_y][current_x]:
total_neighbours += 1
# If it is end pixel
if total_neighbours == 1:
ends.append(pixel)
cv2.circle(img, pixel, 3, (0, 255, 255), 1)
As a human I know, where are the curves and what contours are part of each unique curve:
But I do not know, how can I connect these split contours programmatically.
I tried using first and second derivative to predict, but it was not good enough:
# Make contour "predictions"
# - go from end to second end and calculate first derivative
# - "predict" on second end contour connection
for end in ends:
pixel_x, pixel_y = end
def predict(pixel_x, pixel_y, was):
for plus_x, plus_y in directions:
current_x = pixel_x + plus_x
current_y = pixel_y + plus_y
if current_y < 0 or current_y >= gray.shape[0]:
continue
if current_x < 0 or current_x >= gray.shape[1]:
continue
if (current_x, current_y) not in ends:
if (current_x, current_y) not in was:
if gray[current_y][current_x]:
was.append((current_x, current_y))
predict(current_x, current_y, was)
else:
derivatives_x = []
derivatives_y = []
# Calculate derivative
for pix in range(len(was) - 3):
x1, y1 = was[pix]
x2, y2 = was[pix + 3]
derivatives_x.append(x1 - x2)
derivatives_y.append(y1 - y2)
if not derivatives_x:
continue
# Get last N derivatives and average them
avg_x = derivatives_x[-20:]
avg_y = derivatives_y[-20:]
avg_x = sum(avg_x) / len(avg_x)
avg_y = sum(avg_y) / len(avg_y)
# Predict N pixels
for i in range(7):
pos = round(x2 - avg_x * i), round(y2 - avg_y * i)
cv2.circle(img, pos, 1, (0, 0, 255), cv2.FILLED)
predict(pixel_x, pixel_y, [])
cv2.imshow("Output", img)
cv2.waitKey(0)
Anybody knows how to fit some curve/spline/Bezier/.. to it and recognize the curves as a human?
Thanks.
from Recent Questions - Stack Overflow https://ift.tt/3EJYPNT
https://ift.tt/3CZo6lB
Comments
Post a Comment