From 69a1aa93b81415a082dc4b5cecaad3d0dc0a97a6 Mon Sep 17 00:00:00 2001 From: Paweł Redman Date: Tue, 16 Jul 2019 13:47:38 +0200 Subject: Basics of MAT exporting --- Makefile | 3 +- src/common.h | 9 +++ src/e2e.c | 1 + src/e2e.h | 2 - src/eli.h | 5 ++ src/export.c | 259 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/export.h | 1 + src/main.c | 11 +-- 8 files changed, 283 insertions(+), 8 deletions(-) create mode 100644 src/common.h create mode 100644 src/export.c create mode 100644 src/export.h diff --git a/Makefile b/Makefile index e98fe38..8db2a45 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ CC = gcc CFLAGS += -g -Wall -O3 CPPFLAGS += -MMD -LDFLAGS += -pthread -lm +LDFLAGS += -pthread -lm -lmatio PP_BOLD := $(shell tput bold) PP_RESET := $(shell tput sgr0) @@ -10,6 +10,7 @@ PP_LD := $(PP_BOLD)$(shell tput setf 2)LD$(PP_RESET) PP_RM := $(PP_BOLD)$(shell tput setf 4)RM$(PP_RESET) SRC := src/e2e.c \ + src/export.c \ src/main.c OBJ := $(SRC:src/%.c=obj/%.o) diff --git a/src/common.h b/src/common.h new file mode 100644 index 0000000..7f1e41c --- /dev/null +++ b/src/common.h @@ -0,0 +1,9 @@ +#include +#include +#include +#include +#include +#include "eli.h" + +#define HASH_FOR(i, head, field) for ((i) = (head); (i); (i) = (i)->field.next) +#define errorf(fmt, ...) (fprintf(stderr, fmt, ##__VA_ARGS__)) diff --git a/src/e2e.c b/src/e2e.c index f2728c1..5ac9f6c 100644 --- a/src/e2e.c +++ b/src/e2e.c @@ -1,3 +1,4 @@ +#include "common.h" #include #include #include diff --git a/src/e2e.h b/src/e2e.h index 960aa3e..65428ea 100644 --- a/src/e2e.h +++ b/src/e2e.h @@ -2,8 +2,6 @@ #include #include "eli.h" -#define errorf(fmt, ...) (fprintf(stderr, fmt, ##__VA_ARGS__)) - #define E2E_NONE 0xffffffff #define E2E_IMAGE_FUNDUS 0x02010201 diff --git a/src/eli.h b/src/eli.h index 8cd75a6..4a387f7 100644 --- a/src/eli.h +++ b/src/eli.h @@ -16,6 +16,9 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ +#ifndef _ELI_H +#define _ELI_H + #include // size_t #define eli_rebase(x, xm, y) \ @@ -82,3 +85,5 @@ eli_unlink_real((void**)(pphead), (entry), &((*(pphead))->member), &((entry)->me // Loop over a list #define eli_for(i, head, member) \ for ((i) = (head); (i); (i) = (i)->member.next) + +#endif // _ELI_H diff --git a/src/export.c b/src/export.c new file mode 100644 index 0000000..5a98f2d --- /dev/null +++ b/src/export.c @@ -0,0 +1,259 @@ +#include "common.h" +#include + +#include "e2e.h" +#include "export.h" + +static size_t dims_scalar = 1; + +#define COUNT(x) (sizeof(x) / sizeof((x)[0])) + +matvar_t *create_int(const int *value) +{ + return Mat_VarCreate(NULL, MAT_C_INT32, MAT_T_INT32, 1, &dims_scalar, + (int*)value, 0); +} + +matvar_t *create_struct(const char **fields, int nfields) +{ + return Mat_VarCreateStruct(NULL, 1, &dims_scalar, fields, nfields); +} + + +static int export_tomogram(const struct e2e_slice *slices, matvar_t **tomogram, + matvar_t **slice_ids) +{ + size_t i, dims[3], zstride; + int *ids; + const struct e2e_slice *slice; + float *image3d; + + dims[0] = slices->image->width; + dims[1] = slices->image->height; + dims[2] = HASH_COUNT(slices); + + ids = calloc(dims[2], sizeof(int)); + if (!ids) + return ENOMEM; + + i = 0; + HASH_FOR(slice, slices, hh) + ids[i++] = slice->id; + + *slice_ids = Mat_VarCreate(NULL, MAT_C_INT32, MAT_T_INT32, 1, dims + 2, + ids, 0); + free(ids); + if (!*slice_ids) + return ENOMEM; + + // FIXME: check overflow + zstride = dims[0] * dims[1]; + image3d = calloc(zstride * dims[2], sizeof(float)); + if (!image3d) + goto error_image3d; + + i = 0; + HASH_FOR(slice, slices, hh) + memcpy(image3d + i * zstride, slice->image->tomogram, + zstride * sizeof(float)); + + *tomogram = Mat_VarCreate(NULL, MAT_C_SINGLE, MAT_T_SINGLE, 3, dims, + image3d, 0); + free(image3d); + if (!*tomogram) + goto error_image3d; + + return 0; + +error_image3d: + Mat_VarFree(*slice_ids); + return ENOMEM; +} + +static int export_series(const struct e2e_series *series, matvar_t **out) +{ + int rv; + size_t i, dims; + const struct e2e_series *series1; + + dims = HASH_COUNT(series); + *out = Mat_VarCreate(NULL, MAT_C_CELL, MAT_T_CELL, 1, &dims, NULL, 0); + if (!*out) + return ENOMEM; + + i = 0; + HASH_FOR(series1, series, hh) { + const char *fields[] = { + "series_id", + "tomogram", + "tomogram_slice_ids", + "fundi", + }; + matvar_t *st, *id, *tomogram, *slice_ids; + + st = create_struct(fields, COUNT(fields)); + if (!st) { + rv = ENOMEM; + goto error; + } + + id = create_int(&series1->id); + if (!id) { + rv = ENOMEM; + goto error_id; + } + + Mat_VarSetStructFieldByName(st, "series_id", 0, id); + + if (HASH_COUNT(series1->slices)) { + rv = export_tomogram(series1->slices, &tomogram, &slice_ids); + if (rv) + goto error_tomogram; + + Mat_VarSetStructFieldByName(st, "tomogram", 0, tomogram); + Mat_VarSetStructFieldByName(st, "tomogram_slice_ids", 0, + slice_ids); + } + // TODO: export fundus images + + Mat_VarSetCell(*out, i++, st); + continue; + + error_tomogram: + Mat_VarFree(id); + error_id: + Mat_VarFree(st); + goto error; + } + + return 0; + +error: + Mat_VarFree(*out); + return rv; +} + +static int export_studies(const struct e2e_study *studies, matvar_t **out) +{ + int rv; + size_t i, dims; + const struct e2e_study *study; + + dims = HASH_COUNT(studies); + *out = Mat_VarCreate(NULL, MAT_C_CELL, MAT_T_CELL, 1, &dims, NULL, 0); + if (!*out) + return ENOMEM; + + i = 0; + HASH_FOR(study, studies, hh) { + const char *fields[] = {"study_id", "series"}; + matvar_t *st, *id, *series; + + st = create_struct(fields, COUNT(fields)); + if (!st) { + rv = ENOMEM; + goto error; + } + + id = create_int(&study->id); + if (!id) { + rv = ENOMEM; + goto error_id; + } + + rv = export_series(studies->series, &series); + if (rv) + goto error_series; + + Mat_VarSetStructFieldByName(st, "study_id", 0, id); + Mat_VarSetStructFieldByName(st, "series", 0, series); + Mat_VarSetCell(*out, i++, st); + continue; + + error_series: + Mat_VarFree(id); + error_id: + Mat_VarFree(st); + goto error; + } + + return 0; + +error: + Mat_VarFree(*out); + return rv; +} + +static int export_patients(const struct e2e_patient *patients, matvar_t **out) +{ + int rv; + size_t i, dims; + const struct e2e_patient *patient; + + dims = HASH_COUNT(patients); + *out = Mat_VarCreate("patients", MAT_C_CELL, MAT_T_CELL, 1, &dims, + NULL, 0); + if (!*out) + return ENOMEM; + + i = 0; + HASH_FOR(patient, patients, hh) { + const char *fields[] = {"patient_id", "studies"}; + matvar_t *st, *id, *studies; + + st = create_struct(fields, COUNT(fields)); + if (!st) { + rv = ENOMEM; + goto error; + } + + id = create_int(&patient->id); + if (!id) { + rv = ENOMEM; + goto error_id; + } + + rv = export_studies(patients->studies, &studies); + if (rv) + goto error_studies; + + Mat_VarSetStructFieldByName(st, "patient_id", 0, id); + Mat_VarSetStructFieldByName(st, "studies", 0, studies); + Mat_VarSetCell(*out, i++, st); + continue; + + error_studies: + Mat_VarFree(id); + error_id: + Mat_VarFree(st); + goto error; + } + + return 0; + +error: + Mat_VarFree(*out); + return rv; +} + +int export(const struct e2e_data *data, const char *path) +{ + int rv = 0; + mat_t *mat; + matvar_t *patients; + + mat = Mat_Create(path, NULL); + if (!mat) { + errorf("error: couldn't open '%s' for writing\n", path); + return EIO; + } + + rv = export_patients(data->patients, &patients); + if (!rv) { + Mat_VarWrite(mat, patients, MAT_COMPRESSION_ZLIB); + Mat_VarFree(patients); + } + + Mat_Close(mat); + return rv; +} \ No newline at end of file diff --git a/src/export.h b/src/export.h new file mode 100644 index 0000000..1552396 --- /dev/null +++ b/src/export.h @@ -0,0 +1 @@ +int export(const struct e2e_data *data, const char *path); diff --git a/src/main.c b/src/main.c index 0242172..dcb5d06 100644 --- a/src/main.c +++ b/src/main.c @@ -1,7 +1,4 @@ -#include -#include -#include -#include +#include "common.h" #include #include #include @@ -9,6 +6,7 @@ #include #include "e2e.h" +#include "export.h" int main(int argc, char **argv) { @@ -45,8 +43,11 @@ int main(int argc, char **argv) goto error_mmap; } - if (e2e_read(&data, input, input + st.st_size)) + if (errno = e2e_read(&data, input, input + st.st_size)) perror("e2e_read"); + else if (errno = export(&data, "testing.mat")) + perror("export"); + e2e_destroy(&data); munmap(input, st.st_size); -- cgit