From 3c895c00438392bf9b9b9b89da0d46e6f0d0650c Mon Sep 17 00:00:00 2001 From: Jingpeng Wu Date: Mon, 28 Mar 2022 11:28:19 -0400 Subject: [PATCH] Adjust seg (#75) * add unit test for preprocess; remove object contact is really working * inplace segmentation of watershed * seeded watershed * add robin map github repo as submodule since robin_map is not updated in conda-forge * make the priority queue more general to use * update the edit of priority queue * move priority queue to utils * move priority queue back to segmentation since the functions are built in for the edge type * seeded watershed compiles, but runs with core dump error * compilation in macbook pro * unit test for seeded watershed. the correctness of the result is not checked * add segmentation module with 2d seeded watershed * fixed the bug; the code still has a lot of assertion * remove a lot of assertions * test seeded watershed 3d --- .gitignore | 1 + .gitmodules | 4 +- .vscode/c_cpp_properties.json | 36 +++- cpp/CMakeLists.txt | 27 +-- cpp/include/reneu/segmentation/preprocess.hpp | 24 +-- .../reneu/segmentation/priority_queue.hpp | 23 +-- .../reneu/segmentation/region_graph.hpp | 28 ++- .../reneu/segmentation/region_graph_chunk.hpp | 2 +- .../reneu/segmentation/seeded_watershed.hpp | 182 ++++++++++++++++++ cpp/include/reneu/segmentation/watershed.hpp | 13 +- cpp/include/reneu/type_aliase.hpp | 2 +- cpp/include/reneu/utils/print.hpp | 17 ++ cpp/segmentation.cpp | 7 +- python/reneu/segmentation.py | 17 ++ setup.py | 1 + test.sh | 15 +- tests/segmentation/test_preprocess.py | 62 +++++- tests/segmentation/test_segmentation.py | 14 -- 18 files changed, 375 insertions(+), 100 deletions(-) create mode 100644 cpp/include/reneu/segmentation/seeded_watershed.hpp create mode 100644 cpp/include/reneu/utils/print.hpp create mode 100644 python/reneu/segmentation.py mode change 100644 => 100755 tests/segmentation/test_preprocess.py delete mode 100644 tests/segmentation/test_segmentation.py diff --git a/.gitignore b/.gitignore index b4e5e23..9b1c23d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +*.nfs* *.code-workspace *.DS_Store diff --git a/.gitmodules b/.gitmodules index 0a9fadd..3de331a 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,3 @@ [submodule "cpp/third-party/robin-map"] - path = cpp/third-party/robin-map - url = https://github.com/Tessil/robin-map.git + path = cpp/third-party/robin-map + url = https://github.com/Tessil/robin-map.git diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json index e7b0285..8513656 100644 --- a/.vscode/c_cpp_properties.json +++ b/.vscode/c_cpp_properties.json @@ -1,19 +1,39 @@ { "configurations": [ { - "name": "Mac", + "name": "centos", "includePath": [ - "~/code/reneu/cpp/include", - "~/opt/anaconda3/envs/reneu/include", - "~/opt/anaconda3/envs/reneu/include/python3.8", - "~/opt/anaconda3/envs/reneu/lib/python3.8/site-packages/numpy/core/include" + "${HOME}/code/reneu/cpp/include", + "${CONDA_PREFIX}/include/python3.8", + "${CONDA_PREFIX}/include", + "${CONDA_PREFIX}/lib/python3.8/site-packages/numpy/core/include", + "${workspaceFolder}/cpp/third-party/robin-map/include" ], "defines": [], "macFrameworkPath": [], - "compilerPath": "/usr/bin/clang", + "compilerPath": "/cm/shared/sw/nix/store/hmphldjnv7440cwpv29ph5d5bp3lbxz5-gcc-11.2.0/bin/gcc", "cStandard": "c17", - "cppStandard": "c++17", - "intelliSenseMode": "clang-x64", + "cppStandard": "c++20", + "intelliSenseMode": "linux-gcc-x64", + "configurationProvider": "ms-vscode.cmake-tools" + }, + { + "name": "MacOS", + "includePath": [ + "${workspaceFolder}/cpp/include", + "${CONDA_PREFIX}/include/python3.8", + "${CONDA_PREFIX}/include", + "${HOME}/opt/anaconda3/envs/reneu/include", + "${CONDA_PREFIX}/lib/python3.8/site-packages/numpy/core/include", + "${workspaceFolder}/cpp/third-party/robin-map/include" + ], + "defines": [], + "macFrameworkPath": [ + "/System/Library/Frameworks" + ], + "cStandard": "c17", + "cppStandard": "c++20", + "intelliSenseMode": "macos-clang-x64", "configurationProvider": "ms-vscode.cmake-tools" } ], diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index 21a095f..c33f4fd 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -2,6 +2,9 @@ cmake_minimum_required(VERSION 3.12.0) set(RENEU_VERSION 0.2.0) project(libreneu VERSION ${RENEU_VERSION} LANGUAGES CXX) +# add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/third-party/robin-map) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}/third-party/robin-map/include) + set(CMAKE_THREAD_LIBS_INIT "-lpthread") set(CMAKE_HAVE_THREADS_LIBRARY 1) set(CMAKE_USE_WIN32_THREADS_INIT 0) @@ -18,7 +21,6 @@ set(xtensor_DIR ${CONDA_PREFIX}/lib/cmake/xtensor) set(xtensor-python_DIR ${CONDA_PREFIX}/lib/cmake/xtensor-python) set(xtl_DIR ${CONDA_PREFIX}/lib/cmake/xtl) -add_subdirectory(third-party/robin-map) set(Boost_USE_STATIC_LIBS OFF) set(Boost_USE_MULTITHREADED OFF) @@ -35,14 +37,10 @@ if(Boost_NO_SYSTEM_PATH) endif(Boost_NO_SYSTEM_PATH) find_package(Boost REQUIRED serialization) -set(RENEU_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include) -include_directories(${NUMPY_INCLUDE_DIR} ${RENEU_INCLUDE_DIR} - ${CONDA_PREFIX}/include ${BOOST_INCLUDEDIR}) - set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules) -set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED True) -set(PYBIND11_CPP_STANDARD "-std=c++17") +set(PYBIND11_CPP_STANDARD "-std=c++20") set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_CURRENT_SOURCE_DIR}/../bin) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_CURRENT_SOURCE_DIR}/../bin) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_DEBUG ${CMAKE_CURRENT_SOURCE_DIR}/../python/reneu/lib) @@ -52,14 +50,19 @@ find_package(BLAS REQUIRED) find_package(PythonInterp 3 REQUIRED) find_package(PythonLibs 3 REQUIRED) find_package(Numpy REQUIRED) -#find_package(Python3 REQUIRED COMPONENTS Numpy) +# find_package(Python3 REQUIRED COMPONENTS Numpy) find_package(pybind11 REQUIRED) find_package(xtensor REQUIRED) find_package(xtensor-python REQUIRED) find_package(xtensor-blas REQUIRED) -# find_package(tsl REQUIRED) +#find_package(tsl_robin_map REQUIRED) +# find_package(tsl-robin-map REQUIRED) # find_package(TBB REQUIRED) +set(RENEU_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include) +include_directories(${NUMPY_INCLUDE_DIR} ${RENEU_INCLUDE_DIR} + ${CONDA_PREFIX}/include ${BOOST_INCLUDEDIR}) + pybind11_add_module(skeleton ${CMAKE_CURRENT_SOURCE_DIR}/skeleton.cpp) pybind11_add_module(segmentation ${CMAKE_CURRENT_SOURCE_DIR}/segmentation.cpp) pybind11_add_module(synapse ${CMAKE_CURRENT_SOURCE_DIR}/synapse.cpp) @@ -71,10 +74,8 @@ target_link_libraries(skeleton PRIVATE ${BLAS_LIBRARIES}) message("boost libarries: ${Boost_LIBRARIES}") target_include_directories(segmentation PUBLIC ${NUMPY_INCLUDE_DIR} ${RENEU_INCLUDE_DIR}) -target_link_libraries(segmentation PRIVATE ${Boost_LIBRARIES} tsl::robin_map) - -# target_link_libraries(segmentation ${Boost_LIBRARIES} ) -# target_link_libraries(segmentation "${Boost_LIBRARIES}/libboost_serialization.dylib" ) +#target_link_libraries(segmentation PRIVATE ${Boost_LIBRARIES} tsl::robin_map) +target_link_libraries(segmentation PRIVATE ${Boost_LIBRARIES}) # options option(BUILD_TESTS "build test suite" OFF) diff --git a/cpp/include/reneu/segmentation/preprocess.hpp b/cpp/include/reneu/segmentation/preprocess.hpp index 2450010..b4a537b 100644 --- a/cpp/include/reneu/segmentation/preprocess.hpp +++ b/cpp/include/reneu/segmentation/preprocess.hpp @@ -4,6 +4,7 @@ #include "reneu/type_aliase.hpp" #include +#include "reneu/utils/print.hpp" namespace reneu{ @@ -15,10 +16,10 @@ void remove_contact_1d(SEG1D seg1d){ if(seg1d(x)>0 && seg1d(x-1)>0 && seg1d(x)!=seg1d(x-1)){ seg1d(x) = 0; seg1d(x-1) = 0; - std::cout< void fill_background_with_affinity_guidance( - SEG& seg, const AFFS& affs, const AFF_EDGE& threshold){ + PySegmentation& seg, const PyAffinityMap& affs, + const aff_edge_t& threshold){ for(size_t z = 0; z, std::less>; +template class PriorityQueue{ private: - std::vector _edges; + std::vector _edges; public: PriorityQueue(): _edges({}) { } diff --git a/cpp/include/reneu/segmentation/region_graph.hpp b/cpp/include/reneu/segmentation/region_graph.hpp index d1ef7d7..a9bd08d 100644 --- a/cpp/include/reneu/segmentation/region_graph.hpp +++ b/cpp/include/reneu/segmentation/region_graph.hpp @@ -30,6 +30,30 @@ namespace reneu{ class RegionGraph; +struct EdgeInHeap{ + segid_t segid0; + segid_t segid1; + aff_edge_t aff; + size_t version; + + // constructor for emplace operation + EdgeInHeap( + const segid_t& segid0_, const segid_t& segid1_, + const aff_edge_t& aff_, const std::size_t& version_): + segid0(segid0_), segid1(segid1_), aff(aff_), version(version_){} + + bool operator<(const EdgeInHeap& other) const { + return aff < other.aff; + } +}; +// struct LessThanByAff{ +// bool operator()(const EdgeInQueue& lhs, const EdgeInQueue& rhs) const { +// return lhs.aff < rhs.aff; +// } +// }; +// using PriorityQueue = std::priority_queue, std::less>; + + class RegionEdge{ public: // we use the same type for both value for type stability in the average division. @@ -170,7 +194,7 @@ inline void _accumulate_edge(const segid_t& segid0, const segid_t& segid1, const auto _build_priority_queue (const aff_edge_t& threshold) const { - PriorityQueue heap; + PriorityQueue heap; for(const auto& [segid0, neighbors0] : _segid2neighbor){ for(const auto& [segid1, edgeIndex] : neighbors0){ // the connection is bidirectional, @@ -192,7 +216,7 @@ auto _build_priority_queue (const aff_edge_t& threshold) const { } auto _merge_segments(segid_t& segid0, segid_t& segid1, const RegionEdge& edge, - PriorityQueue& heap, + PriorityQueue& heap, const aff_edge_t& affinityThreshold){ // always merge object with less neighbors to more neighbors diff --git a/cpp/include/reneu/segmentation/region_graph_chunk.hpp b/cpp/include/reneu/segmentation/region_graph_chunk.hpp index 4be7122..050064f 100644 --- a/cpp/include/reneu/segmentation/region_graph_chunk.hpp +++ b/cpp/include/reneu/segmentation/region_graph_chunk.hpp @@ -65,7 +65,7 @@ inline auto _frozen_neighbor_flag(const segid_t& segid0, const aff_edge_t& thres auto _build_priority_queue (const aff_edge_t& threshold) const { - PriorityQueue heap; + PriorityQueue heap; for(const auto& [segid0, neighbors0] : _segid2neighbor){ for(const auto& [segid1, edgeIndex] : neighbors0){ // the connection is bidirectional, diff --git a/cpp/include/reneu/segmentation/seeded_watershed.hpp b/cpp/include/reneu/segmentation/seeded_watershed.hpp new file mode 100644 index 0000000..8fd770f --- /dev/null +++ b/cpp/include/reneu/segmentation/seeded_watershed.hpp @@ -0,0 +1,182 @@ +#pragma once + +#include +// #include "reneu/type_aliase.hpp" +#include "../type_aliase.hpp" +// #include "reneu/utils/priority_queue.hpp" + + +namespace reneu{ + + +struct AffEdge{ + aff_edge_t aff; + std::size_t channel; + std::ptrdiff_t z; + std::ptrdiff_t y; + std::ptrdiff_t x; + + // constructor for emplace operation + AffEdge(const aff_edge_t& aff_, const std::size_t& channel_, + const std::ptrdiff_t& z_, const std::ptrdiff_t& y_, + const std::ptrdiff_t& x_): aff(aff_), channel(channel_), + z(z_), y(y_), x(x_){} + + // comparitor for sorting in heap + // sort by decremental rather than default increamental + bool operator<(const AffEdge& other) const { + return aff < other.aff; + } +}; + +template +auto _build_priority_queue(const SEG& seg, const AFFS& affs, + const aff_edge_t& threshold){ + + std::priority_queue heap = {}; + // the first dimension of affs is channel + assert(affs.shape(1)==seg.shape(0)); + assert(affs.shape(2)==seg.shape(1)); + assert(affs.shape(3)==seg.shape(2)); + + // z direction + // the order in channels is xyz due to historical definition! + std::size_t channel = 2; + for(std::ptrdiff_t z=1; z0) || (sid1==0 && sid0>0)){ + // only one of them is background + const auto& aff = affs(channel, z,y,x); + if(aff > threshold) + heap.emplace(aff, channel, z, y, x); + } + } + } + } + + // y direction + channel = 1; + for(std::ptrdiff_t z=0; z0) || (sid1==0 && sid0>0)){ + // only one of them is background + const auto& aff = affs(channel, z,y,x); + if(aff > threshold) + heap.emplace(aff, channel, z, y, x); + } + } + } + } + + // x direction + channel = 0; + for(std::ptrdiff_t z=0; z0) || (sid1==0 && sid0>0)){ + // only one of them is background + const auto& aff = affs(channel, z,y,x); + if(aff > threshold) + heap.emplace(aff, channel, z, y, x); + } + } + } + } + return heap; +} + +template +void _update_priority_queue(HEAP& heap, const SEG& seg, + const AFFS& affs, const aff_edge_t& threshold, + const std::ptrdiff_t z, const std::ptrdiff_t y, + const std::ptrdiff_t x){ + + assert(seg(z,y,x)>0); + // search all the six surrounding directions + // we are sure that voxel in z,y,x is non-zero since + // this is the voxel we just expanded + if(z>0 && seg(z-1, y, x)==0 && affs(2, z, y, x)>threshold){ + heap.emplace(affs(2, z, y, x), 2, z, y, x); + } + if(y>0 && seg(z, y-1, x)==0 && affs(1, z, y, x)>threshold){ + heap.emplace(affs(1, z, y, x), 1, z, y, x); + } + if(x>0 && seg(z, y, x-1)==0 && affs(0, z, y, x)>threshold){ + heap.emplace(affs(0, z, y, x), 0, z, y, x); + } + + if(zthreshold){ + heap.emplace(affs(2, z+1, y, x), 2, z+1, y, x); + } + if(ythreshold){ + heap.emplace(affs(1, z, y+1, x), 1, z, y+1, x); + } + if(xthreshold){ + heap.emplace(affs(0, z, y, x+1), 0, z, y, x+1); + } + +} + +void seeded_watershed(PySegmentation& seg, const PyAffinityMap& affs, + const aff_edge_t& threshold){ + + // std::cout<< "start building priority queue..."<0); + seg(z,y,x) = seg(z-1, y, x); + _update_priority_queue(heap, seg, affs, threshold, z, y, x); + }else if(seg(z-1, y, x) ==0){ + assert(seg(z, y, x)>0); + seg(z-1, y, x) = seg(z, y, x); + _update_priority_queue(heap, seg, affs, threshold, z-1, y, x); + } + case 1: + if(seg(z, y, x) == 0){ + assert(seg(z, y-1, x)>0); + seg(z, y, x) = seg(z, y-1, x); + _update_priority_queue(heap, seg, affs, threshold, z, y, x); + }else if(seg(z, y-1, x)==0){ + assert(seg(z, y, x)>0); + seg(z, y-1, x) = seg(z, y, x); + _update_priority_queue(heap, seg, affs, threshold, z, y-1, x); + } + case 0: + if(seg(z, y, x) == 0){ + // if(seg(z,y,x-1)==0) + // std::cout<<"\nposition: "<0); + seg(z, y, x) = seg(z, y, x-1); + _update_priority_queue(heap, seg, affs, threshold, z, y, x); + }else if(seg(z, y, x-1) == 0){ + assert(seg(z, y, x)>0); + seg(z, y, x-1) = seg(z, y, x); + _update_priority_queue(heap, seg, affs, threshold, z, y, x-1); + } + } + } +} + +} // namespace of reneu \ No newline at end of file diff --git a/cpp/include/reneu/segmentation/watershed.hpp b/cpp/include/reneu/segmentation/watershed.hpp index f96370f..ca2de13 100644 --- a/cpp/include/reneu/segmentation/watershed.hpp +++ b/cpp/include/reneu/segmentation/watershed.hpp @@ -75,7 +75,8 @@ auto steepest_ascent(const AffinityMap &affs, aff_edge_t low, aff_edge_t high ){ return sag; } -auto divide_plateaus(SteepestAscentGraph& sag){ +template +auto divide_plateaus(S& sag){ std::ptrdiff_t sz = sag.shape(0); std::ptrdiff_t sy = sag.shape(1); std::ptrdiff_t sx = sag.shape(2); @@ -134,7 +135,8 @@ auto divide_plateaus(SteepestAscentGraph& sag){ } -auto find_basins(Segmentation& seg){ +template +auto find_basins(SEG& seg){ // seg is initially the steepest ascent graph // and will be transformed in-place to yield the segmentation into basins @@ -218,7 +220,8 @@ auto find_basins(Segmentation& seg){ return std::make_tuple(seg, counts); } -auto watershed(const AffinityMap& affs, const aff_edge_t& low, const aff_edge_t& high){ + +auto py_watershed(const PyAffinityMap& affs, const aff_edge_t& low, const aff_edge_t& high){ std::cout<< "start steepest ascent..." << std::endl; auto sag = steepest_ascent(affs, low, high); std::cout<< "start divide plateaus..." << std::endl; @@ -228,8 +231,4 @@ auto watershed(const AffinityMap& affs, const aff_edge_t& low, const aff_edge_t& return seg; } -auto py_watershed(const PyAffinityMap& affs, const aff_edge_t& low, const aff_edge_t& high){ - return watershed(affs, low, high); -} - } // namespace reneu \ No newline at end of file diff --git a/cpp/include/reneu/type_aliase.hpp b/cpp/include/reneu/type_aliase.hpp index be94a49..bd31573 100644 --- a/cpp/include/reneu/type_aliase.hpp +++ b/cpp/include/reneu/type_aliase.hpp @@ -1,6 +1,6 @@ # pragma once -#include +#include "xtensor/xtensor.hpp" #include #include diff --git a/cpp/include/reneu/utils/print.hpp b/cpp/include/reneu/utils/print.hpp new file mode 100644 index 0000000..fc24348 --- /dev/null +++ b/cpp/include/reneu/utils/print.hpp @@ -0,0 +1,17 @@ +#pragma once + +// #include "reneu/type_aliase.hpp" + + +namespace reneu::utils{ + +template +void print_array(const ARRAY& arr){ + std::cout<<"print out this array:"<(m, "Dendrogram") .def(py::init()) diff --git a/python/reneu/segmentation.py b/python/reneu/segmentation.py new file mode 100644 index 0000000..a2e971a --- /dev/null +++ b/python/reneu/segmentation.py @@ -0,0 +1,17 @@ +import numpy as np +from tqdm import tqdm + +from reneu.lib.segmentation import seeded_watershed + + +def seeded_watershed_2d(seg: np.ndarray, affs: np.ndarray, threshold: float): + for z in tqdm(range(seg.shape[0])): + seg2d = seg[z, :, :] + seg2d = np.expand_dims(seg2d, 0) + affs2d = affs[:, z, :, :] + affs2d = np.expand_dims(affs2d, 1) + + seeded_watershed(seg2d, affs2d, threshold) + seg[z, :, :] = seg2d + + diff --git a/setup.py b/setup.py index 1367ac8..c81b6b2 100644 --- a/setup.py +++ b/setup.py @@ -118,6 +118,7 @@ def build_extension(self, ext): "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", ], python_requires='>=3', zip_safe=False, diff --git a/test.sh b/test.sh index 8c95327..268a728 100755 --- a/test.sh +++ b/test.sh @@ -7,16 +7,17 @@ module load gcc/11.2.0 module load cmake -#rm -rf ./build -#mv python/reneu/lib/segmentation.so /tmp/ -rm python/reneu/lib/skeleton.so -rm python/reneu/lib/segmentation.so +rm -rf ./build +rm python/reneu/lib/skeleton*.so +rm python/reneu/lib/synapse*.so +rm python/reneu/lib/segmentation*.so #python setup.py develop python setup.py build --debug -#pytest tests/segmentation/test_disjoint_sets.py -s --pdb -#pytest tests/segmentation/test_dendrogram.py -s --pdb -#pytest tests/segmentation/test_region_graph.py -s --pdb +pytest tests/segmentation/test_preprocess.py +pytest tests/segmentation/test_disjoint_sets.py -s +pytest tests/segmentation/test_dendrogram.py -s +pytest tests/segmentation/test_region_graph.py -s #pytest tests/segmentation/test_region_graph_chunk.py -s --pdb diff --git a/tests/segmentation/test_preprocess.py b/tests/segmentation/test_preprocess.py old mode 100644 new mode 100755 index 0e2de36..3987400 --- a/tests/segmentation/test_preprocess.py +++ b/tests/segmentation/test_preprocess.py @@ -1,12 +1,64 @@ +#!/usr/bin/env python + from copy import deepcopy import numpy as np -from reneu.segmentation import remove_contact +from numpy.random import rand + +from reneu.lib.segmentation import seeded_watershed, remove_contact, fill_background_with_affinity_guidance +from reneu.segmentation import seeded_watershed_2d + + +def random_affinity_map(shape=(3,4,4,4)): + if isinstance(shape, int): + shape = (3, shape, shape, shape) + elif len(shape)==3: + shape = tuple(3, *shape) + else: + assert len(shape) == 4 + assert shape[0] == 3 + + affs = rand(*shape) + affs = affs.astype(np.float32) + return affs + +def random_segmentation(shape=(4,4,4), high=8): + if isinstance(shape, int): + shape = (shape, shape, shape) + else: + assert len(shape) == 3 + + seg = np.random.randint(0, high=high, size=shape, dtype=np.uint64) + return seg + +def test_seeded_watershed(shape=96): + affs = random_affinity_map(shape=shape) + seg = random_segmentation(shape=shape) + + seg2 = deepcopy(seg) + seeded_watershed_2d(seg2, affs, 0.5) + assert np.any(seg!=seg2) + + seg3 = deepcopy(seg) + seeded_watershed(seg3, affs, 0.5) + assert np.any(seg!=seg3) def test_remove_contact(): - seg1 = np.zeros((4,4,4), dtype=np.uint64) - seg1[:2, ...] = 1 - seg1[2:, ...] = 2 + seg1 = np.zeros((2,4,4), dtype=np.uint64) + seg1[..., :2] = 1 + seg1[..., 2:] = 2 seg2 = deepcopy(seg1) remove_contact(seg2) - assert np.any(seg1!=seg2) \ No newline at end of file + assert np.any(seg1!=seg2) + + +def test_fill_segmentation_with_affinity_guidance(): + affs = random_affinity_map() + seg = random_segmentation() + seg2 = deepcopy(seg) + fill_background_with_affinity_guidance(seg2, affs, 0.5) + assert np.any(seg!=seg2) + + +if __name__ == '__main__': + test_seeded_watershed() \ No newline at end of file diff --git a/tests/segmentation/test_segmentation.py b/tests/segmentation/test_segmentation.py deleted file mode 100644 index 40bdd72..0000000 --- a/tests/segmentation/test_segmentation.py +++ /dev/null @@ -1,14 +0,0 @@ -from reneu.lib.segmentation import fill_background_with_affinity_guidance - -import numpy as np -np.random.seed(0) - - -def test_fill_background_with_affinity_guidance(): - # seg = np.random.randint(2000, dtype=np.uint32, size=(64,64,64)) - seg = np.random.randint(2000, dtype=np.uint64, size=(64,64,64)) - seg[seg<500] = 0 - assert np.any(seg==0) - affs = np.random.rand(3,64,64,64).astype(np.float32) - fill_background_with_affinity_guidance(seg, affs) - assert np.alltrue(seg>0)