[英]Image segmentation in Python + Processing
我在尝试运行此图像分割代码时遇到了困难。
我的想法是拍摄像这样的图像:
并提取所有黑色的波浪形并将每个波浪形保存为自己的图像。
似乎代码正在运行,但是由于某种原因它没有对我的图像进行分段。
我收到的错误是:( ('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
快速调查发现了问题所在:此功能在这里
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
,请参见此处的说明。
但是,这不是唯一的问题。 对于示例中的图像, offset=10
会降低threshold_local产生的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;就我所知,此问题与处理无关),它将返回Segments detected: 108
,并产生很好的细分:
plt.imshow(segments[0],interpolation='none')
plt.show()
旁注:基于您对问题的措辞,我是否正确地假设您自己没有编写此代码,并且您在该领域的专业知识可能有限?
如果是这样,您可能有兴趣了解更多有关基于python的图像处理和分割的信息。 我最近在这个主题上做了一个简短的课程,其中包括一个完全不言自明的关于管道的动手教程,与您在此使用的类似。 这些材料可公开访问,因此可以随时查看。
编辑:
根据您的评论,这里是一个解决方案,应允许程序以完整路径作为输入运行。
首先,删除所有这些:
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:
为了透明scipy.misc.imsave
,如果将数组另存为RGBA(MxNx4),则scipy.misc.imsave
允许使用alpha图层,请参见此处 。
取代这个
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'...'
格式会产生原始字符串文字 。)
接下来,替换这个
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)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.