【问题标题】:Python3 Pillow Get all pixels on a linePython3 Pillow 获取一条线上的所有像素
【发布时间】:2014-09-02 09:10:35
【问题描述】:

我需要沿着一条线获取像素值,我使用的是 Python3 和 Pillow。在 opencv 中有 LineIterator 这样的东西,它将返回两点之间的所有适当像素,但我在 Pillow 的文档中没有找到类似的东西。

我使用 Pillow 是因为我最初看到 this 帖子说 python3 没有 opencv 支持,我知道它是从 2012 年开始的,但这似乎得到了 this 帖子的证实,我相信它来自今年,鉴于职位上没有年份。但是当我运行 pip3.2 search opencv 我可以看到一个 pyopencv 但无法安装它,它说它找不到合适的版本(可能是 python2.x 到 python3.x 的问题)。

我的首选解决方案排序如下:

  1. 一种为python3正确安装opencv的方法(最好是opencv 2.4.8)
  2. 一种仅使用 Pillow 获取线条像素的方法
  3. 不涉及额外库 (numpy/scipy) 的简单解决方案
  4. 其他一切

【问题讨论】:

    标签: python opencv python-3.x numpy pillow


    【解决方案1】:

    我尝试了@Rick 建议的代码,但没有成功。然后我去Xiaolin's code用Matlab写的,翻译成Python:

    def xiaoline(x0, y0, x1, y1):
    
            x=[]
            y=[]
            dx = x1-x0
            dy = y1-y0
            steep = abs(dx) < abs(dy)
    
            if steep:
                x0,y0 = y0,x0
                x1,y1 = y1,x1
                dy,dx = dx,dy
    
            if x0 > x1:
                x0,x1 = x1,x0
                y0,y1 = y1,y0
    
            gradient = float(dy) / float(dx)  # slope
    
            """ handle first endpoint """
            xend = round(x0)
            yend = y0 + gradient * (xend - x0)
            xpxl0 = int(xend)
            ypxl0 = int(yend)
            x.append(xpxl0)
            y.append(ypxl0) 
            x.append(xpxl0)
            y.append(ypxl0+1)
            intery = yend + gradient
    
            """ handles the second point """
            xend = round (x1);
            yend = y1 + gradient * (xend - x1);
            xpxl1 = int(xend)
            ypxl1 = int (yend)
            x.append(xpxl1)
            y.append(ypxl1) 
            x.append(xpxl1)
            y.append(ypxl1 + 1)
    
            """ main loop """
            for px in range(xpxl0 + 1 , xpxl1):
                x.append(px)
                y.append(int(intery))
                x.append(px)
                y.append(int(intery) + 1)
                intery = intery + gradient;
    
            if steep:
                y,x = x,y
    
            coords=zip(x,y)
    
            return coords
    

    最后,我使用上面的代码和一个脚本进行绘图:

        import numpy as np 
        import demo_interpolate_pixels_along_line as interp 
        import matplotlib.pyplot as plt
    
    
        A=np.zeros((21,21))
    
        p0=(5,15)
        p1=(20,5)
    
        coords=interp.xiaoline(p0[0],p0[1],p1[0],p1[1])
        for c in coords:
            A[c]=1
    
        A[p0]=0.2
        A[p1]=0.8
    
        plt.figure()
        plt.imshow(A.T,interpolation='none',
                        origin='lower',
                        cmap='gist_earth_r',
                        vmin=0,
                        vmax=1)
        plt.grid(which='major')
        plt.xlabel('X')
        plt.ylabel('Y')
        plt.text(p0[0],p0[1],'0',fontsize=18,color='r')
        plt.text(p1[0],p1[1],'1',fontsize=18,color='r')
        plt.show()
    

    ...我没有足够的声誉来发布图片:(

    【讨论】:

    • 很高兴您能找到解决方案,但我的代码不起作用是怎么回事?是有错误还是只是我发布后发生了一些变化?只是想知道我的解决方案是否需要更新。
    • 在小问题中添加import math 并将xpxl0xpxl1 转换为int,否则您会收到TypeError 消息(范围是int)。在主要问题中,如果我有一个 100x100 的网格并尝试绘制一条从 (10,70) 到 (80,80) 的线,我会得到一条从 (10,70) 到 (80,70) 的线。我不确定这是为什么,但这就是我在 Matlab 中使用原始代码的原因。
    • 请注意,在一半的情况下(取决于线的角度),这实际上会向后返回点。它也经常超过一个像素
    • 另外,代码x.append(xpxl1);y.append(ypxl1);x.append(xpxl1);y.append(ypxl1 + 1)可以放在主循环之后,这样端点实际上就在结果列表的末尾。
    【解决方案2】:

    我最终选择了基于 Xiaolin Wu's line algorithm 的直接 python 解决方案

    def interpolate_pixels_along_line(x0, y0, x1, y1):
        """Uses Xiaolin Wu's line algorithm to interpolate all of the pixels along a
        straight line, given two points (x0, y0) and (x1, y1)
    
        Wikipedia article containing pseudo code that function was based off of:
            http://en.wikipedia.org/wiki/Xiaolin_Wu's_line_algorithm
        """
        pixels = []
        steep = abs(y1 - y0) > abs(x1 - x0)
    
        # Ensure that the path to be interpolated is shallow and from left to right
        if steep:
            t = x0
            x0 = y0
            y0 = t
    
            t = x1
            x1 = y1
            y1 = t
    
        if x0 > x1:
            t = x0
            x0 = x1
            x1 = t
    
            t = y0
            y0 = y1
            y1 = t
    
        dx = x1 - x0
        dy = y1 - y0
        gradient = dy / dx  # slope
    
        # Get the first given coordinate and add it to the return list
        x_end = round(x0)
        y_end = y0 + (gradient * (x_end - x0))
        xpxl0 = x_end
        ypxl0 = round(y_end)
        if steep:
            pixels.extend([(ypxl0, xpxl0), (ypxl0 + 1, xpxl0)])
        else:
            pixels.extend([(xpxl0, ypxl0), (xpxl0, ypxl0 + 1)])
    
        interpolated_y = y_end + gradient
    
        # Get the second given coordinate to give the main loop a range
        x_end = round(x1)
        y_end = y1 + (gradient * (x_end - x1))
        xpxl1 = x_end
        ypxl1 = round(y_end)
    
        # Loop between the first x coordinate and the second x coordinate, interpolating the y coordinates
        for x in range(xpxl0 + 1, xpxl1):
            if steep:
                pixels.extend([(math.floor(interpolated_y), x), (math.floor(interpolated_y) + 1, x)])
    
            else:
                pixels.extend([(x, math.floor(interpolated_y)), (x, math.floor(interpolated_y) + 1)])
    
            interpolated_y += gradient
    
        # Add the second given coordinate to the given list
        if steep:
            pixels.extend([(ypxl1, xpxl1), (ypxl1 + 1, xpxl1)])
        else:
            pixels.extend([(xpxl1, ypxl1), (xpxl1, ypxl1 + 1)])
    
        return pixels
    

    【讨论】:

    • 请注意,在一半的情况下(取决于线的角度),这实际上会向后返回点。它也经常超过一个像素
    【解决方案3】:

    你应该试试opencv的开发版本3.0-dev。当前的2.4系列将不支持python3。检查this answer

    使用枕头时,Image.getpixel 会给你像素值。因此,您可以简单地在纯 python 中插入两个点并将所有这些索引提供给 Image.getpixel。我不知道一个优雅的纯 python 插值实现来获取一条线上的所有像素。

    所以,如果这太麻烦了,您可以使用 numpy/matplotlib 来更轻松地完成它(懒惰)。您可以使用matplotlib.path.Path 创建路径并使用其 contains_points 方法遍历所有可能的点(例如使用 numpy.meshgrid 获取由这两个点定义的绑定框的所有像素坐标)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-06-08
      • 1970-01-01
      • 2016-10-05
      • 2020-03-27
      • 2015-02-08
      • 2021-12-28
      相关资源
      最近更新 更多