2016-05-08 5 views
3

Ich möchte das Teilbild erhalten, das aus dem Ausschneiden eines Polygons in einem Bild resultiert.Bildsegment aus Polygon extrahieren, mit skimage

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

Wie geht das?

Unten ist, was ich versucht habe. Ich suche nicht unbedingt nach einem ähnlichen Weg, ich suche nach der saubersten und effizientesten Implementierung.


Mit diesem Code überlagert das Polygon richtig den Teil des Bildes I extrahiert werden soll (aber das Segment von Interesse nicht 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) 

enter image description here

Aber wenn Ich versuche, das segmentierte Bild mit diesem Code zu erhalten, das Overlay zeigt falsch an:

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

enter image description here

Es sieht aus wie die Y des Polygons müssen Koordinaten nur gespiegelt (vor allem, da das obere Bild zeigt Y-Achse umgekehrt zu bestellen), 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() 

enter image description here

(Tatsächlich gibt es nicht nur ein Offset-Problem in X-Koordinaten, es gibt sogar ein Skalierungsproblem in Y-Koordinaten. Ich habe keine Ahnung warum)

+0

Was ist Ann in der Schleife? für SEG in ann [ 'Segmentierungs']: poly = np.array (SEG) .reshape ((len (seg)/2, 2)) polygons.append (Polygon (poly, True, alpha = 0,4)) color.append (c) –

Antwort

3

Ich kann das seltsame Verhalten auch nicht erklären. Auf jeden Fall habe ich kürzlich in another question ein Rezept vorgeschlagen, das hier helfen könnte (obwohl ich es nicht die sauberste Lösung nennen würde). Mit diesem (nicht sehr hübsch) 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 das gewünschte Ergebnis bauen:

Cropped figure

Der Code, der für Sie am wichtigsten ist, ist dies:

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 und Klick zu erstellen:

Point and click polygon crop

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

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