См. Пример:
from PIL import Image, ImageFilter, ImageChops
import math
a = [['.','.','.','.','.','.','.'],
['.','.','.','.','.','.','.'],
['.','.','.','.','.','.','.'],
['.','#','#','#','.','.','.'],
['.','#','#','#','.','.','.'],
['.','.','.','.','.','.','.']]
sz=(len(a[0]), len(a))
flat_list = [j=='.' for i in a for j in i]
image=Image.new('1', sz)
image.putdata(flat_list)
contour=ImageChops.difference(image, image.filter(ImageFilter.MinFilter(3)))
contour_list=list(contour.getdata())
points=[divmod(i,sz[0]) for i in range(len(contour_list)) if contour_list[i]]
points_x,points_y=zip(*points)
avg=lambda x: sum(x)/len(x)
mean_x=avg(points_x)
mean_y=avg(points_y)
phase=[(math.atan2(points_y[i]-mean_y, points_x[i]-mean_x),i) \
for i in range(len(points))]
phase.sort()
for i in range(len(points)):
print(*points[phase[i][1]])