我想获得在图像中剪切多边形所产生的子图像。
我在skimage中有一个图像,我在matplotlib.patches中有一个多边形。
怎么做?
以下是我的尝试。我不一定在寻找类似于下面的方法,我正在寻找最干净,最有效的实现。
使用此代码,多边形正确地覆盖了我想要提取的图像部分(但不提取感兴趣的片段):
import numpy as np
import skimage.io as io
import matplotlib.pyplot as plt
from matplotlib.collections import PatchCollection
from matplotlib.patches import Polygon
I = io.imread(fp) # fp is path to image
plt.imshow(I)
ax = plt.gca()
polygons, color = [], []
c = np.random.random((1, 3)).tolist()[0]
for seg in ann['segmentation']:
poly = np.array(seg).reshape((len(seg)/2, 2))
polygons.append(Polygon(poly, True,alpha=0.4))
color.append(c)
p = PatchCollection(polygons, facecolors=color, edgecolors=(0,0,0,1), linewidths=3, alpha=0.4)
ax.add_collection(p)
但是当我尝试使用此代码获取分段图像时,叠加显示错误:
fig, ax = plt.subplots()
im = ax.imshow(I)
im.set_clip_path(polygon)
plt.axis('off')
plt.show()
看起来多边形的Y坐标只需要翻转(特别是因为上面的图像显示Y轴以其他方式排序),但事实并非如此:
a = polygons[0].xy.copy()
a[:,1] = im._A.shape[0] - a[:,1]
newPoly = Polygon(a, True,alpha=0.4)
fig, ax = plt.subplots()
im = ax.imshow(I)
im.set_clip_path(newPoly)
plt.axis('off')
plt.show()
(事实上,X坐标不仅存在偏移问题,Y坐标中甚至存在尺度问题。我不明白为什么)
答案 0 :(得分:3)
我也无法解释这种奇怪的行为。无论如何最近在another question我建议了一个可能对此有帮助的配方(尽管我不会称之为最干净的解决方案)。使用这个(不是很漂亮)的代码:
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
from matplotlib import path
class LineBuilder:
def __init__(self, line,ax,color):
self.line = line
self.ax = ax
self.color = color
self.xs = []
self.ys = []
self.cid = line.figure.canvas.mpl_connect('button_press_event', self)
self.counter = 0
self.shape_counter = 0
self.shape = {}
self.precision = 10
def __call__(self, event):
if event.inaxes!=self.line.axes: return
if self.counter == 0:
self.xs.append(event.xdata)
self.ys.append(event.ydata)
if np.abs(event.xdata-self.xs[0])<=self.precision and np.abs(event.ydata-self.ys[0])<=self.precision and self.counter != 0:
self.xs.append(self.xs[0])
self.ys.append(self.ys[0])
self.ax.scatter(self.xs,self.ys,s=120,color=self.color)
self.ax.scatter(self.xs[0],self.ys[0],s=80,color='blue')
self.ax.plot(self.xs,self.ys,color=self.color)
self.line.figure.canvas.draw()
self.shape[self.shape_counter] = [self.xs,self.ys]
self.shape_counter = self.shape_counter + 1
self.xs = []
self.ys = []
self.counter = 0
else:
if self.counter != 0:
self.xs.append(event.xdata)
self.ys.append(event.ydata)
self.ax.scatter(self.xs,self.ys,s=120,color=self.color)
self.ax.plot(self.xs,self.ys,color=self.color)
self.line.figure.canvas.draw()
self.counter = self.counter + 1
def create_shape_on_image(data,cmap='jet'):
def change_shapes(shapes):
new_shapes = {}
for i in range(len(shapes)):
l = len(shapes[i][1])
new_shapes[i] = np.zeros((l,2),dtype='int')
for j in range(l):
new_shapes[i][j,0] = shapes[i][0][j]
new_shapes[i][j,1] = shapes[i][1][j]
return new_shapes
fig = plt.figure()
ax = fig.add_subplot(111)
ax.set_title('click to include shape markers (10 pixel precision to close the shape)')
line = ax.imshow(data)
ax.set_xlim(0,data[:,:,0].shape[1])
ax.set_ylim(0,data[:,:,0].shape[0])
linebuilder = LineBuilder(line,ax,'red')
plt.gca().invert_yaxis()
plt.show()
new_shapes = change_shapes(linebuilder.shape)
return new_shapes
img = mpimg.imread('wm4HA.png')
shapes = create_shape_on_image(img)[0]
xx,yy = np.meshgrid(range(img.shape[0]),range(img.shape[1]))
shapes = np.hstack((shapes[:,1][:,np.newaxis],shapes[:,0][:,np.newaxis]))
p = path.Path(shapes)
for i in range(img.shape[0]):
for j in range(img.shape[1]):
if not p.contains_point((i,j)):
img[i,j,:] = np.array([0,0,0,0])
plt.imshow(img)
plt.show()
我可以建立你想要的结果:
对您来说最重要的代码是:
img = mpimg.imread('wm4HA.png')
shapes = create_shape_on_image(img)[0] # Here I'm calling a function to build a polygon.
xx,yy = np.meshgrid(range(img.shape[0]),range(img.shape[1]))
shapes = np.hstack((shapes[:,1][:,np.newaxis],shapes[:,0][:,np.newaxis]))
p = path.Path(shapes)
for i in range(img.shape[0]):
for j in range(img.shape[1]):
if not p.contains_point((i,j)):
img[i,j,:] = np.array([0,0,0,0])
plt.imshow(img)
plt.show()
在这种情况下,我使用配方通过点和点击构建多边形:
使用那个多边形,我制作了alpha通道(在RGBA中,JPEG只是RGB,我认为)0用于透明度。
我知道它并不完美,但我希望它有所帮助。