Bildsegment aus Polygon extrahieren, mit Skimage

Ich möchte das Sub-Image, das aus dem Ausschneiden eines Polygons in einem Bild resultiert, erhalten.

Ich habe ein Bild im Skimage, und ich habe ein Polygon in matplotlib.patches.

Wie es geht?

Unten ist was ich versucht habe. Ich bin nicht unbedingt auf der Suche nach einem ähnlichen Weg wie unten, ich bin auf der Suche nach der saubersten, effizientesten Umsetzung.


Mit diesem Code überlagert das Polygon den Teil des Bildes, das ich extrahieren möchte (aber nicht das Segment des Interesses extrahieren):

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) 

Bildbeschreibung hier eingeben

Aber wenn ich versuche, das segmentierte Bild mit diesem Code zu erhalten, erscheint das Overlay falsch:

 fig, ax = plt.subplots() im = ax.imshow(I) im.set_clip_path(polygon) plt.axis('off') plt.show() 

Bildbeschreibung hier eingeben

Es sieht aus wie die Y-Koordinaten des Polygons müssen nur umgedreht werden (vor allem seit Bild oben zeigt Y-Achse anders angeordnet), aber das ist nicht der Fall:

 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() 

Bildbeschreibung hier eingeben

(In der Tat gibt es nicht nur ein Offset-Problem in X-Koordinaten, es gibt sogar ein Skala Problem in Y-Koordinaten.Ich habe keine Ahnung warum)

One Solution collect form web for “Bildsegment aus Polygon extrahieren, mit Skimage”

Ich kann das seltsame Verhalten auch nicht erklären. In jedem Fall vor kurzem in einer anderen Frage habe ich ein Rezept vorgeschlagen, das hier helfen könnte (obwohl ich es nicht die sauberste Lösung nennen würde). Mit diesem (nicht sehr hübschen) Code:

 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() 

Ich kann dein gewünschtes Ergebnis bauen:

Freigegebene Figur

Der Code, der Ihnen am wichtigsten ist, ist:

 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() 

In diesem Fall habe ich ein Rezept verwendet, um ein Polygon nach Punkt zu bauen und zu klicken:

Punkt- und Klick-Polygon-Ernte

Und mit diesem Polygon habe ich den Alpha-Kanal (in RGBA, JPEG ist nur RGB ich denke) 0 für Transparenz.

Ich weiß, es ist nicht perfekt, aber ich hoffe es hilft.

Python ist die beste Programmiersprache der Welt.