GithubHelp home page GithubHelp logo

kld123509945 / porousmediaanalysis Goto Github PK

View Code? Open in Web Editor NEW

This project forked from vasilibaranov/porousmediaanalysis

0.0 1.0 0.0 18.07 MB

The program allows segmentation of void space in porous materials into pores and throats and computation of geodesic distances

License: MIT License

C++ 36.70% C 42.73% Makefile 0.68% Gnuplot 0.01% Assembly 0.04% Objective-C 4.46% Roff 1.24% HTML 0.05% Perl 0.01% Batchfile 0.03% Pascal 0.90% PHP 0.02% C# 10.70% Shell 0.02% Awk 0.01% Visual Basic 2.41%

porousmediaanalysis's Introduction

Welcome to the PorousMediaAnalysis project

The program allows morphological processing of three-dimensional binary images, comprised of solid (black) and void (non-black) pixels. It can

  • detect pores (large connected parts of void voxels (3D pixels)) and throats between these pores. This procedure is based on, but not equivalent to, the work of Dong and Blunt, 2009
  • compute shortest paths (geodesic distance) between the center void voxel and all the other void voxels in the sample

It is a console program, which doesn't require any preinstalled libraries, is multiplatform (Windows/nix) and supports in some steps OpenMP. On Windows, it shall compile at least with Visual Studio 2010-2015.

It was developed by me (Vasili Baranau) while doing research in the group of Prof. Dr. Ulrich Tallarek in Marburg, Germany, in 2014. It is distributed under the MIT license. This code (release v1.0) has a DOI: DOI.

If you use this program in a scientific project, please cite this paper: K. Hormann, V. Baranau, D. Hlushkou, A. Höltzel, and U. Tallarek; Topological analysis of non-granular, disordered porous media: determination of pore connectivity, pore coordination, and geometric tortuosity in physically reconstructed silica monoliths; New Journal of Chemistry, 40, 4187–4199 (2015); doi:10.1039/C5NJ02814K.

Overview of operation

Overview of operation

The image above represents detecting pores in the solid-void structure. From left to right: original geometry (white—solid); Euclidean Distance Transform; "containing ball radii" (in the sense of local thickness); separation of the void space into pores (pore boundaries are black). Similar to Fig. 3 in Hormann et al., 2015. For details, see the short algorithm description below or the full pore-throat detection description. The calculations were done in 3D, this is why the structure of pores may seem a little unnatural for this particular 2D slice.

Another thing that the program does is computation of shortest paths to all the void voxels from the central void voxel. An illustration of this operation can be found in Fig. 8 in the paper of Hormann et al., 2015.

Main links in the project

  1. This page, below : a short program description and links to important wiki pages
  2. Latest release
  3. Wiki
  4. Example
  5. Matlab scripts for reading the results

Below is a very short program description on a conceptual level and some links to important wiki pages. For a very detailed algorithm and program API description, please see the project wiki. Please read the wiki page Compilation prior to building the project, because compilation on nix systems may require some precaution due to a bug in Eclipse.

Table of contents:

  1. Short algorithm description
  2. Pore-throat detection
  3. Shortest paths computation
  4. Program execution
  5. Other

Short algorithm description

Pore-throat detection

To detect pores and throats, we do the following steps (inspired by the work of Dong and Blunt, 2009):

  1. Do Euclidean distance transform (EDT)
  2. Find containing spheres for each voxel
  3. Find starting pore voxels (pore seeds)
  4. Do pore propagation through containing ball radii starting at the pore seeds
  5. Do watershed propagation through containing ball radii, using the pore seeds as water sources

The image above in the overview of operation depicts stages 1, 2, and 5. This procedure is described in slightly more detail just below. For a very detailed description, please read this wiki page. I will use the words "pixel" and "voxel" (3D pixel) interchangeably throughout the readme and the wiki pages.

1. Euclidean distance transform

We do a standard Euclidean distance transform. In other words, we determine for each voxel a sphere that can be inscribed around this voxel and just touches the solid boundary (the maximum inscribed sphere).

2. Finding containing sphere radii

Each void voxel is thus covered by many maximum inscribed spheres. For each void voxel, we determine the radius of the largest sphere that coveres the voxel (the maximum containing sphere).

3. Finding pore seeds

After step 2, we can detect areas of local maxima in the map of maximum containing radii. I.e., some maximum containing radii form plateaus surrounded by voxels with lower maximum containing radii. Such plateaus can be formed either by one maximum containing sphere or by several maximum containing spheres with equal radii. We identify each plateau with a separate pore. For each plateau, we arbitrary select a center of one of the forming spheres as a pore center (pore seed).

4. Initial pore propagation

For each pore seed, we conduct pore propagation. Pore propagation is an iterative process that expands pore boundary at each iteration. At each iteration, we check all 26 neighbors of each pore boundary pixel. If a neighbor (i) is void, (ii) does not belong to the current pore yet, and (iii) its maximum inscribed radius is not larger than the maximum inscribed radius of a current boundary pixel, we mark the neighbor as belonging to the current pore and include it in the list of boundary pixels for the next iteration. Pixels that form the boundary at a current iteration are not included in the boundary for the next iteration. We stop iterations if there are no pixels in the boundary for the next step. After all pores finish propagating, each void pixel can belong to several pores. The areas of shared pixels may be quite large. Please note that the actual program execution determines pore seeds during the initial pore propagation (as described here). A separate step 3 (finding pore seeds) is added here for simplicity.

5. Watershed segmentation

Finally, watershed segmentation is used to define smaller pore boundaries. We use maximum containing radii as the depth of the “relief” where watershed happens. For the segmentation, we need to maintain “water level” and a set of boundary pixels for each pore. Initially, pore boundaries are formed only by pore seeds. Water level is initially set at the largest maximum containing radius among pore seeds (the deepest point in the relief) and then increased gradually. For each water level, we conduct pore propagation, which is an iterative process that expands boundaries of each pore. At each iteration, we process for each pore those boundary pixels that are at a current water level. For each boundary pixel, we check its 26 neighbors. If a neighbor is (i) void and (ii) its maximum containing radius is not larger than the maximum containing radius of a current boundary pixel, the boundary can propagate to it. If the neighbor does not belong to any pore yet, we mark the neighbor as belonging to the current pore and add it to the pore boundary (to be processed on the next iteration). If the neighbor is already marked as belonging to one or more pores, we specify that the neighbor belongs to the current pore as well, do not add it to the pore boundary, and remove it from the boundaries of other pores which he belongs to (whether it has to be processed on the current or future iterations). When there are no more boundary pixels on a current water level, the water level is increased by one and iterations start again. When there are no more boundary pixels to be processed at all, the segmentation stops. At this point all void voxels shall belong to one or more pores.

For a very detailed description of the steps above, please read this wiki page.

Shortest paths computation

The program can calculate shortest paths between a single starting void voxel and all other void voxel of a reconstruction. As a starting voxel, we use a void voxel closest to the geometric center of the sample. To calculate shortest paths, we considered each void voxel as a vertex in a graph. We consider each voxel connected only with its 26 nearest neighbors, excluding solid voxels. Euclidean distance between voxels is used as a weight of edges in this graph. It can thus have only values of 1, √2, and √3. Thus, we calculate shortest paths between the starting voxel and other void voxels inside this graph. We employ Dijkstra’s shortest paths algorithm.

For a very detailed description of this step, please read this wiki page. An illustration of this operation can be found in Fig. 8 in the paper of Hormann et al., 2015.

Program execution

Pore-throat detection

For a detailed description of console parameters, file formats, memory requirements, etc., please read this wiki page.

Shortest paths computation

For a detailed description of console parameters, file formats, memory requirements, etc., please read this wiki page.

Other

Architecture describes a high-level architecture of the project.

Compilation describes how to edit and build the PorousMediaAnalysis project. Please read it because compilation on nix systems may require some precaution due to a bug in Eclipse.

Known problems describes the list of known problems and workarounds. Currently it contains a description of handling tiff images (that encode geometry) with inverted gray scales.

porousmediaanalysis's People

Contributors

vasilibaranov avatar

Watchers

James Cloos avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.