504 lines
14 KiB
C
Executable File
504 lines
14 KiB
C
Executable File
// Copyright (c) 2005-2008 ASCLEPIOS Project, INRIA Sophia-Antipolis (France)
|
|
// All rights reserved.
|
|
//
|
|
// This file is part of the ImageIO Library, and as been adapted for
|
|
// CGAL (www.cgal.org).
|
|
// You can redistribute it and/or modify it under the terms of the
|
|
// GNU Lesser General Public License as published by the Free Software Foundation;
|
|
// either version 3 of the License, or (at your option) any later version.
|
|
//
|
|
// Licensees holding a valid commercial license may use this file in
|
|
// accordance with the commercial license agreement provided with the software.
|
|
//
|
|
// These files are provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
|
|
// WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
|
|
//
|
|
// $URL$
|
|
// $Id$
|
|
// SPDX-License-Identifier: LGPL-3.0+
|
|
//
|
|
//
|
|
// Author(s) : ASCLEPIOS Project (INRIA Sophia-Antipolis), Laurent Rineau
|
|
|
|
#ifdef CGAL_HEADER_ONLY
|
|
#define CGAL_INLINE_FUNCTION inline
|
|
#else
|
|
#define CGAL_INLINE_FUNCTION
|
|
#endif
|
|
|
|
#ifdef _MSC_VER
|
|
#pragma warning ( disable : 4068 4786 4081 )
|
|
#endif
|
|
|
|
#ifdef MINC_FILES
|
|
|
|
#include <math.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
/** Magic header for MINC (MNI NetCDF) file format */
|
|
#ifdef MINC_FILES
|
|
# define MINC_MAGIC "CDF"
|
|
#endif
|
|
|
|
|
|
CGAL_INLINE_FUNCTION
|
|
int readMincHeader(_image *im, const char* filename,
|
|
double *startx, double *starty, double *startz,
|
|
double *stepx, double *stepy, double *stepz,
|
|
double *Xcosines, double *Ycosines, double *Zcosines) {
|
|
int fin, varid, minc_icv, id, ndims, i, dim[256], length,
|
|
minfound = 0, maxfound = 0;
|
|
long start[3] = {0, 0, 0}, count[3];
|
|
unsigned int plane1, plane2, line, shift[3], ct[3];
|
|
nc_type type;
|
|
char sign_type[MI_MAX_ATTSTR_LEN], name[MAX_NC_NAME];
|
|
void *data;
|
|
double range[2], swap;
|
|
|
|
/* open minc file */
|
|
fin = miopen((char *) filename, NC_NOWRITE);
|
|
if(fin == MI_ERROR) return 0;
|
|
|
|
/* get number of dimensions and type */
|
|
id = ncvarid(fin, MIimage);
|
|
(void) ncvarinq(fin, id, NULL, &type, &ndims, dim, NULL);
|
|
if(ndims != 3) {
|
|
fprintf(stderr, "unsupported %i dimensional minc file\n", ndims);
|
|
return 0;
|
|
}
|
|
|
|
/* get sign */
|
|
if ((miattgetstr(fin, id, MIsigntype, MI_MAX_ATTSTR_LEN, sign_type)
|
|
== NULL) || ((strcmp(sign_type, MI_UNSIGNED)!=0) &&
|
|
(strcmp(sign_type, MI_SIGNED)!=0))) {
|
|
if (type == NC_BYTE)
|
|
(void) strcpy(sign_type, MI_UNSIGNED);
|
|
else
|
|
(void) strcpy(sign_type, MI_SIGNED);
|
|
}
|
|
im->sign = (!strcmp(sign_type, MI_UNSIGNED)) ? SGN_UNSIGNED : SGN_SIGNED;
|
|
|
|
switch(type) {
|
|
case NC_CHAR:
|
|
case NC_BYTE:
|
|
im->wdim = 1;
|
|
im->wordKind = WK_FIXED;
|
|
im->sign = SGN_UNSIGNED;
|
|
break;
|
|
case NC_SHORT:
|
|
im->wdim = 2;
|
|
im->wordKind = WK_FIXED;
|
|
break;
|
|
case NC_LONG:
|
|
im->wdim = 4;
|
|
im->wordKind = WK_FIXED;
|
|
break;
|
|
case NC_FLOAT:
|
|
im->wdim = 4;
|
|
im->wordKind = WK_FLOAT;
|
|
im->sign = SGN_UNKNOWN;
|
|
break;
|
|
case NC_DOUBLE:
|
|
im->wdim = 8;
|
|
im->wordKind = WK_FLOAT;
|
|
im->sign = SGN_UNKNOWN;
|
|
break;
|
|
default:
|
|
fprintf(stderr, "unsupported minc type\n");
|
|
return 0;
|
|
break;
|
|
}
|
|
|
|
|
|
/* get dimensions length and voxel size */
|
|
ncopts = 0;
|
|
for(i = 0; i < ndims; i++) {
|
|
(void) ncdiminq(fin, dim[i], name, &count[i]);
|
|
varid = ncvarid(fin, name);
|
|
if(!strcmp(name, MIxspace)) {
|
|
im->xdim = count[i];
|
|
if(miattget1(fin, varid, MIstep, NC_DOUBLE, stepx) == MI_ERROR)
|
|
*stepx = 1.0;
|
|
im->vx = fabs(*stepx);
|
|
if(miattget1(fin, varid, MIstart, NC_DOUBLE, startx) == MI_ERROR)
|
|
*startx = 0.0;
|
|
if(miattget(fin, varid, MIdirection_cosines, NC_DOUBLE, 3,
|
|
(void *) Xcosines, (int *) 0) == MI_ERROR ) {
|
|
Xcosines[0] = 0.0;
|
|
Xcosines[1] = 0.0;
|
|
Xcosines[2] = 0.0;
|
|
}
|
|
}
|
|
else if(!strcmp(name, MIyspace)) {
|
|
im->ydim = count[i];
|
|
if(miattget1(fin, varid, MIstep, NC_DOUBLE, stepy) == MI_ERROR)
|
|
*stepy = 1.0;
|
|
im->vy = fabs(*stepy);
|
|
if(miattget1(fin, varid, MIstart, NC_DOUBLE, starty) == MI_ERROR)
|
|
*starty = 0.0;
|
|
if(miattget(fin, varid, MIdirection_cosines, NC_DOUBLE, 3,
|
|
(void *) Ycosines, (int *) 0) == MI_ERROR ) {
|
|
Ycosines[0] = 0.0;
|
|
Ycosines[1] = 0.0;
|
|
Ycosines[2] = 0.0;
|
|
}
|
|
}
|
|
else if(!strcmp(name, MIzspace)) {
|
|
im->zdim = count[i];
|
|
if(miattget1(fin, varid, MIstep, NC_DOUBLE, stepz) == MI_ERROR)
|
|
*stepz = 1.0;
|
|
im->vz = fabs(*stepz);
|
|
if(miattget1(fin, varid, MIstart, NC_DOUBLE, startz) == MI_ERROR)
|
|
*startz = 0.0;
|
|
if(miattget(fin, varid, MIdirection_cosines, NC_DOUBLE, 3,
|
|
(void *) Zcosines, (int *) 0) == MI_ERROR ) {
|
|
Zcosines[0] = 0.0;
|
|
Zcosines[1] = 0.0;
|
|
Zcosines[2] = 0.0;
|
|
}
|
|
} else {
|
|
fprintf(stderr, "unsupported dimension %s\n", name);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
if( miattget( fin, id, MIvalid_range, NC_DOUBLE, 2,
|
|
(void *) range, &length) == MI_ERROR || length != 2 ) {
|
|
if( miattget1( fin, id, MIvalid_min, NC_DOUBLE,
|
|
(void *) &range[0] ) != MI_ERROR )
|
|
minfound = 1;
|
|
if( miattget1( fin, id, MIvalid_max, NC_DOUBLE,
|
|
(void *) &range[1] ) != MI_ERROR )
|
|
maxfound = 1;
|
|
}
|
|
else {
|
|
if( range[0] > range[1] ) {
|
|
swap = range[0];
|
|
range[0] = range[1];
|
|
range[1] = swap;
|
|
}
|
|
minfound = 1;
|
|
maxfound = 1;
|
|
}
|
|
|
|
if(!minfound) {
|
|
switch(type) {
|
|
case NC_CHAR:
|
|
case NC_BYTE:
|
|
range[0] = 0;
|
|
break;
|
|
case NC_SHORT:
|
|
if(im->sign == SGN_SIGNED) range[0] = -32768.0;
|
|
else range[0] = 0;
|
|
break;
|
|
case NC_LONG:
|
|
if(im->sign == SGN_SIGNED) range[0] = -2147483648.0;
|
|
else range[0] = 0;
|
|
break;
|
|
default:
|
|
range[0] = 0.0;
|
|
break;
|
|
}
|
|
}
|
|
if(!maxfound) {
|
|
switch(type) {
|
|
case NC_CHAR:
|
|
case NC_BYTE:
|
|
range[1] = 255.0;
|
|
break;
|
|
case NC_SHORT:
|
|
if(im->sign == SGN_SIGNED) range[1] = 32767.0;
|
|
else range[1] = 65535.0;
|
|
break;
|
|
case NC_LONG:
|
|
if(im->sign == SGN_SIGNED) range[1] = 2147483647.0;
|
|
else range[1] = 4294967295.0;
|
|
break;
|
|
default:
|
|
range[1] = 1.0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
ncopts = NC_VERBOSE | NC_FATAL;
|
|
im->vdim = 1;
|
|
|
|
/* read data bytes */
|
|
im->data = ImageIO_alloc(im->xdim * im->ydim * im->zdim * im->vdim *
|
|
im->wdim);
|
|
|
|
minc_icv = miicv_create();
|
|
(void) miicv_setint( minc_icv, MI_ICV_TYPE, type );
|
|
(void) miicv_setstr( minc_icv, MI_ICV_SIGN, sign_type );
|
|
(void) miicv_setint( minc_icv, MI_ICV_DO_NORM, 1 );
|
|
(void) miicv_setint( minc_icv, MI_ICV_DO_FILLVALUE, 1 );
|
|
(void) miicv_setdbl( minc_icv, MI_ICV_VALID_MIN, range[0] );
|
|
(void) miicv_setdbl( minc_icv, MI_ICV_VALID_MAX, range[1] );
|
|
|
|
(void) miicv_attach( minc_icv, fin, id );
|
|
|
|
if(miicv_get(minc_icv, start, count, im->data) == MI_ERROR) {
|
|
fprintf(stderr, "error while reading file\n");
|
|
return 0;
|
|
}
|
|
(void) miicv_detach( minc_icv );
|
|
(void) miicv_free( minc_icv );
|
|
|
|
ImageIO_closeImage(im);
|
|
|
|
/* order data in ZYX */
|
|
(void) ncdiminq(fin, dim[0], name, NULL);
|
|
if(!strcmp(name, MIzspace)) {
|
|
(void) ncdiminq(fin, dim[1], name, NULL);
|
|
/* file is ZYX */
|
|
if(!strcmp(name, MIyspace)) {
|
|
miclose(fin);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
(void) ncdiminq(fin, dim[0], name, NULL);
|
|
/* file is ZXY */
|
|
if(!strcmp(name, MIzspace)) {
|
|
shift[0] = 0;
|
|
shift[1] = 2;
|
|
shift[2] = 1;
|
|
plane2 = im->xdim * im->ydim;
|
|
line = im->ydim;
|
|
}
|
|
/* file is Y first */
|
|
else if(!strcmp(name, MIyspace)) {
|
|
shift[0] = 1;
|
|
plane2 = im->xdim * im->zdim;
|
|
(void) ncdiminq(fin, dim[1], name, NULL);
|
|
/* file is YXZ */
|
|
if(!strcmp(name, MIxspace)) {
|
|
shift[1] = 2;
|
|
shift[2] = 0;
|
|
line = im->zdim;
|
|
}
|
|
/* file is YZX */
|
|
else {
|
|
shift[1] = 0;
|
|
shift[2] = 2;
|
|
line = im->xdim;
|
|
}
|
|
}
|
|
/* file is X first */
|
|
else {
|
|
shift[0] = 2;
|
|
plane2 = im->ydim * im->zdim;
|
|
(void) ncdiminq(fin, dim[1], name, NULL);
|
|
/* file is XYZ */
|
|
if(!strcmp(name, MIyspace)) {
|
|
shift[1] = 1;
|
|
shift[2] = 0;
|
|
line = im->zdim;
|
|
}
|
|
/* file is XZY */
|
|
else {
|
|
shift[1] = 0;
|
|
shift[2] = 1;
|
|
line = im->ydim;
|
|
}
|
|
}
|
|
|
|
data = ImageIO_alloc(im->xdim * im->ydim * im->zdim * im->vdim * im->wdim);
|
|
plane1 = im->xdim * im->ydim;
|
|
|
|
for(ct[0] = 0; ct[0] < im->zdim; ct[0]++) {
|
|
for(ct[1] = 0; ct[1] < im->ydim; ct[1]++) {
|
|
for(ct[2] = 0; ct[2] < im->xdim; ct[2]++) {
|
|
memcpy((unsigned char *) data +
|
|
(ct[0] * plane1 + ct[1] * im->xdim + ct[2]) * im->wdim,
|
|
(unsigned char *) im->data +
|
|
(ct[shift[0]] * plane2 + ct[shift[1]] * line + ct[shift[2]])
|
|
* im->wdim, im->wdim);
|
|
}
|
|
}
|
|
}
|
|
|
|
ImageIO_free(im->data);
|
|
im->data = data;
|
|
|
|
/* close file */
|
|
miclose(fin);
|
|
return 1;
|
|
}
|
|
|
|
|
|
|
|
CGAL_INLINE_FUNCTION
|
|
int writeMincFile( const _image* im, const char *filename,
|
|
const char *sourcename,
|
|
double startx, double starty, double startz,
|
|
double stepx, double stepy, double stepz,
|
|
const double *Xcosine, const double *Ycosine,
|
|
const double *Zcosine, const double *range ) {
|
|
int i, cdfid, minc_icv, dim_vars[3], dim_ids[3], img_var_id, min_id, max_id,
|
|
src_cdfid, src_img_var, varid, n_excluded, excluded_vars[10],
|
|
src_min_id, src_max_id, src_root_id, old_att_length, same_file = 0;
|
|
long org[3] = {0, 0, 0}, count[3] = { im->zdim, im->ydim, im->xdim };
|
|
char *dim_names[3] = { MIzspace, MIyspace, MIxspace }, *history,
|
|
*excluded_list[3] = { MIxspace, MIyspace, MIzspace }, *newname;
|
|
nc_type type, datatype;
|
|
double start[3] = { startz, starty, startx },
|
|
vx[3] = { stepz, stepy, stepx };
|
|
|
|
/* if filename is the same file that sourcename, it is needed to create
|
|
a temporary file for output */
|
|
newname = (char *) filename;
|
|
if(sourcename) {
|
|
struct stat out, org;
|
|
same_file = (stat(sourcename, &org) == 0) && (stat(filename, &out) == 0)
|
|
&& (org.st_ino == out.st_ino);
|
|
if(same_file) {
|
|
newname = (char *) malloc((strlen(filename) + 10) * sizeof(char));
|
|
for(i = strlen(filename) - 1; i > 0 && filename[i] != '/'; i--) ;
|
|
if(filename[i] == '/') {
|
|
strncpy(newname, filename, i + 1);
|
|
newname[i+1] = '\0';
|
|
strcat(newname, "#TMP#");
|
|
strcat(newname, filename + i + 1);
|
|
}
|
|
else
|
|
sprintf(newname, "#TMP#%s", filename);
|
|
}
|
|
}
|
|
|
|
/* open file */
|
|
cdfid = micreate( (char *) newname, NC_CLOBBER );
|
|
if( cdfid == MI_ERROR ) {
|
|
fprintf(stderr, "Error: opening MINC file \"%s\".\n", filename );
|
|
return -1;
|
|
}
|
|
|
|
/* set word type */
|
|
switch(im->wordKind) {
|
|
case WK_FIXED:
|
|
if(im->wdim == 1) type = NC_BYTE;
|
|
else if(im->wdim == 2) type = NC_SHORT;
|
|
else type = NC_LONG;
|
|
break;
|
|
case WK_FLOAT:
|
|
default:
|
|
if(im->wdim == 4) type = NC_FLOAT;
|
|
else type = NC_DOUBLE;
|
|
break;
|
|
}
|
|
|
|
/* create dimensions variables */
|
|
for(i = 0; i < 3; i++)
|
|
dim_vars[i] = ncdimdef( cdfid, dim_names[i], count[i] );
|
|
|
|
for(i = 0; i < 3; i++ ) {
|
|
dim_ids[i] = micreate_std_variable( cdfid, dim_names[i], NC_DOUBLE,
|
|
0, NULL);
|
|
if( dim_ids[i] < 0 ) return -1;
|
|
(void) miattputdbl( cdfid, dim_ids[i], MIstep, vx[i]);
|
|
(void) miattputdbl( cdfid, dim_ids[i], MIstart, start[i]);
|
|
}
|
|
if(Zcosine[0] != 0.0 || Zcosine[1] != 0.0 || Zcosine[2] != 0.0)
|
|
(void) ncattput(cdfid, dim_ids[0], MIdirection_cosines, NC_DOUBLE, 3,
|
|
Zcosine);
|
|
if(Ycosine[0] != 0.0 || Ycosine[1] != 0.0 || Ycosine[2] != 0.0)
|
|
(void) ncattput(cdfid, dim_ids[1], MIdirection_cosines, NC_DOUBLE, 3,
|
|
Ycosine);
|
|
if(Xcosine[0] != 0.0 || Xcosine[1] != 0.0 || Xcosine[2] != 0.0)
|
|
(void) ncattput(cdfid, dim_ids[2], MIdirection_cosines, NC_DOUBLE, 3,
|
|
Xcosine);
|
|
|
|
/* create image variable */
|
|
img_var_id = micreate_std_variable( cdfid, MIimage, type, 3, dim_vars );
|
|
(void) miattputstr( cdfid, img_var_id, MIcomplete, MI_FALSE );
|
|
if(im->sign == SGN_SIGNED)
|
|
(void) miattputstr( cdfid, img_var_id, MIsigntype, MI_SIGNED );
|
|
else
|
|
(void) miattputstr( cdfid, img_var_id, MIsigntype, MI_UNSIGNED );
|
|
(void) ncattput(cdfid, img_var_id, MIvalid_range ,NC_DOUBLE, 2, range);
|
|
|
|
min_id = micreate_std_variable(cdfid, MIimagemin, NC_DOUBLE, 0, 0 );
|
|
max_id = micreate_std_variable(cdfid, MIimagemax, NC_DOUBLE, 0, 0 );
|
|
|
|
/* if the image comes from a minc file, duplicate all minc attributes */
|
|
if(sourcename) {
|
|
if( (src_cdfid = miopen((char *) sourcename, NC_NOWRITE)) == MI_ERROR ) {
|
|
fprintf(stderr, "Error opening %s\n", sourcename );
|
|
return -1;
|
|
}
|
|
|
|
n_excluded = 0;
|
|
for( i = 0; i < 3; i++ ) {
|
|
if( (varid = ncvarid(src_cdfid, excluded_list[i] )) != MI_ERROR )
|
|
excluded_vars[n_excluded++] = varid;
|
|
}
|
|
|
|
if( (src_img_var = ncvarid(src_cdfid, MIimage )) != MI_ERROR )
|
|
excluded_vars[n_excluded++] = src_img_var;
|
|
if( (src_max_id = ncvarid(src_cdfid, MIimagemax )) != MI_ERROR )
|
|
excluded_vars[n_excluded++] = src_max_id;
|
|
if( (src_min_id = ncvarid(src_cdfid, MIimagemin )) != MI_ERROR )
|
|
excluded_vars[n_excluded++] = src_min_id;
|
|
if( (src_root_id = ncvarid(src_cdfid, MIrootvariable )) != MI_ERROR )
|
|
excluded_vars[n_excluded++] = src_root_id;
|
|
|
|
(void) micopy_all_var_defs( src_cdfid, cdfid, n_excluded, excluded_vars );
|
|
|
|
if( src_img_var != MI_ERROR )
|
|
(void) micopy_all_atts( src_cdfid, src_img_var, cdfid, img_var_id );
|
|
if( src_root_id != MI_ERROR )
|
|
(void) micopy_all_atts( src_cdfid, src_root_id, cdfid,
|
|
ncvarid( cdfid, MIrootvariable) );
|
|
|
|
ncopts = 0;
|
|
if(ncattinq(cdfid, NC_GLOBAL, MIhistory, &datatype, &old_att_length)
|
|
== MI_ERROR || datatype != NC_CHAR )
|
|
old_att_length = 0;
|
|
|
|
history = (char *) malloc(sizeof(char) * old_att_length);
|
|
history[0] = (char) 0;
|
|
(void) miattgetstr( cdfid, NC_GLOBAL, MIhistory, old_att_length+1,
|
|
history );
|
|
ncopts = NC_VERBOSE | NC_FATAL;
|
|
(void) miattputstr( cdfid, NC_GLOBAL, MIhistory, history );
|
|
free(history);
|
|
|
|
(void) miclose( src_cdfid );
|
|
}
|
|
|
|
|
|
/* write data */
|
|
if(ncendef(cdfid) == MI_ERROR) return -1;
|
|
minc_icv = miicv_create();
|
|
(void) miicv_setint( minc_icv, MI_ICV_TYPE, type);
|
|
(void) miicv_setstr( minc_icv, MI_ICV_SIGN,
|
|
(im->sign == SGN_SIGNED) ? MI_SIGNED : MI_UNSIGNED );
|
|
(void) miicv_setint( minc_icv, MI_ICV_DO_NORM, 1 );
|
|
(void) miicv_setint( minc_icv, MI_ICV_USER_NORM, 1 );
|
|
(void) miicv_attach( minc_icv, cdfid, img_var_id );
|
|
|
|
if( miicv_put(minc_icv, org, count, im->data) == MI_ERROR )
|
|
return -1;
|
|
|
|
(void) miattputstr( cdfid, img_var_id, MIcomplete, MI_TRUE);
|
|
(void) miclose( cdfid );
|
|
(void) miicv_free( minc_icv );
|
|
|
|
if(same_file) {
|
|
unlink(filename);
|
|
link(newname, filename);
|
|
unlink(newname);
|
|
free(newname);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
#endif
|