Python + Processing中的图像分割

时间:2017-07-14 22:27:22

标签: python numpy scipy processing image-segmentation

我在尝试运行此图像分段代码时遇到了困难 我的想法是拍摄如下图像:

http://imgur.com/a/AmcKq

并提取所有黑色波浪形并将每个单独的波浪形保存为自己的图像 看起来代码工作正常,但由于某种原因它没有对我的图像进行分割 我得到的错误是:('segments detected:', 0)

这是我使用的代码:

import os, sys  
import numpy as np  
from scipy import ndimage as ndi  
from scipy.misc import imsave  
import matplotlib.pyplot as plt  

from skimage.filters import sobel, threshold_local  
from skimage.morphology import watershed  
from skimage import io  


def open_image(name):  
    filename = os.path.join(os.getcwd(), name)  
    return io.imread(filename, as_grey=True)  


def adaptive_threshold(image):  
    print(type(image))  
    print(image)  
    block_size = 41  
    binary_adaptive = threshold_local(image, block_size, offset=10)  
    binary_adaptive = np.asarray(binary_adaptive, dtype=int)  
    return np.invert(binary_adaptive) * 1.  


def segmentize(image):  
    # make segmentation using edge-detection and watershed  
    edges = sobel(image)  
    markers = np.zeros_like(image)  
    foreground, background = 1, 2  
    markers[image == 0] = background  
    markers[image == 1] = foreground  

    ws = watershed(edges, markers)  

    return ndi.label(ws == foreground)  


def find_segment(segments, index):  
    segment = np.where(segments == index)  
    shape = segments.shape  

    minx, maxx = max(segment[0].min() - 1, 0), min(segment[0].max() + 1, shape[0])  
    miny, maxy = max(segment[1].min() - 1, 0), min(segment[1].max() + 1, shape[1])  

    im = segments[minx:maxx, miny:maxy] == index  

    return (np.sum(im), np.invert(im))  


def run(f):  
    print('Processing:', f)  

    image = open_image(f)  
    processed = adaptive_threshold(image)  
    segments = segmentize(processed)  

    print('Segments detected:', segments[1])  

    seg = []  
    for s in range(1, segments[1]):  
        seg.append(find_segment(segments[0], s))  

    seg.sort(key=lambda s: -s[0])    

    for i in range(len(seg)):  
        imsave('segments/' + f + '_' + str(i) + '.png', seg[i][1])  

folder = os.path.join(os.getcwd(), 'segments')  
os.path.isfile(folder) and os.remove(folder)  
os.path.isdir(folder) or os.mkdir(folder)  
for f in sys.argv[1:]:  
    run(f)  

我还要提到我在Processing 3.3.5中运行这个Python脚本,使用它作为我的草图文件:

import deadpixel.command.Command;  

static final String BASH =  
  platform == WINDOWS? "cmd /C " :  
  platform == MACOSX? "open" : "xdg-open";  

static final String CD = "cd ", PY_APP = "python ";  
static final String AMP = " && ", SPC = " ";  

static final String PY_DIR = "scripts/";  
//static final String PY_FILE = PY_DIR + "abc.py";  
static final String PY_FILE = PY_DIR + "segmenting.py";  

static final String PICS_DIR = "images/";  
static final String PICS_EXTS = "extensions=,png,jpg,jpeg,gif";  

void setup() {  
  final String dp = dataPath(""), py = dataPath(PY_FILE);  
  final String prompt = BASH + CD + dp + AMP + PY_APP + py;  

  final String pd = dataPath(PICS_DIR);  
  final String pics = join(listPaths(pd, PICS_EXTS), SPC);  

  final Command cmd = new Command(prompt + SPC + pics);  
  println(cmd.command, ENTER);  

  println("Successs:", cmd.run(), ENTER);  
  printArray(cmd.getOutput());  

  exit();  
}   

这是在处理的新标签中:
https://github.com/GoToLoop/command/blob/patch-1/src/deadpixel/command/Command.java

1 个答案:

答案 0 :(得分:0)

快速调查显示问题:此功能在这里

def adaptive_threshold(image):  
    print(type(image))  
    print(image)  
    block_size = 41  
    binary_adaptive = threshold_local(image, block_size, offset=10)  
    binary_adaptive = np.asarray(binary_adaptive, dtype=int)  
    return np.invert(binary_adaptive) * 1. 

应该通过自适应阈值处理来创建图像的掩码 - 但这会(非常)错误。

主要原因似乎是对threshold_local如何工作的误解:此代码期望它返回输入图像的二值化分段版本,而实际上它返回threshold image,请参阅解释{ {3}}

然而,这不是唯一的问题。对于您示例中的图像,offset=10会将threshold_local生成的阈值降低太多,因此整个图像将高于阈值。

这是该函数的工作版本:

def adaptive_threshold(image):

    # Create threshold image
    # Offset is not desirable for these images
    block_size = 41 
    threshold_img = threshold_local(image, block_size)

    # Binarize the image with the threshold image
    binary_adaptive = image < threshold_img

    # Convert the mask (which has dtype bool) to dtype int
    # This is required for the code in `segmentize` (below) to work
    binary_adaptive = binary_adaptive.astype(int)   

    # Return the binarized image
    return binary_adaptive

如果使用此函数运行代码(使用python;此问题与Processing无关,据我所知),它返回Segments detected: 108并产生一个很好的分段:

plt.imshow(segments[0],interpolation='none')
plt.show()

here

旁注:根据您如何处理您的问题,我是否正确地假设您自己没有编写此代码并且您可能在此领域的专业知识有限?

如果是这样,您可能有兴趣学习更多关于基于python的图像处理和分割。我最近在这个主题上开了一个简短的课程,其中包括一个完全不言自明的管道实践教程,类似于你在这里使用的管道。 enter image description here是公开访问的,所以请随时查看。

编辑:

根据您的评论,这是一个解决方案,应该允许程序以完整路径作为输入运行。

首先,删除所有这些:

folder = os.path.join(os.getcwd(), 'segments')  
os.path.isfile(folder) and os.remove(folder)  
os.path.isdir(folder) or os.mkdir(folder)  

所以只剩下这个:

for f in sys.argv[1:]:  
    run(f)

接下来,替换它:

    for i in range(len(seg)):  
        imsave('segments/' + f + '_' + str(i) + '.png', seg[i][1])  

由此:

    # Get the directory name (if a full path is given)
    folder = os.path.dirname(f)

    # Get the file name
    filenm = os.path.basename(f)

    # If it doesn't already exist, create a new dir "segments" 
    # to save the PNGs
    segments_folder = os.path.join(folder,"segments")
    os.path.isdir(segments_folder) or os.mkdir(segments_folder)

    # Save the segments to the "segments" directory
    for i in range(len(seg)):
        imsave(os.path.join(segments_folder, filenm + '_' + str(i) + '.png'), seg[i][1]) 

此解决方案可以处理仅文件输入(例如'test.png')和路径输入(例如'C:\Users\Me\etc\test.png')。

编辑2:

对于透明度,如果数组保存为RGBA(MxNx4),scipy.misc.imsave允许使用alpha图层,请参阅The materials

替换此

        imsave(os.path.join(segments_folder, filenm + '_' + str(i) + '.png'), seg[i][1]) 

由此

        # Create an MxNx4 array (RGBA)
        seg_rgba = np.zeros((seg[i][1].shape[0],seg[i][1].shape[1],4),dtype=np.bool)

        # Fill R, G and B with copies of the image
        for c in range(3):
            seg_rgba[:,:,c] = seg[i][1]

        # For A (alpha), use the invert of the image (so background is 0=transparent)
        seg_rgba[:,:,3] = ~seg[i][1]

        # Save image
        imsave(os.path.join(segments_folder, filenm + '_' + str(i) + '.png'), seg_rgba) 

编辑3:

用于保存到每个分段图像的具有单独子文件夹的其他目标文件夹:

而不是这一行

    folder = os.path.dirname(f)

您可以指定目标文件夹,例如

    folder = r'C:\Users\Dude\Desktop'

(请注意r'...'格式,这会产生here。)

接下来,替换此

    segments_folder = os.path.join(folder,"segments")

由此

    segments_folder = os.path.join(folder,filenm[:-4]+"_segments")

并且要额外清洁,请替换此

        imsave(os.path.join(segments_folder, filenm + '_' + str(i) + '.png'), seg_rgba) 

由此

        imsave(os.path.join(segments_folder, filenm[:-4] + '_' + str(i) + '.png'), seg_rgba)