6

Ich zeichne eine Reihe von Linien mit der ImageDraw.line() der Python Imaging Library, aber sie sehen schrecklich aus, da ich keine Möglichkeit finde, sie zu anti-aliasieren. Wie kann ich Linien in PIL anti-alias? Wenn PIL es nicht kann, gibt es eine andere Python-Bildmanipulationsbibliothek?Zeichnen einer Anti-Alias-Linie mit der Python-Imaging-Bibliothek

+0

Mögliche Antwort: http://stackoverflow.com/questions/1828345/any-way-to-make-nice-antialiased- Round-Ecken-für-Bilder-in-Python – unutbu

+0

Nun, ich nehme an, das ist eine Lösung, wenn eine langsame. – snostorm

Antwort

3

aggdraw bietet eine schönere Zeichnung als PIL.

+0

Sieht gut aus, aber es ist nicht für Ubuntu verpackt. Ich brauche das irgendwie. – snostorm

+0

Die Linien sehen immer noch abgehackt aus, wenn Sie mit der grundlegenden Zeichenmethode (Punkte, Stift) arbeiten. –

+0

Ist das für Python3 noch verfügbar? – DrMickeyLauer

11

Dies ist eine sehr schnell gehackte Funktion, um eine Anti-Alias-Linie mit PIL zu zeichnen, die ich nach dem googlen für das gleiche Problem geschrieben habe, diesen Beitrag zu sehen und Aggdraw nicht zu installieren und in einer engen Frist zu sein. Es ist eine Implementierung des Linienalgorithmus von Xiaolin Wu. Ich hoffe, es hilft jedem, für dasselbe zu googeln !!

:)

"""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

Was ist col? Was ist steil? Eine kleine Erklärung würde sehr geschätzt werden. –

+0

@RamenRecon, ich war neugierig auf Col und auch steil. Basierend auf meinem Code lesen, ist Steil ein boolescher für ob xdelta ist kleiner als ydelta und damit, wenn die Linie steil ist, was wahrscheinlich den Algorithmus betrifft, aber es wird nur intern von der DrawLine-Funktion und seiner Plot-Helfer-Funktion verwendet, so ist nichts Der Benutzer muss sich Sorgen machen. Col hingegen muss vom Benutzer angegeben werden und scheint eine 4-Tupel-RGBA-Farbe (rot, gr, blau, alpha) zu sein, die verwendet wird, um den Alpha-Transparenzwert jedes Punktes zu bestimmen (dh den Antialiasing-Effekt). Neugierig, es zu versuchen und zu sehen, wie schnell es ist ... –

+1

Btw @ Toastie Ihre ist die einzige manuelle Python-Implementierung für Antialiasing ive überall gesehen. Ich bin überrascht, dass Ihre Antwort nicht mehr upvotes, ich bin sicher, es hat eine Reihe von Menschen obwohl geholfen. +1 –

2

Ich hatte ein ähnliches Problem, meine Linien Ecken und Kanten hatten, wo Richtungen zu verändern. Ich habe einen Hinweis darauf, wie Linien in IOS gezogen werden und kam mit diesem Code. Es setzt gerundete Linienkappen an den Enden der Linien und räumt wirklich alles auf. Nicht gerade Anti-Aliasing, aber für PIL total neu und es fiel mir so schwer, eine Antwort zu finden, die ich teilen würde. Braucht einige Optimierungen und es ist wahrscheinlich ein besserer Weg, aber das tut, was ich :) brauchen


    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")