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
Antwort
aggdraw bietet eine schönere Zeichnung als PIL.
Sieht gut aus, aber es ist nicht für Ubuntu verpackt. Ich brauche das irgendwie. – snostorm
Die Linien sehen immer noch abgehackt aus, wenn Sie mit der grundlegenden Zeichenmethode (Punkte, Stift) arbeiten. –
Ist das für Python3 noch verfügbar? – DrMickeyLauer
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
Was ist col? Was ist steil? Eine kleine Erklärung würde sehr geschätzt werden. –
@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 ... –
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 –
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")
Mögliche Antwort: http://stackoverflow.com/questions/1828345/any-way-to-make-nice-antialiased- Round-Ecken-für-Bilder-in-Python – unutbu
Nun, ich nehme an, das ist eine Lösung, wenn eine langsame. – snostorm