【问题标题】:Drawing an anti-aliased line with thePython Imaging Library [closed]使用 Python Imaging Library 绘制抗锯齿线 [关闭]
【发布时间】:2010-06-25 23:21:38
【问题描述】:

我正在使用 Python Imaging Library 的 ImageDraw.line() 绘制一堆线条,但它们看起来很糟糕,因为我找不到消除锯齿的方法。如何在 PIL 中消除锯齿线?

【问题讨论】:

  • 好吧,我想这是一种解决方案,如果是一个缓慢的解决方案。
  • 这个问题应该重新打开,因为它询问如何在特定库中消除锯齿行。我已经编辑删除了要求其他建议的行。

标签: python image graphics python-imaging-library antialiasing


【解决方案1】:

这是一个非常快速的组合功能,用于使用 PIL 绘制抗锯齿线,这是我在谷歌搜索同一问题后编写的,看到这篇文章并未能安装 aggdraw 并且时间紧迫。这是小林吴的线算法的实现。我希望它可以帮助任何在谷歌上搜索相同内容的人!

:)

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

【讨论】:

  • 什么是col?什么是陡峭?一点解释将不胜感激。
  • @RamenRecon,我也对 col 和陡峭感到好奇。根据我对代码的阅读,陡峭是一个布尔值,用于判断 xdelta 是否小于 ydelta,因此如果线陡峭,这可能会影响算法,但它仅由 drawLine 函数及其绘图辅助函数在内部使用,所以什么都不是用户不得不担心。另一方面,Col 必须由用户给出,并且看起来是 4 元组 RGBA 颜色(红色、gr、blu、alpha),用于决定每个点的 alpha 透明度值(即抗锯齿效果)。很想尝试一下,看看它有多快......
  • 顺便说一句 @toastie yours 是我在任何地方看到的唯一用于抗锯齿的手动 Python 实现。令我惊讶的是,您的回答没有更多的赞成票,但我确信它帮助了很多人。 +1
  • 感谢您的回答。 @MattN.D.Hat,正如卡里姆所说,“陡峭”是一个布尔值,用于判断线条是否更接近垂直而不是水平。 Wu 线 dawing 算法的工作原理是获取线的任一侧的像素并根据它们与线的接近程度对它们进行加权(本质上给它们一个不透明度或 alpha 值)。如果线更接近垂直,则这些像素是水平的,否则它们是垂直的。我希望这是有帮助的。这段代码似乎改编自维基百科文章en.wikipedia.org/wiki/Xiaolin_Wu%27s_line_algorithm
  • 您不需要知道 c 或陡峭是什么。只要调用,draw_line_antialiased(draw, img, x1, y1, x2, y2, col) col就是颜色,必须包含RGB和A
【解决方案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")

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-08-15
    • 2023-04-07
    • 2010-12-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多