2010-06-25 117 views
6

我用Python成像庫的ImageDraw.line()繪製了一堆線條,但它們看起來很可怕,因爲我找不到一種方法來反鋸齒。我如何在PIL中防別線?如果PIL無法做到這一點,是否有另一個Python圖像處理庫可以?用Python成像庫繪製一條反鋸齒線

+0

可能的答案:http://stackoverflow.com/questions/1828345/any-way-to-make-nice-antialiased-圓角爲圖像在python – unutbu 2010-06-25 23:25:44

+0

嗯,我想這是一個解決方案,如果一個緩慢的。 – snostorm 2010-06-26 13:06:56

回答

3

aggdraw提供比PIL更好的繪圖。

+0

看起來很不錯,但它不是爲Ubuntu打包的。我有點需要。 – snostorm 2010-06-26 01:31:45

+0

使用基本繪製(點,筆)方法,線條在aggdraw中仍然看起來不連貫。 – 2013-07-17 07:20:17

+0

這可以用於Python3嗎? – DrMickeyLauer 2016-02-02 10:32:57

11

這是一個真正快速入侵的函數,用於繪製PIL的反鋸齒行,我在Google搜索同一個問題後看到這篇文章,並且未能安裝aggdraw並處於緊急截止日期之後編寫的。這是吳小林的線算法的實現。我希望它可以幫助任何人Google搜索相同的東西!

:)

"""Library to draw an antialiased line.""" 
# http://stackoverflow.com/questions/3122049/drawing-an-anti-aliased-line-with-thepython-imaging-library 
# https://en.wikipedia.org/wiki/Xiaolin_Wu%27s_line_algorithm 
import math 


def plot(draw, img, x, y, c, col, steep, dash_interval): 
    """Draws an antiliased pixel on a line.""" 
    if steep: 
     x, y = y, x 
    if x < img.size[0] and y < img.size[1] and x >= 0 and y >= 0: 
     c = c * (float(col[3])/255.0) 
     p = img.getpixel((x, y)) 
     x = int(x) 
     y = int(y) 
     if dash_interval: 
      d = dash_interval - 1 
      if (x/dash_interval) % d == 0 and (y/dash_interval) % d == 0: 
       return 
     draw.point((x, y), fill=(
      int((p[0] * (1 - c)) + col[0] * c), 
      int((p[1] * (1 - c)) + col[1] * c), 
      int((p[2] * (1 - c)) + col[2] * c), 255)) 


def iround(x): 
    """Rounds x to the nearest integer.""" 
    return ipart(x + 0.5) 


def ipart(x): 
    """Floors x.""" 
    return math.floor(x) 


def fpart(x): 
    """Returns the fractional part of x.""" 
    return x - math.floor(x) 


def rfpart(x): 
    """Returns the 1 minus the fractional part of x.""" 
    return 1 - fpart(x) 


def draw_line_antialiased(draw, img, x1, y1, x2, y2, col, dash_interval=None): 
    """Draw an antialised line in the PIL ImageDraw. 

    Implements the Xialon Wu antialiasing algorithm. 

    col - color 
    """ 
    dx = x2 - x1 
    if not dx: 
     draw.line((x1, y1, x2, y2), fill=col, width=1) 
     return 

    dy = y2 - y1 
    steep = abs(dx) < abs(dy) 
    if steep: 
     x1, y1 = y1, x1 
     x2, y2 = y2, x2 
     dx, dy = dy, dx 
    if x2 < x1: 
     x1, x2 = x2, x1 
     y1, y2 = y2, y1 
    gradient = float(dy)/float(dx) 

    # handle first endpoint 
    xend = round(x1) 
    yend = y1 + gradient * (xend - x1) 
    xgap = rfpart(x1 + 0.5) 
    xpxl1 = xend # this will be used in the main loop 
    ypxl1 = ipart(yend) 
    plot(draw, img, xpxl1, ypxl1, rfpart(yend) * xgap, col, steep, 
     dash_interval) 
    plot(draw, img, xpxl1, ypxl1 + 1, fpart(yend) * xgap, col, steep, 
     dash_interval) 
    intery = yend + gradient # first y-intersection for the main loop 

    # handle second endpoint 
    xend = round(x2) 
    yend = y2 + gradient * (xend - x2) 
    xgap = fpart(x2 + 0.5) 
    xpxl2 = xend # this will be used in the main loop 
    ypxl2 = ipart(yend) 
    plot(draw, img, xpxl2, ypxl2, rfpart(yend) * xgap, col, steep, 
     dash_interval) 
    plot(draw, img, xpxl2, ypxl2 + 1, fpart(yend) * xgap, col, steep, 
     dash_interval) 

    # main loop 
    for x in range(int(xpxl1 + 1), int(xpxl2)): 
     plot(draw, img, x, ipart(intery), rfpart(intery), col, steep, 
      dash_interval) 
     plot(draw, img, x, ipart(intery) + 1, fpart(intery), col, steep, 
      dash_interval) 
     intery = intery + gradient 
+0

什麼是col?什麼是陡峭的?一個小解釋將不勝感激。 – 2013-07-17 07:21:16

+0

@RamenRecon,我很好奇,也很陡。根據我對代碼的閱讀,steep是一個布爾值,它表示xdelta是否小於ydelta,因此如果行很陡,可能會影響算法,但它只在內部由drawLine函數和其輔助函數繪圖函數使用用戶不得不擔心。另一方面Col必須由用戶給出,並且似乎是用於決定每個點alpha透明度值(即抗混疊效果)的四元組RGBA顏色(紅色,gr,藍色,alpha)。好奇地嘗試一下,看看它有多快... – 2014-03-17 23:57:23

+1

Btw @toastie yours是唯一可以在任何地方看到抗鋸齒功能的手動Python實現。林驚訝你的答案沒有更多upvotes,即時通訊它確實幫助了一堆人。 +1 – 2014-03-18 00:04:14

2

我有一個類似的問題,我的臺詞有粗糙的邊緣,其中改變方向。我從線路如何在IOS中繪製線索並提出了這個代碼。它在線條的末端放置了圓形線條帽,並且真正清理了一些東西。不完全是反鋸齒,但是對於PIL來說是全新的,並且很難找到我想分享的答案。需要一些調整,有可能是一個更好的辦法,但確實是我需要:)


    from PIL import Image 
    import ImageDraw 

    class Point: 
     def __init__(self, x, y): 
      self.x = x 
      self.y = y 

    class DrawLines: 
     def draw(self, points, color, imageName): 
      img = Image.new("RGBA", [1440,1080], (255,255,255,0)) 
      draw = ImageDraw.Draw(img) 
      linePoints = [] 
      for point in points: 
       draw.ellipse((point.x-7, point.y-7, point.x+7, point.y+7), fill=color) 
       linePoints.append(point.x) 
       linePoints.append(point.y) 
      draw.line(linePoints, fill=color, width=14) 
      img.save(imageName) 

    p1 = Point(100,200) 
    p2 = Point(190,250) 
    points = [p1,p2] 

    red = (255,0,0) 
    drawLines = DrawLines() 
    drawLines.draw(points, red, "C:\\test.png")