Hi Everyone:I had implemented a watershed by numba, and now it has pass all the 
test_watershed check and got a exactly same result with skimage, support 
watershed-line, support connectivity, (pass test 0-12, but mine did not support 
compact yet)
It support nd, now only support uint8 image with uint16 marks. (because I think 
sometimes it is enough, It can process float image if it is needed)
And it is very smart and fast. less than 100 lines, and faster than skimage 
one. a 3d image which skimage run more than 10 minutes ( and I cannot wait any 
longer, so kill it), but my watershed just need 28 s.
The code are attached. 
BestYXDragon
import numpy as np
from numba import jit
from scipy.ndimage import label, generate_binary_structure
from scipy.misc import imread, imsave

def neighbors(shape, conn=1):
    dim = len(shape)
    block = generate_binary_structure(dim, conn)
    block[tuple([1]*dim)] = 0
    idx = np.where(block>0)
    idx = np.array(idx, dtype=np.uint8).T
    idx = np.array(idx-[1]*dim)
    acc = np.cumprod((1,)+shape[::-1][:-1])
    return np.dot(idx, acc[::-1])

@jit
def step(img, msk, line, pts, s, level, up, nbs):
    cur = 0
    while cur<s:
        p = pts[cur]
        if msk[p] == 0xfffe or up and img[p]>level or not up and img[p]<level:
            cur += 1
            continue
        for dp in nbs:
            cp = p+dp
            if msk[cp]==0:
                msk[cp] = msk[p]
                if s == len(pts):
                    s, cur = clear(pts, s, cur)
                pts[s] = cp
                s+=1
                
            elif msk[cp] == msk[p]:
                continue
            elif msk[cp] == 0xffff:
                continue
            elif msk[cp] == 0xfffe:
                continue
                
            elif line : msk[cp] = 0xfffe
        pts[cur] = -1
        cur+=1
    return cur

@jit
def clear(pts, s, cur):
    ns = 0; nc=0;
    for c in range(s):
        if pts[c]!=-1:
            pts[ns] = pts[c]
            ns += 1
            if c<cur:nc += 1
    return ns, nc
        
@jit
def collect(img, mark, nbs, pts):
    bins = np.zeros(img.max()+1, dtype=np.uint32)
    cur = 0
    for p in range(len(mark)):
        bins[img[p]] += 1
        if mark[p]==0xffff: continue # edge
        if mark[p]==0: continue      # zero
        for dp in nbs:
            if mark[p+dp]!=mark[p]:
                pts[cur] = p
                cur += 1
                break
    return cur, bins

@jit
def erose(mark):
    for i in range(len(mark)):
        if mark[i]>0xfff0:mark[i]=0

def buffer(img, dtype):
    buf = np.zeros(tuple(np.array(img.shape)+2), dtype=dtype)
    buf[tuple([slice(1,-1)]*buf.ndim)] = img
    return buf

def watershed(img, mark, conn=1, line=False, up=True):
    maxv = img.max(); minv = img.min();
    if img.dtype != np.uint8:
        img = ((img-minv)*(255/(maxv-minv))).astype(np.uint8)
    img = buffer(img, np.uint8)
    mark = buffer(mark, np.uint16)
    ndim = img.ndim
    for n in range(ndim):
        idx = [slice(None) if i!=n else [0,-1] for i in range(ndim)]
        mark[tuple(idx)] = 0xffff
    
    nbs = neighbors(img.shape, conn)
    img = img.ravel()
    mark1d = mark.ravel()

    pts = np.zeros(img.size//3, dtype=np.int64)
    s, bins = collect(img, mark1d, nbs, pts)

    for level in range(len(bins))[::1 if up else -1]:
        if bins[level]==0:continue
        s, c = clear(pts, s, 0)
        s = step(img, mark1d, line, pts, s, level, up, nbs)
    if line:erose(mark1d)
    return mark[tuple([slice(1,-1)]*ndim)]

#============================= test =============================
from skimage.morphology.watershed import watershed as skwatershed
def test_watershed01():
    "watershed 1"
    data = np.array([[0, 0, 0, 0, 0, 0, 0],
                    [0, 0, 0, 0, 0, 0, 0],
                    [0, 0, 0, 0, 0, 0, 0],
                    [0, 1, 1, 1, 1, 1, 0],
                    [0, 1, 0, 0, 0, 1, 0],
                    [0, 1, 0, 0, 0, 1, 0],
                    [0, 1, 0, 0, 0, 1, 0],
                    [0, 1, 1, 1, 1, 1, 0],
                    [0, 0, 0, 0, 0, 0, 0],
                    [0, 0, 0, 0, 0, 0, 0]], np.uint8)
    markers = np.array([[ 2, 0, 0, 0, 0, 0, 0],
                        [ 0, 0, 0, 0, 0, 0, 0],
                        [ 0, 0, 0, 0, 0, 0, 0],
                        [ 0, 0, 0, 0, 0, 0, 0],
                        [ 0, 0, 0, 0, 0, 0, 0],
                        [ 0, 0, 0, 1, 0, 0, 0],
                        [ 0, 0, 0, 0, 0, 0, 0],
                        [ 0, 0, 0, 0, 0, 0, 0],
                        [ 0, 0, 0, 0, 0, 0, 0],
                        [ 0, 0, 0, 0, 0, 0, 0]], np.uint16)
    out1 = watershed(data, markers)
    out2 = skwatershed(data, markers)
    print(np.sum(out1-out2!=0))

def test_watershed02():
    "watershed 2"
    data = np.array([[0, 0, 0, 0, 0, 0, 0],
                     [0, 0, 0, 0, 0, 0, 0],
                     [0, 0, 0, 0, 0, 0, 0],
                     [0, 0, 0, 0, 0, 0, 0],
                     [0, 1, 1, 1, 1, 1, 0],
                     [0, 1, 0, 0, 0, 1, 0],
                     [0, 1, 0, 0, 0, 1, 0],
                     [0, 1, 0, 0, 0, 1, 0],
                     [0, 1, 1, 1, 1, 1, 0],
                     [0, 0, 0, 0, 0, 0, 0],
                     [0, 0, 0, 0, 0, 0, 0]], np.uint8)
    markers = np.array([[2, 0, 0, 0, 0, 0, 0],
                        [0, 0, 0, 0, 0, 0, 0],
                        [0, 0, 0, 0, 0, 0, 0],
                        [0, 0, 0, 0, 0, 0, 0],
                        [0, 0, 0, 0, 0, 0, 0],
                        [0, 0, 0, 0, 0, 0, 0],
                        [0, 0, 0, 1, 0, 0, 0],
                        [0, 0, 0, 0, 0, 0, 0],
                        [0, 0, 0, 0, 0, 0, 0],
                        [0, 0, 0, 0, 0, 0, 0],
                        [0, 0, 0, 0, 0, 0, 0]], np.uint16)
    out1 = watershed(data, markers, 2)
    out2 = skwatershed(data, markers, 2)
    print(np.sum(out1-out2!=0))

def test_watershed03():
    "watershed 3"
    data = np.array([[0, 0, 0, 0, 0, 0, 0],
                     [0, 1, 1, 1, 1, 1, 0],
                     [0, 1, 0, 1, 0, 1, 0],
                     [0, 1, 0, 1, 0, 1, 0],
                     [0, 1, 0, 1, 0, 1, 0],
                     [0, 1, 1, 1, 1, 1, 0],
                     [0, 0, 0, 0, 0, 0, 0],
                     [0, 0, 0, 0, 0, 0, 0],
                     [0, 0, 0, 0, 0, 0, 0],
                     [0, 0, 0, 0, 0, 0, 0]], np.uint8)
    markers = np.array([[0, 0, 0, 0, 0, 0, 0],
                        [0, 0, 0, 0, 0, 0, 0],
                        [0, 0, 0, 0, 0, 0, 0],
                        [0, 0, 2, 0, 3, 0, 0],
                        [0, 0, 0, 0, 0, 0, 0],
                        [0, 0, 0, 0, 0, 0, 0],
                        [0, 0, 0, 0, 0, 0, 0],
                        [0, 0, 0, 0, 0, 0, 0],
                        [0, 0, 0, 0, 0, 0, 0],
                        [0, 0, 0, 0, 0, 0, 1]], np.uint16)
    out1 = watershed(data, markers)
    out2 = skwatershed(data, markers)
    print(np.sum(out1-out2!=0))

def test_watershed04():
    "watershed 4"
    data = np.array([[0, 0, 0, 0, 0, 0, 0],
                   [0, 1, 1, 1, 1, 1, 0],
                   [0, 1, 0, 1, 0, 1, 0],
                   [0, 1, 0, 1, 0, 1, 0],
                   [0, 1, 0, 1, 0, 1, 0],
                   [0, 1, 1, 1, 1, 1, 0],
                   [0, 0, 0, 0, 0, 0, 0],
                   [0, 0, 0, 0, 0, 0, 0],
                   [0, 0, 0, 0, 0, 0, 0],
                   [0, 0, 0, 0, 0, 0, 0]], np.uint8)
    markers = np.array([[0, 0, 0, 0, 0, 0, 0],
                        [0, 0, 0, 0, 0, 0, 0],
                        [0, 0, 0, 0, 0, 0, 0],
                        [0, 0, 2, 0, 3, 0, 0],
                        [0, 0, 0, 0, 0, 0, 0],
                        [0, 0, 0, 0, 0, 0, 0],
                        [0, 0, 0, 0, 0, 0, 0],
                        [0, 0, 0, 0, 0, 0, 0],
                        [0, 0, 0, 0, 0, 0, 0],
                        [0, 0, 0, 0, 0, 0, 1]], np.uint8)
    out1 = watershed(data, markers, 2)
    out2 = skwatershed(data, markers, 2)
    print(np.sum(out1-out2!=0))

def test_watershed05():
    "watershed 4"
    data = np.array([[0, 0, 0, 0, 0, 0, 0],
                   [0, 1, 1, 1, 1, 1, 0],
                   [0, 1, 0, 1, 0, 1, 0],
                   [0, 1, 0, 1, 0, 1, 0],
                   [0, 1, 0, 1, 0, 1, 0],
                   [0, 1, 1, 1, 1, 1, 0],
                   [0, 0, 0, 0, 0, 0, 0],
                   [0, 0, 0, 0, 0, 0, 0],
                   [0, 0, 0, 0, 0, 0, 0],
                   [0, 0, 0, 0, 0, 0, 0]], np.uint8)
    markers = np.array([[0, 0, 0, 0, 0, 0, 0],
                        [0, 0, 0, 0, 0, 0, 0],
                        [0, 0, 0, 0, 0, 0, 0],
                        [0, 0, 3, 0, 2, 0, 0],
                        [0, 0, 0, 0, 0, 0, 0],
                        [0, 0, 0, 0, 0, 0, 0],
                        [0, 0, 0, 0, 0, 0, 0],
                        [0, 0, 0, 0, 0, 0, 0],
                        [0, 0, 0, 0, 0, 0, 0],
                        [0, 0, 0, 0, 0, 0, 1]], np.uint8)
    out1 = watershed(data, markers, 2)
    out2 = skwatershed(data, markers, 2)
    print(np.sum(out1-out2!=0))
        
def test_watershed06():
    "watershed 6"
    data = np.array([[0, 1, 0, 0, 0, 1, 0],
                     [0, 1, 0, 0, 0, 1, 0],
                     [0, 1, 0, 0, 0, 1, 0],
                     [0, 1, 1, 1, 1, 1, 0],
                     [0, 0, 0, 0, 0, 0, 0],
                     [0, 0, 0, 0, 0, 0, 0],
                     [0, 0, 0, 0, 0, 0, 0],
                     [0, 0, 0, 0, 0, 0, 0],
                     [0, 0, 0, 0, 0, 0, 0]], np.uint8)
    markers = np.array([[0, 0, 0, 0, 0, 0, 0],
                        [0, 0, 0, 1, 0, 0, 0],
                        [0, 0, 0, 0, 0, 0, 0],
                        [0, 0, 0, 0, 0, 0, 0],
                        [0, 0, 0, 0, 0, 0, 0],
                        [0, 0, 0, 0, 0, 0, 0],
                        [0, 0, 0, 0, 0, 0, 0],
                        [0, 0, 0, 0, 0, 0, 0],
                        [2, 0, 0, 0, 0, 0, 0]], np.uint16)
    out1 = watershed(data, markers, 2)
    out2 = skwatershed(data, markers, 2)
    print(np.sum(out1-out2!=0))

def test_watershed07():
    "A regression test of a competitive case that failed"
    data = np.array([[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 
255, 255, 255, 255, 255],
                     [255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 
255, 255, 255, 255, 255],
                     [255, 255, 255, 255, 255, 204, 204, 204, 204, 204, 204, 
255, 255, 255, 255, 255],
                     [255, 255, 255, 204, 204, 183, 153, 153, 153, 153, 183, 
204, 204, 255, 255, 255],
                     [255, 255, 204, 183, 153, 141, 111, 103, 103, 111, 141, 
153, 183, 204, 255, 255],
                     [255, 255, 204, 153, 111,  94,  72,  52,  52,  72,  94, 
111, 153, 204, 255, 255],
                     [255, 255, 204, 153, 111,  72,  39,   1,   1,  39,  72, 
111, 153, 204, 255, 255],
                     [255, 255, 204, 183, 141, 111,  72,  39,  39,  72, 111, 
141, 183, 204, 255, 255],
                     [255, 255, 255, 204, 183, 141, 111,  72,  72, 111, 141, 
183, 204, 255, 255, 255],
                     [255, 255, 255, 255, 204, 183, 141,  94,  94, 141, 183, 
204, 255, 255, 255, 255],
                     [255, 255, 255, 255, 255, 204, 153, 103, 103, 153, 204, 
255, 255, 255, 255, 255],
                     [255, 255, 255, 255, 204, 183, 141,  94,  94, 141, 183, 
204, 255, 255, 255, 255],
                     [255, 255, 255, 204, 183, 141, 111,  72,  72, 111, 141, 
183, 204, 255, 255, 255],
                     [255, 255, 204, 183, 141, 111,  72,  39,  39,  72, 111, 
141, 183, 204, 255, 255],
                     [255, 255, 204, 153, 111,  72,  39,   1,   1,  39,  72, 
111, 153, 204, 255, 255],
                     [255, 255, 204, 153, 111,  94,  72,  52,  52,  72,  94, 
111, 153, 204, 255, 255],
                     [255, 255, 204, 183, 153, 141, 111, 103, 103, 111, 141, 
153, 183, 204, 255, 255],
                     [255, 255, 255, 204, 204, 183, 153, 153, 153, 153, 183, 
204, 204, 255, 255, 255],
                     [255, 255, 255, 255, 255, 204, 204, 204, 204, 204, 204, 
255, 255, 255, 255, 255],
                     [255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 
255, 255, 255, 255, 255],
                     [255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 
255, 255, 255, 255, 255]], dtype=np.uint8)
    mask = (data != 255)
    markers = np.zeros(data.shape, np.uint16)
    markers[6, 7] = 1
    markers[14, 7] = 2
    out1 = watershed(data, markers, 2)
    out2 = skwatershed(data, markers, 2)
    print(np.sum(out1-out2!=0))

def test_watershed08():
    "The border pixels + an edge are all the same value"
    data = np.array([[255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 
255, 255, 255, 255, 255],
                     [255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 
255, 255, 255, 255, 255],
                     [255, 255, 255, 255, 255, 204, 204, 204, 204, 204, 204, 
255, 255, 255, 255, 255],
                     [255, 255, 255, 204, 204, 183, 153, 153, 153, 153, 183, 
204, 204, 255, 255, 255],
                     [255, 255, 204, 183, 153, 141, 111, 103, 103, 111, 141, 
153, 183, 204, 255, 255],
                     [255, 255, 204, 153, 111,  94,  72,  52,  52,  72,  94, 
111, 153, 204, 255, 255],
                     [255, 255, 204, 153, 111,  72,  39,   1,   1,  39,  72, 
111, 153, 204, 255, 255],
                     [255, 255, 204, 183, 141, 111,  72,  39,  39,  72, 111, 
141, 183, 204, 255, 255],
                     [255, 255, 255, 204, 183, 141, 111,  72,  72, 111, 141, 
183, 204, 255, 255, 255],
                     [255, 255, 255, 255, 204, 183, 141,  94,  94, 141, 183, 
204, 255, 255, 255, 255],
                     [255, 255, 255, 255, 255, 204, 153, 141, 141, 153, 204, 
255, 255, 255, 255, 255],
                     [255, 255, 255, 255, 204, 183, 141,  94,  94, 141, 183, 
204, 255, 255, 255, 255],
                     [255, 255, 255, 204, 183, 141, 111,  72,  72, 111, 141, 
183, 204, 255, 255, 255],
                     [255, 255, 204, 183, 141, 111,  72,  39,  39,  72, 111, 
141, 183, 204, 255, 255],
                     [255, 255, 204, 153, 111,  72,  39,   1,   1,  39,  72, 
111, 153, 204, 255, 255],
                     [255, 255, 204, 153, 111,  94,  72,  52,  52,  72,  94, 
111, 153, 204, 255, 255],
                     [255, 255, 204, 183, 153, 141, 111, 103, 103, 111, 141, 
153, 183, 204, 255, 255],
                     [255, 255, 255, 204, 204, 183, 153, 153, 153, 153, 183, 
204, 204, 255, 255, 255],
                     [255, 255, 255, 255, 255, 204, 204, 204, 204, 204, 204, 
255, 255, 255, 255, 255],
                     [255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 
255, 255, 255, 255, 255],
                     [255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 
255, 255, 255, 255, 255]])
    mask = (data != 255)
    markers = np.zeros(data.shape, int)
    markers[6, 7] = 1
    markers[14, 7] = 2
    out1 = watershed(data, markers, 2)
    out2 = skwatershed(data, markers, 2)
    print(np.sum(out1-out2!=0))
        
def test_watershed09():
    '''this is a float test'''
    pass


def test_watershed10():
    "watershed 10"
    data = np.array([[1, 1, 1, 1],
                     [1, 1, 1, 1],
                     [1, 1, 1, 1],
                     [1, 1, 1, 1]], np.uint8)
    markers = np.array([[1, 0, 0, 2],
                        [0, 0, 0, 0],
                        [0, 0, 0, 0],
                        [3, 0, 0, 4]], np.int8)
    out1 = watershed(data, markers, 2)
    out2 = skwatershed(data, markers, 2)
    print(np.sum(out1-out2!=0))

def test_watershed11():
    '''Make sure that all points on this plateau are assigned to closest seed'''
    data = np.zeros((21, 21), dtype=np.uint8)
    markers = np.zeros((21, 21), int)
    markers[5, 5] = 1
    markers[5, 10] = 2
    markers[10, 5] = 3
    markers[10, 10] = 4

    structure = np.array([[False, True, False],
                          [True, True, True],
                          [False, True, False]])
    out1 = watershed(data, markers)
    out2 = skwatershed(data, markers, structure)
    print(np.sum(out1-out2!=0))
    
        
def test_watershed12():
    "The watershed line"
    data = np.array([[203, 255, 203, 153, 153, 153, 153, 153, 153, 153, 153, 
153, 153, 153, 153, 153],
                     [203, 255, 203, 153, 153, 153, 102, 102, 102, 102, 102, 
102, 153, 153, 153, 153],
                     [203, 255, 203, 203, 153, 153, 102, 102,  77,   0, 102, 
102, 153, 153, 203, 203],
                     [203, 255, 255, 203, 153, 153, 153, 102, 102, 102, 102, 
153, 153, 203, 203, 255],
                     [203, 203, 255, 203, 203, 203, 153, 153, 153, 153, 153, 
153, 203, 203, 255, 255],
                     [153, 203, 255, 255, 255, 203, 203, 203, 203, 203, 203, 
203, 203, 255, 255, 203],
                     [153, 203, 203, 203, 255, 255, 255, 255, 255, 255, 255, 
255, 255, 255, 203, 203],
                     [153, 153, 153, 203, 203, 203, 203, 203, 255, 203, 203, 
203, 203, 203, 203, 153],
                     [102, 102, 153, 153, 153, 153, 203, 203, 255, 203, 203, 
255, 203, 153, 153, 153],
                     [102, 102, 102, 102, 102, 153, 203, 255, 255, 203, 203, 
203, 203, 153, 102, 153],
                     [102,  51,  51, 102, 102, 153, 203, 255, 203, 203, 153, 
153, 153, 153, 102, 153],
                     [ 77,  51,  51, 102, 153, 153, 203, 255, 203, 203, 203, 
153, 102, 102, 102, 153],
                     [ 77,   0,  51, 102, 153, 203, 203, 255, 203, 255, 203, 
153, 102,  51, 102, 153],
                     [ 77,   0,  51, 102, 153, 203, 255, 255, 203, 203, 203, 
153, 102,   0, 102, 153],
                     [102,   0,  51, 102, 153, 203, 255, 203, 203, 153, 153, 
153, 102, 102, 102, 153],
                     [102, 102, 102, 102, 153, 203, 255, 203, 153, 153, 153, 
153, 153, 153, 153, 153]], dtype=np.uint8)
    markerbin = (data==0)
    from skimage.measure import label
    markers = label(markerbin).astype(np.uint16)
    out1 = watershed(data, markers, 1, True)
    out2 = skwatershed(data, markers, 1, watershed_line=True)
    print(np.sum(out1-out2!=0))

def test_compact_watershed():
    '''not support compact'''
    pass

if __name__ == '__main__':
    test_watershed01()
    test_watershed02()
    test_watershed03()
    test_watershed04()
    test_watershed05()
    test_watershed06()
    test_watershed07()
    test_watershed08()
    test_watershed09() 
    test_watershed10()
    test_watershed11()
    test_watershed12()
    
_______________________________________________
scikit-image mailing list
scikit-image@python.org
https://mail.python.org/mailman/listinfo/scikit-image

Reply via email to