diff --git a/CMakeLists.txt b/CMakeLists.txt index 18cd1be..a8b354c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,6 +45,8 @@ set(ZSTD_DIR "${CMAKE_CURRENT_SOURCE_DIR}/dependencies/${ZSTD_VER}") add_subdirectory(${ZSTD_DIR}/build/cmake) set_property(TARGET libzstd_static PROPERTY POSITION_INDEPENDENT_CODE ON) +# Added by XS, add zlib for compilation to work +include_directories(${CMAKE_BINARY_DIR}/dependencies/zlib-1.2.8) # Add libtiff include_directories(${CMAKE_BINARY_DIR}/dependencies/${TIFF_VER}/libtiff) include_directories(${ZSTD_DIR}/lib) diff --git a/mexSrc/compile_parallelReadTiff.m b/mexSrc/compile_parallelReadTiff.m index 4e671a8..b7ffb08 100755 --- a/mexSrc/compile_parallelReadTiff.m +++ b/mexSrc/compile_parallelReadTiff.m @@ -54,10 +54,22 @@ system('chmod 777 ../macArm/parallelReadTiff.mexmaca64'); end elseif ispc - setenv('MW_MINGW64_LOC','C:/mingw64'); - releaseFolder = '../windows'; + %setenv('MW_MINGW64_LOC','C:/mingw64'); + releaseFolder = '..\windows'; if ~exist(releaseFolder, 'dir') mkdir(releaseFolder); end - mex -outdir ../windows -output parallelReadTiff.mexw64 -v CXX="C:/mingw64/bin/g++" -v CXXOPTIMFLAGS="-DNDEBUG -O3" LDOPTIMFLAGS="-Wl',-rpath='''$ORIGIN'''' -O3 -DNDEBUG" CXXFLAGS='$CXXFLAGS -fopenmp -O3' LDFLAGS='$LDFLAGS -fopenmp -O3' -I'C:/Users/matt/Documents/GitHub/c-tiff/jenkinsBuild/install/include' -L'C:/Users/matt/Documents/GitHub/c-tiff/jenkinsBuild/install/lib' -lcppTiff.dll parallelreadtiffmex.cpp + mex -outdir ..\windows -output parallelReadTiff.mexw64 ... + -v CXX="C:\ProgramData\MATLAB\SupportPackages\R2022b\3P.instrset\mingw_w64.instrset\bin\g++" -v CXXOPTIMFLAGS="-DNDEBUG -O3" ... + LDOPTIMFLAGS="-Wl',-rpath='''$ORIGIN'''' -O3 -DNDEBUG" ... + CXXFLAGS='$CXXFLAGS -fopenmp -O3' LDFLAGS='$LDFLAGS -fopenmp -O3' ... + -I'..\dependencies\libdeflate-1.18' ... + -I'..\dependencies\tiff-4.7.0' ... + -I'..\dependencies\tiff-4.7.0\libtiff' ... + -I'..\build\dependencies\tiff-4.7.0\libtiff' ... + -I'..\dependencies\zlib-1.2.8' ... + -I'..\dependencies\zstd-1.5.6' ... + -I'..\build\dependencies\zlib-1.2.8' ... + -L'..\build' -lcppTiff.dll ... + parallelreadtiffmex.cpp end diff --git a/mexSrc/parallelreadtiffmex.cpp b/mexSrc/parallelreadtiffmex.cpp index 6ecb0be..8ac64fd 100755 --- a/mexSrc/parallelreadtiffmex.cpp +++ b/mexSrc/parallelreadtiffmex.cpp @@ -5,7 +5,8 @@ #include "../src/helperfunctions.h" #include "../src/parallelreadtiff.h" - +// Modified to read tiff from stack with a step size by accepting [start step end] as second argument. +// *Read with step is only enabled for the case of 3D, imageJ and 2D case are not touched. void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { @@ -44,7 +45,7 @@ void mexFunction(int nlhs, mxArray *plhs[], TIFF* tif = TIFFOpen(fileName, "r"); if(!tif) mexErrMsgIdAndTxt("tiff:inputError","File \"%s\" cannot be opened",fileName); - uint64_t x = 1,y = 1,z = 1,bits = 1, startSlice = 0; + uint64_t x = 1,y = 1,z = 1,bits = 1, startSlice = 0, sliceStep = 1; TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &x); TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &y); @@ -58,10 +59,8 @@ void mexFunction(int nlhs, mxArray *plhs[], } } else{ - if(mxGetN(prhs[1]) != 2){ - mexErrMsgIdAndTxt("tiff:inputError","Input range is not 2"); - } - else{ + // Modified for accepting both [start end] and [start step end] as second argument + if(mxGetN(prhs[1]) == 2){ startSlice = (uint64_t)*(mxGetPr(prhs[1]))-1; z = (uint64_t)*((mxGetPr(prhs[1])+1))-startSlice; uint64_t maxSize = 0; @@ -74,6 +73,23 @@ void mexFunction(int nlhs, mxArray *plhs[], mexErrMsgIdAndTxt("tiff:rangeOutOfBound","Range is out of bounds"); } } + else if (mxGetN(prhs[1]) == 3){ + if(isImageJIm(fileName)){ + mexErrMsgIdAndTxt("tiff:inputError","Read with step is not supported for ImageJ."); + } + startSlice = (uint64_t)*(mxGetPr(prhs[1]))-1; + sliceStep = (uint64_t)*((mxGetPr(prhs[1])+1)); + uint64_t endSlice = (uint64_t)*((mxGetPr(prhs[1])+2))-1; + z = (endSlice-startSlice)/sliceStep+1; + + uint64_t maxSize = getImageSizeZ(fileName); + if (startSlice < 0 || endSlice+1 > maxSize){ + mexErrMsgIdAndTxt("tiff:rangeOutOfBound","Range is out of bounds"); + } + } + else{ + mexErrMsgIdAndTxt("tiff:inputError","Input range is not 2 or 3"); + } } TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &bits); @@ -139,27 +155,27 @@ void mexFunction(int nlhs, mxArray *plhs[], mexErrMsgIdAndTxt("tiff:dataTypeError","Data type not suppported"); } } - // Case for 3D + // Case for 3D, modified to accept sliceStep as extra argument else{ if(bits == 8){ plhs[0] = mxCreateNumericArray(3,(mwSize*)dim,mxUINT8_CLASS, mxREAL); uint8_t* tiff = (uint8_t*)mxGetPr(plhs[0]); - err = readTiffParallel(x,y,z,fileName, (void*)tiff, bits, startSlice, stripSize, flipXY); + err = readTiffParallel(x,y,z,fileName, (void*)tiff, bits, startSlice, sliceStep, stripSize, flipXY); } else if(bits == 16){ plhs[0] = mxCreateNumericArray(3,(mwSize*)dim,mxUINT16_CLASS, mxREAL); uint16_t* tiff = (uint16_t*)mxGetPr(plhs[0]); - err = readTiffParallel(x,y,z,fileName, (void*)tiff, bits, startSlice, stripSize, flipXY); + err = readTiffParallel(x,y,z,fileName, (void*)tiff, bits, startSlice, sliceStep, stripSize, flipXY); } else if(bits == 32){ plhs[0] = mxCreateNumericArray(3,(mwSize*)dim,mxSINGLE_CLASS, mxREAL); float* tiff = (float*)mxGetPr(plhs[0]); - err = readTiffParallel(x,y,z,fileName, (void*)tiff, bits, startSlice, stripSize, flipXY); + err = readTiffParallel(x,y,z,fileName, (void*)tiff, bits, startSlice, sliceStep, stripSize, flipXY); } else if(bits == 64){ plhs[0] = mxCreateNumericArray(3,(mwSize*)dim,mxDOUBLE_CLASS, mxREAL); double* tiff = (double*)mxGetPr(plhs[0]); - err = readTiffParallel(x,y,z,fileName, (void*)tiff, bits, startSlice, stripSize, flipXY); + err = readTiffParallel(x,y,z,fileName, (void*)tiff, bits, startSlice, sliceStep, stripSize, flipXY); } else{ mexErrMsgIdAndTxt("tiff:dataTypeError","Data type not suppported"); diff --git a/mexSrc/tests.m b/mexSrc/tests.m index 3a4fc70..68f5a3b 100644 --- a/mexSrc/tests.m +++ b/mexSrc/tests.m @@ -1,8 +1,21 @@ +addpath('../windows'); im = rand(100,100,100,'single'); +im(:,:,2:2:100) = 1; parallelWriteTiff('test.tif',im); - -%% +%% parallelReadTiff in different modes imT = parallelReadTiff('test.tif'); - +imT_1_6 = parallelReadTiff('test.tif',[1 6]); %[start end] +imT_1_2_11 = parallelReadTiff('test.tif',[1 2 11]);%[start step end] +imT_2_2_12 = parallelReadTiff('test.tif',[2 2 12]);%[start step end] +%% Visualize tiff read by different modes +figure; +montage(imT_1_6,'Size',[1 6]); +title('1 to 6'); +figure; +montage(imT_1_2_11,'Size',[1 6]); +title('1 to 11 at step 2'); +figure; +montage(imT_2_2_12,'Size',[1 6]); +title('2 to 12 at step 2'); %% -imSize = getImageSizeMex('test.tif'); \ No newline at end of file +imSize = getImageSizeMex('test.tif'); diff --git a/src/parallelreadtiff.cpp b/src/parallelreadtiff.cpp index 08b39b2..fa8c0f2 100755 --- a/src/parallelreadtiff.cpp +++ b/src/parallelreadtiff.cpp @@ -81,7 +81,8 @@ uint8_t readTiffParallelBak(uint64_t x, uint64_t y, uint64_t z, const char* file return err; } -uint8_t readTiffParallel(uint64_t x, uint64_t y, uint64_t z, const char* fileName, void* tiff, uint64_t bits, uint64_t startSlice, uint64_t stripSize, uint8_t flipXY){ +// Modified such that the function can read tiff from stack with step size as specified by sliceStep. +uint8_t readTiffParallel(uint64_t x, uint64_t y, uint64_t z, const char* fileName, void* tiff, uint64_t bits, uint64_t startSlice, uint64_t sliceStep, uint64_t stripSize, uint8_t flipXY){ int32_t numWorkers = omp_get_max_threads(); int32_t batchSize = (z-1)/numWorkers+1; uint64_t bytes = bits/8; @@ -109,8 +110,10 @@ uint8_t readTiffParallel(uint64_t x, uint64_t y, uint64_t z, const char* fileNam } void* buffer = malloc(x*stripSize*bytes); - for(int64_t dir = startSlice+(w*batchSize); dir < startSlice+((w+1)*batchSize); dir++){ - if(dir>=z+startSlice || err) break; + // Modified to enable looping through tiff dir with user specified steps + for(int64_t dir = startSlice+(w*batchSize*sliceStep); dir < startSlice+((w+1)*batchSize*sliceStep); dir = dir+sliceStep){ + // Modified, (z-1)*sliceStep+startSlice is the last slice to read + if(dir>=z*sliceStep+startSlice || err) break; uint8_t counter = 0; while(!TIFFSetDirectory(tif, (uint64_t)dir) && counter<3){ @@ -148,7 +151,7 @@ uint8_t readTiffParallel(uint64_t x, uint64_t y, uint64_t z, const char* fileNam for(int64_t k = 0; k < stripSize; k++){ if((k+(i*stripSize)) >= y) break; for(int64_t j = 0; j < x; j++){ - ((uint8_t*)tiff)[((j*y)+(k+(i*stripSize)))+((dir-startSlice)*(x*y))] = ((uint8_t*)buffer)[j+(k*x)]; + ((uint8_t*)tiff)[((j*y)+(k+(i*stripSize)))+((dir-startSlice)/sliceStep*(x*y))] = ((uint8_t*)buffer)[j+(k*x)]; } } break; @@ -157,7 +160,7 @@ uint8_t readTiffParallel(uint64_t x, uint64_t y, uint64_t z, const char* fileNam for(int64_t k = 0; k < stripSize; k++){ if((k+(i*stripSize)) >= y) break; for(int64_t j = 0; j < x; j++){ - ((uint16_t*)tiff)[((j*y)+(k+(i*stripSize)))+((dir-startSlice)*(x*y))] = ((uint16_t*)buffer)[j+(k*x)]; + ((uint16_t*)tiff)[((j*y)+(k+(i*stripSize)))+((dir-startSlice)/sliceStep*(x*y))] = ((uint16_t*)buffer)[j+(k*x)]; } } break; @@ -166,7 +169,7 @@ uint8_t readTiffParallel(uint64_t x, uint64_t y, uint64_t z, const char* fileNam for(int64_t k = 0; k < stripSize; k++){ if((k+(i*stripSize)) >= y) break; for(int64_t j = 0; j < x; j++){ - ((float*)tiff)[((j*y)+(k+(i*stripSize)))+((dir-startSlice)*(x*y))] = ((float*)buffer)[j+(k*x)]; + ((float*)tiff)[((j*y)+(k+(i*stripSize)))+((dir-startSlice)/sliceStep*(x*y))] = ((float*)buffer)[j+(k*x)]; } } break; @@ -175,7 +178,7 @@ uint8_t readTiffParallel(uint64_t x, uint64_t y, uint64_t z, const char* fileNam for(int64_t k = 0; k < stripSize; k++){ if((k+(i*stripSize)) >= y) break; for(int64_t j = 0; j < x; j++){ - ((double*)tiff)[((j*y)+(k+(i*stripSize)))+((dir-startSlice)*(x*y))] = ((double*)buffer)[j+(k*x)]; + ((double*)tiff)[((j*y)+(k+(i*stripSize)))+((dir-startSlice)/sliceStep*(x*y))] = ((double*)buffer)[j+(k*x)]; } } break; @@ -185,12 +188,12 @@ uint8_t readTiffParallel(uint64_t x, uint64_t y, uint64_t z, const char* fileNam free(buffer); TIFFClose(tif); } - if(err){ - if(errBak) return readTiffParallelBak(x, y, z, fileName, tiff, bits, startSlice, flipXY); - else { - printf(errString); - } - } + //if(err){ + //if(errBak) return readTiffParallelBak(x, y, z, fileName, tiff, bits, startSlice, flipXY); + //else { + //printf(errString); + //} + //} return err; } @@ -565,7 +568,7 @@ uint8_t readTiffParallelImageJ(uint64_t x, uint64_t y, uint64_t z, const char* f return err; } - +// Modified for accepting zRange in the format of both [start end] and [start step end] // tiff pointer guaranteed to be NULL or the correct size array for the tiff file void* readTiffParallelWrapperHelper(const char* fileName, void* tiff, uint8_t flipXY, const std::vector &zRange = {}) { @@ -573,7 +576,7 @@ void* readTiffParallelWrapperHelper(const char* fileName, void* tiff, uint8_t fl TIFF* tif = TIFFOpen(fileName, "r"); if(!tif) return NULL; - uint64_t x = 1,y = 1,z = 1,bits = 1, startSlice = 0; + uint64_t x = 1,y = 1,z = 1,bits = 1, startSlice = 0, sliceStep = 1; TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &x); TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &y); z = getImageSizeZ(fileName); @@ -597,6 +600,11 @@ void* readTiffParallelWrapperHelper(const char* fileName, void* tiff, uint8_t fl startSlice = zRange[0]; z = zRange[1]; } + else if(zRange.size() == 3){ + startSlice = zRange[0]; + sliceStep = zRange[1]; + z = (zRange[2]-zRange[0])/sliceStep+1; + } else{ startSlice = zRange[0]; z = zRange[0]+1; @@ -657,22 +665,22 @@ void* readTiffParallelWrapperHelper(const char* fileName, void* tiff, uint8_t fl else{ if(bits == 8){ if(!tiff) tiff = (uint8_t*)malloc(x*y*z*sizeof(uint8_t)); - readTiffParallel(x,y,z,fileName, (void*)tiff, bits, startSlice, stripSize, flipXY); + readTiffParallel(x,y,z,fileName, (void*)tiff, bits, startSlice, sliceStep, stripSize, flipXY); return (void*)tiff; } else if(bits == 16){ if(!tiff) tiff = (uint16_t*)malloc(x*y*z*sizeof(uint16_t)); - readTiffParallel(x,y,z,fileName, (void*)tiff, bits, startSlice, stripSize, flipXY); + readTiffParallel(x,y,z,fileName, (void*)tiff, bits, startSlice, sliceStep, stripSize, flipXY); return (void*)tiff; } else if(bits == 32){ if(!tiff) tiff = (float*)malloc(x*y*z*sizeof(float)); - readTiffParallel(x,y,z,fileName, (void*)tiff, bits, startSlice, stripSize, flipXY); + readTiffParallel(x,y,z,fileName, (void*)tiff, bits, startSlice, sliceStep, stripSize, flipXY); return (void*)tiff; } else if(bits == 64){ if(!tiff) tiff = (double*)malloc(x*y*z*sizeof(double)); - readTiffParallel(x,y,z,fileName, (void*)tiff, bits, startSlice, stripSize, flipXY); + readTiffParallel(x,y,z,fileName, (void*)tiff, bits, startSlice, sliceStep, stripSize, flipXY); return (void*)tiff; } else{ diff --git a/src/parallelreadtiff.h b/src/parallelreadtiff.h index 1495558..9f351f7 100755 --- a/src/parallelreadtiff.h +++ b/src/parallelreadtiff.h @@ -4,7 +4,7 @@ #include #include -uint8_t readTiffParallel(uint64_t x, uint64_t y, uint64_t z, const char* fileName, void* tiff, uint64_t bits, uint64_t startSlice, uint64_t stripSize, uint8_t flipXY); +uint8_t readTiffParallel(uint64_t x, uint64_t y, uint64_t z, const char* fileName, void* tiff, uint64_t bits, uint64_t startSlice, uint64_t sliceStep, uint64_t stripSize, uint8_t flipXY); uint8_t readTiffParallel2D(uint64_t x, uint64_t y, uint64_t z, const char* fileName, void* tiff, uint64_t bits, uint64_t startSlice, uint64_t stripSize, uint8_t flipXY);