我需要沿着一条线获取像素值,我正在使用Python3和Pillow。在opencv中有一个LineIterator这样的东西会返回两点之间的所有相应像素,但我在Pillow的文档中找不到类似的东西。
我正在使用Pillow,因为我最初看到this帖子说python3没有opencv支持,我知道它是从2012年开始的,但这似乎是由this帖子证实的我相信是从今年起,因为这些职位没有一年。但是当我运行pip3.2搜索opencv时我可以看到pyopencv但是无法安装它,它说它找不到合适的版本(可能是python2.x到python3.x问题)。
我首选的解决方案如下:
答案 0 :(得分:5)
我最终选择了基于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
答案 1 :(得分:2)
您应该尝试使用opencv的开发版3.0-dev。目前的2.4系列不支持python3。检查this answer。
使用枕头时,Image.getpixel会为您提供像素值。因此,您可以简单地在纯python中插入两个点,并将所有这些索引提供给Image.getpixel。我不知道优雅的纯python实现插值来获取一行上的所有像素。
所以,如果这太麻烦了,你可以使用numpy / matplotlib让它更容易(懒惰)。您可以使用matplotlib.path.Path创建路径并使用其contains_points方法遍历所有可能的点(例如,使用numpy.meshgrid获取由这两个点定义的绑定框的所有像素坐标)。
答案 2 :(得分:2)
我尝试了@Rick建议的代码,但它没有用。然后我去了用Matlab编写的{{3}}并将其翻译成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()
...我没有足够的声誉来发布图片:(