下面是一个使用 Python 的演示,
它会显示图像让您更好地了解正在发生的事情。
from typing import List, Tuple
import pyclipper
import numpy as np
import cv2
from grid_extractor import show_img # pip install grid_extractor # Don't worry. It's a simple library. I am lazy, so I don't want to write a lot of things that is not what I cared, so I use a library that I publish to PyPI instead of it.
from matplotlib.colors import LinearSegmentedColormap
import matplotlib._cm
import matplotlib.pyplot
def main():
point_list = (
(348, 257), (364, 148), (362, 148), (326, 241),
(295, 219), (258, 88), (440, 129), (370, 196),
(372, 275)
)
img = init_canvas(max([x for x, y in point_list]), max([y for x, y in point_list]))
# Show original data on the image
draw_point_list(img, point_list, bgr_color=(0, 255, 255), size=5)
draw_line(img, point_list, (255, 255, 0), thickness=3)
# show_img(img)
# Show the result after `pco.Execute`
pco = pyclipper.PyclipperOffset()
pco.AddPath(point_list, pyclipper.JT_ROUND, pyclipper.ET_CLOSEDPOLYGON)
contours_list: List[List[Tuple[int, int]]] = pco.Execute(-7.0) # - shrink the outline
dot_thickness = 3
line_thickness = 2
bgr_color_list = get_color_list('gist_rainbow', num_colors=len(contours_list))
for contours, color in zip(contours_list, bgr_color_list):
color = np.array(list(color)) * 255
print(f'number of points found: {len(contours)}')
draw_point_list(img, contours, color, dot_thickness)
draw_line(img, contours, color, line_thickness)
show_img(img)
if __name__ == '__main__':
main()
结果图像

额外代码
我不想一次把代码写得太长(可能会导致用户不愿意阅读),所以我决定把不重要的代码放在这里。如果你想跑,只要把它放在一起跑,就完成了。
def get_color_list(cmap_name: str, num_colors: int, ft='bgr') -> List[Tuple[float, float, float]]:
"""
::
bgr_list = get_color_list(cmap_name='gist_rainbow', num_colors=120)
rgb_list = get_color_list(cmap_name='gist_rainbow', num_colors=120, ft='rgb')
for color in bgr_list:
color = np.array(list(color)) * 255
"""
assert cmap_name in matplotlib._cm.datad, KeyError(cmap_name)
cm: LinearSegmentedColormap = matplotlib.pyplot.get_cmap(cmap_name)
color_list = [(int(b * 255) / 255, int(g * 255) / 255, int(r * 255) / 255) if ft == 'bgr' else
(int(r * 255) / 255, int(g * 255) / 255, int(b * 255) / 255)
for r, g, b, a in
[cm.__call__(1. * i / num_colors) for i in range(num_colors)]
]
return color_list # some kind of stuff like that `[(1, 0, 0), (0, 1, 0) ...]`
def init_canvas(max_x: int, max_y: int) -> np.ndarray:
img = np.ones((int(max_y * 1.2), int(max_x * 1.2), 3), # 1.2 is margin
dtype=np.uint8) * 255 # fill the background with white color
return img
def draw_point_list(img, point_list, bgr_color: Tuple[int, int, int], size):
for x, y in point_list:
img[int(y - size):int(y + size), int(x - size): int(x + size)] = bgr_color
def draw_line(img, point_list, bgr_color: Tuple[int, int, int], thickness, close_flag=True):
"""
draw a line which cross every points.
"""
begin_point = point_list[0]
for i, (x, y) in enumerate(point_list):
if i == 0:
continue
end_point = (x, y)
cv2.line(img, tuple(begin_point), end_point, bgr_color, thickness)
begin_point = end_point
if close_flag:
cv2.line(img, tuple(begin_point), tuple(point_list[0]), bgr_color, thickness)