存储在矩阵中的图像的边缘检测

14 python algorithm numpy edge-detection

我以二维数组的形式表示图像.我有这张照片:

原版的

如何获得直接位于灰色区域边界上的像素并将其着色?

彩色

我想分别用绿色和红色得到矩阵元素的坐标.矩阵上只有白色,黑色和灰色区域.

Ed *_*ith 8

希望以下内容可以满足您的需求(或者至少是帮助).想法是使用基于阈值的逻辑检查分成各个区域.然后可以使用numpy roll检测这些区域之间的边缘以移动x和y中的像素并比较以查看我们是否处于边缘,

import matplotlib.pyplot as plt
import numpy as np
import scipy as sp
from skimage.morphology import closing

thresh1 = 127
thresh2 = 254

#Load image
im = sp.misc.imread('jBD9j.png')

#Get threashold mask for different regions
gryim = np.mean(im[:,:,0:2],2)
region1 =  (thresh1<gryim)
region2 =  (thresh2<gryim)
nregion1 = ~ region1
nregion2 = ~ region2

#Plot figure and two regions
fig, axs = plt.subplots(2,2)
axs[0,0].imshow(im)
axs[0,1].imshow(region1)
axs[1,0].imshow(region2)

#Clean up any holes, etc (not needed for simple figures here)
#region1 = sp.ndimage.morphology.binary_closing(region1)
#region1 = sp.ndimage.morphology.binary_fill_holes(region1)
#region1.astype('bool')
#region2 = sp.ndimage.morphology.binary_closing(region2)
#region2 = sp.ndimage.morphology.binary_fill_holes(region2)
#region2.astype('bool')

#Get location of edge by comparing array to it's 
#inverse shifted by a few pixels
shift = -2
edgex1 = (region1 ^ np.roll(nregion1,shift=shift,axis=0))
edgey1 = (region1 ^ np.roll(nregion1,shift=shift,axis=1))
edgex2 = (region2 ^ np.roll(nregion2,shift=shift,axis=0)) 
edgey2 = (region2 ^ np.roll(nregion2,shift=shift,axis=1))

#Plot location of edge over image
axs[1,1].imshow(im)
axs[1,1].contour(edgex1,2,colors='r',lw=2.)
axs[1,1].contour(edgey1,2,colors='r',lw=2.)
axs[1,1].contour(edgex2,2,colors='g',lw=2.)
axs[1,1].contour(edgey2,2,colors='g',lw=2.)
plt.show()
Run Code Online (Sandbox Code Playgroud)

哪个给了 以下.为简单起见,我使用roll与每个区域的倒数.您可以将每个连续区域滚动到下一个区域以检测边缘

感谢@Kabyle提供奖励,这是我花了一段时间寻找解决方案的问题.我尝试了scipy skeletonize,feature.canny,拓扑模块和openCV,但成效有限......这种方式对我来说是最强大的(Droplet界面跟踪).希望能帮助到你!


Ale*_*x I 5

有一个非常简单的解决方案:根据定义,具有白色和灰色邻居的任何像素都在“红色”边缘上,而具有灰色和黑色邻居的像素在“绿色”边缘上。最亮/最暗的邻居由中的最大/最小滤镜返回skimage.filters.rank,并且具有最亮/最暗的邻居(白色/灰色或灰色/黑色)的像素掩码的二进制组合分别产生边缘。

结果:

在此处输入图片说明

一个可行的解决方案:

import numpy
import skimage.filters.rank
import skimage.morphology
import skimage.io

# convert image to a uint8 image which only has 0, 128 and 255 values
# the source png image provided has other levels in it so it needs to be thresholded - adjust the thresholding method for your data
img_raw = skimage.io.imread('jBD9j.png', as_grey=True)
img = numpy.zeros_like(img, dtype=numpy.uint8)
img[:,:] = 128
img[ img_raw < 0.25 ] = 0
img[ img_raw > 0.75 ] = 255

# define "next to" - this may be a square, diamond, etc
selem = skimage.morphology.disk(1)

# create masks for the two kinds of edges
black_gray_edges = (skimage.filters.rank.minimum(img, selem) == 0) & (skimage.filters.rank.maximum(img, selem) == 128)
gray_white_edges = (skimage.filters.rank.minimum(img, selem) == 128) & (skimage.filters.rank.maximum(img, selem) == 255)

# create a color image
img_result = numpy.dstack( [img,img,img] )

# assign colors to edge masks
img_result[ black_gray_edges, : ] = numpy.asarray( [ 0, 255, 0 ] )
img_result[ gray_white_edges, : ] = numpy.asarray( [ 255, 0, 0 ] )

imshow(img_result)
Run Code Online (Sandbox Code Playgroud)

具有黑白邻居或所有三种颜色邻居的PS像素属于未定义类别。上面的代码不会给这些颜色上色。您需要弄清楚在这种情况下如何给输出着色。但是很容易扩展上面的方法来为此生成另一个或两个掩模。

PS边缘是两个像素宽。没有更多的信息就无法解决:边缘在两个区域之间,并且您还没有定义在每种情况下都希望它们重叠的两个区域中的哪个,因此唯一的对称解决方案是将两个区域重叠一个像素。

PS这会将像素本身视为自己的邻居。孤立的灰色白色或黑色像素,反之亦然,将被视为边缘(以及周围的所有像素)。


plo*_*ser 0

也许有一种更优雅的方法来做到这一点......但如果你的数组是一个具有尺寸(灰度)numpy的数组,你可以这样做(N,N)

import numpy as np

# assuming black -> 0 and white -> 1 and grey -> 0.5
black_reg = np.where(a < 0.1, a, 10)
white_reg = np.where(a > 0.9, a, 10)

xx_black,yy_black = np.gradient(black_reg)
xx_white,yy_white = np.gradient(white_reg)

# getting the coordinates
coord_green = np.argwhere(xx_black**2 + yy_black**2>0.2)
coord_red   = np.argwhere(xx_white**2 + yy_white**2>0.2)
Run Code Online (Sandbox Code Playgroud)

这个数字0.2只是一个阈值,需要进行调整。