Skip to content

Commit

Permalink
integrate nii2mesh functions
Browse files Browse the repository at this point in the history
  • Loading branch information
neurolabusc committed Jan 17, 2022
1 parent 271a69b commit 587aa9c
Show file tree
Hide file tree
Showing 16 changed files with 2,883 additions and 106 deletions.
10 changes: 10 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,13 @@ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

The PolygoniseCube function comes from Cory Bloyd's public domain Marching Cubes Example Program described here http://paulbourke.net/geometry/polygonise/

The bwlabel.cpp file was written by Jesper Andersson, who has explicitly allowed this to be shared using the BSD 2-Clause license (above).

base64.cpp was written by Jouni Malinen and is distributed under the BSD license. For a performance evaluation, see https://github.com/gaspardpetit/base64

simplify.h was written by Sven Forstmann and distributed under the MIT license. It was ported from C++ to C by Chris Rorden. https://github.com/sp4cerat/Fast-Quadric-Mesh-Simplification

The software can be optionally compiled to use the radixsort files written by Cameron Hart (2014) using the zlib license. https://github.com/bitshifter/radixsort
19 changes: 18 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ niimath has a few features not provided by fslmaths:
- dogx <sPos> <sNeg> : as dog, zero-crossing for 2D sagittal slices
- dogy <sPos> <sNeg> : as dog, zero-crossing for 2D coronal slices
- dogz <sPos> <sNeg> : as dog, zero-crossing for 2D axial slices
- mesh : see separate section below
- `--compare` <ref> : report if images are identical, terminates without saving new image\n");
- filename.nii : mimic fslhd (can also export to a txt file: 'niimath T1.nii 2> T1.txt') report header and terminate without saving new image

Expand Down Expand Up @@ -156,9 +157,25 @@ Here are the same testson a desktop computer with twelve cores (24 threads, Ryze
| niimath rest -demean out (same output as above) | 2.6x (2.6x) | 3.0x (10.8x) |
| fslmaths rest -bptf 77 8.68 out : 887 (1019) | 2.6x (2.5x) | 23x (23.0x) |

## Converting voxelwise images to a triangulated mesh

niimath can convert NIfTI images to meshes, suitable for viewing in Surfice, blender, SUMA, FreeSurfer and other tools. The features are based on [nii2mesh](https://github.com/neurolabusc/nii2mesh) and the features are almost identical. However, the order of arguments is different to match the expectations of fslmaths/niimath. So the call `nii2mesh -r 1 bet.nii.gz r100.ply` becomes `niimath bet.nii.gz -mesh -r 1 r100.ply`. As described on the nii2mesh page, you can create independent meshes for each area in an atlas using the command:

```
niimath D99_atlas_v2.0_right.nii.gz -mesh -p 0 -s 10 -a D99_v2.0_labels_semicolon.txt ./gii/D99s10roi.gii
```
Both programs allow you to explicitly set the isolevel using the `-i` value, so `-i 128` we render a surface for voxels brighter than 128. One minor difference between the programs is that niimath allows you also request `dark`, `medium` and `bright` using the `-i d`, `-i m` and `-i b` commands respectively. These use Otsu's method, and typically identify pleasing values. Also, if the user does not specify an isolevel be aware that nii2mesh chooses the middle brightness (the midpoint between the darkest and brightest value) while niimath uses the medium Otsu threshold. The latter is more robust to outliers. Here are examples illustrating this usage:

```
niimath bet.nii.gz -mesh -i 128 Isolevel128.gii
niimath bet.nii.gz -mesh -i d darkIsolevel.gii
niimath bet.nii.gz -mesh -i m medIsolevel.gii
niimath bet.nii.gz -mesh -i b brightIsolevel.gii
```

## License

niimath is licensed under the 2-Clause BSD License. Except where noted, the code was written by Chris Rorden in 2020. The code in `tensor.c` was written by Daniel Glen (2004) from the US National Institutes of Health and is not copyrighted (though it is included here with the permission of the author). The FSL team graciously allowed the text strings (help, warning and error messages) to be copied verbatim. The Butterworth Filter Coefficients in `bw.c` are from [Exstrom Labs](http://www.exstrom.com/journal/sigproc/) and the authors provided permission for it to be included in this project under the [LGPL](https://www.gnu.org/licenses/lgpl-3.0.en.html), the file provides additional details. Taylor Hanayik from the FSL group provided pseudo-code for some functions where there is little available documentation.
niimath is licensed under the 2-Clause BSD License. Except where noted, the code was written by Chris Rorden in 2020-2022. The code in `tensor.c` was written by Daniel Glen (2004) from the US National Institutes of Health and is not copyrighted (though it is included here with the permission of the author). The FSL team graciously allowed the text strings (help, warning and error messages) to be copied verbatim. The Butterworth Filter Coefficients in `bw.c` are from [Exstrom Labs](http://www.exstrom.com/journal/sigproc/) and the authors provided permission for it to be included in this project under the [LGPL](https://www.gnu.org/licenses/lgpl-3.0.en.html), the file provides additional details. Taylor Hanayik from the FSL group provided pseudo-code for some functions where there is little available documentation. The PolygoniseCube function comes from Cory Bloyd's public domain [Marching Cubes example](http://paulbourke.net/geometry/polygonise/) program described here. The bwlabel.cpp file was written by Jesper Andersson, who has explicitly allowed this to be shared using the BSD 2-Clause license. The [high performance](https://github.com/gaspardpetit/base64) base64.cpp was written by Jouni Malinen and is distributed under the BSD license. The mesh simplification was written by [Sven Forstmann](https://github.com/sp4cerat/Fast-Quadric-Mesh-Simplification) and distributed under the MIT license. It was ported from C++ to C by Chris Rorden. The [radixsort.c](https://github.com/bitshifter/radixsort) was written by Cameron Hart (2014) using the zlib license.

## Links

Expand Down
2 changes: 1 addition & 1 deletion src/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,5 @@ ifeq "$(OMP)" "1"
endif

all:
$(CNAME) $(CFLAGS) -o niimath niimath.c bwlabel.c bw.c core.c tensor.c core32.c core64.c niftilib/nifti2_io.c znzlib/znzlib.c -I./niftilib -I./znzlib $(LFLAGS)
$(CNAME) $(CFLAGS) -o niimath niimath.c meshify.c quadric.c base64.c radixsort.c bwlabel.c bw.c core.c tensor.c core32.c core64.c niftilib/nifti2_io.c znzlib/znzlib.c -I./niftilib -I./znzlib $(LFLAGS)

162 changes: 162 additions & 0 deletions src/base64.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
/*
* Base64 encoding/decoding (RFC1341)
* Copyright (c) 2005-2011, Jouni Malinen <[email protected]>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/

//#include "includes.h"

//#include "os.h"
#include "base64.h"
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>

static const unsigned char base64_table[65] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

/**
* base64_encode - Base64 encode
* @src: Data to be encoded
* @len: Length of the data to be encoded
* @out_len: Pointer to output length variable, or %NULL if not used
* Returns: Allocated buffer of out_len bytes of encoded data,
* or %NULL on failure
*
* Caller is responsible for freeing the returned buffer. Returned buffer is
* nul terminated to make it easier to use as a C string. The nul terminator is
* not included in out_len.
*/
unsigned char * base64_encode(const unsigned char *src, size_t len,
size_t *out_len)
{
unsigned char *out, *pos;
const unsigned char *end, *in;
size_t olen;

olen = len * 4 / 3 + 4; /* 3-byte blocks to 4-byte */
#ifdef USE_EOLN
int line_len 0;
olen += olen / 72; /* line feeds */
#endif
olen++; /* nul termination */
if (olen < len)
return NULL; /* integer overflow */
out = (unsigned char *) malloc(olen); //os_
if (out == NULL)
return NULL;
end = src + len;
in = src;
pos = out;
while (end - in >= 3) {
*pos++ = base64_table[in[0] >> 2];
*pos++ = base64_table[((in[0] & 0x03) << 4) | (in[1] >> 4)];
*pos++ = base64_table[((in[1] & 0x0f) << 2) | (in[2] >> 6)];
*pos++ = base64_table[in[2] & 0x3f];
in += 3;
#ifdef USE_EOLN
line_len += 4;
if (line_len >= 72) {
*pos++ = '\n';
line_len = 0;
}
#endif
}

if (end - in) {
*pos++ = base64_table[in[0] >> 2];
if (end - in == 1) {
*pos++ = base64_table[(in[0] & 0x03) << 4];
*pos++ = '=';
} else {
*pos++ = base64_table[((in[0] & 0x03) << 4) |
(in[1] >> 4)];
*pos++ = base64_table[(in[1] & 0x0f) << 2];
}
*pos++ = '=';
#ifdef USE_EOLN
line_len += 4;
#endif
}
#ifdef USE_EOLN
if (line_len)
*pos++ = '\n';
#endif
*pos = '\0';
if (out_len)
*out_len = pos - out;
return out;
}

/**
* base64_decode - Base64 decode
* @src: Data to be decoded
* @len: Length of the data to be decoded
* @out_len: Pointer to output length variable
* Returns: Allocated buffer of out_len bytes of decoded data,
* or %NULL on failure
*
* Caller is responsible for freeing the returned buffer.
*/
unsigned char * base64_decode(const unsigned char *src, size_t len,
size_t *out_len)
{
unsigned char dtable[256], *out, *pos, block[4], tmp;
size_t i, count, olen;
int pad = 0;

memset(dtable, 0x80, 256); //os_
for (i = 0; i < sizeof(base64_table) - 1; i++)
dtable[base64_table[i]] = (unsigned char) i;
dtable['='] = 0;

count = 0;
for (i = 0; i < len; i++) {
if (dtable[src[i]] != 0x80)
count++;
}

if (count == 0 || count % 4)
return NULL;

olen = count / 4 * 3;
pos = out = (unsigned char *) malloc(olen); //os_
if (out == NULL)
return NULL;

count = 0;
for (i = 0; i < len; i++) {
tmp = dtable[src[i]];
if (tmp == 0x80)
continue;

if (src[i] == '=')
pad++;
block[count] = tmp;
count++;
if (count == 4) {
*pos++ = (block[0] << 2) | (block[1] >> 4);
*pos++ = (block[1] << 4) | (block[2] >> 2);
*pos++ = (block[2] << 6) | block[3];
count = 0;
if (pad) {
if (pad == 1)
pos--;
else if (pad == 2)
pos -= 2;
else {
/* Invalid padding */
free(out); //os_
return NULL;
}
break;
}
}
}

*out_len = pos - out;
return out;
}
17 changes: 17 additions & 0 deletions src/base64.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
* Base64 encoding/decoding (RFC1341)
* Copyright (c) 2005, Jouni Malinen <[email protected]>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
*/

#ifndef BASE64_H
#define BASE64_H

#include <stdio.h>

unsigned char * base64_encode(const unsigned char *src, size_t len,size_t *out_len);
unsigned char * base64_decode(const unsigned char *src, size_t len,size_t *out_len);

#endif /* BASE64_H */
Loading

0 comments on commit 587aa9c

Please sign in to comment.