使用PIL的Imagedraw创建具有指定厚度的弧
我正在尝试使用PIL和Imagedraw来创建一个分段的弧形。弧形函数让我可以很简单地画出一个弧,但它只是一个线条。我需要能够绘制一个指定半径和厚度(内径到外径)的弧形,但我找不到任何设置厚度或宽度的方法。有没有办法做到这一点?如果没有,使用PIL还有其他方法可以实现吗?
代码片段:
import Image
import ImageDraw
conv = 0.1
ID = 15
OD = 20
image = Image.new('1',(int(ceil(OD/conv))+2,int(ceil(OD/conv))+1), 1)
draw = ImageDraw.Draw(image)
diam = OD-ID
box=(1, 1, int(ceil(diam/conv)), int(ceil(diam/conv))) #create bounding box
draw.arc(box, 0, 90, 0) #draw circle in black
4 个回答
1
PIL(Python Imaging Library)不能画很宽的弧形,但Aggdraw可以,而且它和PIL配合得很好(它们是同一个作者做的)。
3
我根据Mark的建议,创建了以下的弧形替换函数:
https://gist.github.com/skion/9259926
可能不是完全精准(也不算快),但对于我需要的功能来说,似乎差不多。如果你有更好的版本,请在这个Gist里留言。
def arc(draw, bbox, start, end, fill, width=1, segments=100):
"""
Hack that looks similar to PIL's draw.arc(), but can specify a line width.
"""
# radians
start *= math.pi / 180
end *= math.pi / 180
# angle step
da = (end - start) / segments
# shift end points with half a segment angle
start -= da / 2
end -= da / 2
# ellips radii
rx = (bbox[2] - bbox[0]) / 2
ry = (bbox[3] - bbox[1]) / 2
# box centre
cx = bbox[0] + rx
cy = bbox[1] + ry
# segment length
l = (rx+ry) * da / 2.0
for i in range(segments):
# angle centre
a = start + (i+0.5) * da
# x,y centre
x = cx + math.cos(a) * rx
y = cy + math.sin(a) * ry
# derivatives
dx = -math.sin(a) * rx / (rx+ry)
dy = math.cos(a) * ry / (rx+ry)
draw.line([(x-dx*l,y-dy*l), (x+dx*l, y+dy*l)], fill=fill, width=width)
0
我发现一个小技巧,就是在黑色圆圈里面再画一个白色圆圈。你可以用“饼状切片”这个方法来根据需要把它们分开。绘制是按顺序进行的,所以你只需要把顺序搞对就行。比较难的是要把位置调整好,因为Imagedraw使用的是边界框,而不是中心和半径坐标。你必须确保所有东西的中心都完全重合。
这个解决方案只在特定情况下有效,具体请看评论。