32#include "DGtal/base/Common.h"
33#include <DGtal/helpers/StdDefs.h>
34#include <DGtal/images/ImageContainerBySTLVector.h>
36#include <DGtal/io/readers/GenericReader.h>
37#include <DGtal/io/writers/GenericWriter.h>
42#include "DGtal/io/readers/ITKReader.h"
43#include "DGtal/io/writers/ITKWriter.h"
93typedef ImageContainerBySTLVector < Z3i::Domain, unsigned char > Image3D;
95typedef ImageContainerBySTLVector < Z3i::Domain, double > Image3D_D;
96typedef ImageContainerBySTLVector < Z3i::Domain, int > Image3D_I;
103template<
typename TImage,
typename TImageMask>
104typename TImageMask::Domain
105subDomainMasked(
const TImage &image,
const TImageMask &maskImage,
106 typename TImageMask::Value maskValue,
unsigned int domainOffset=1){
107 typename TImageMask::Domain res;
108 Z3i::Point minP = image.domain().upperBound();
109 Z3i::Point maxP = image.domain().lowerBound();
111 Z3i::Point::Iterator minIt;
112 Z3i::Point::Iterator maxIt;
113 bool foundMaskedVal =
false;
114 for(
const auto &p: image.domain())
116 minIt = minP.begin();
117 maxIt = maxP.begin();
118 if( maskImage.domain().isInside(p) && maskImage(p) == maskValue )
121 for(
auto pIt=p.begin(); pIt!=p.end();pIt++ )
123 if( *pIt < *minIt ){*minIt = *pIt;}
124 if( *pIt > *maxIt ){*maxIt = *pIt;}
132 trace.info() <<
"No masked value found resulting image will be empty." << std::endl;
133 return image.domain();
137 Z3i::Point offset(domainOffset,domainOffset,domainOffset);
140 trace.info() <<
"sub-domain:" << minP <<
" " << maxP << std::endl;
141 return typename TImageMask::Domain(minP, maxP);
145template<
typename TImage,
typename TImageMask>
147applyMask(
const TImage &inputImage,TImage &outputImage,
148 const TImageMask &maskImage,
typename TImageMask::Value maskValue)
150 for (
const auto &p: outputImage.domain())
152 if (inputImage.domain().isInside(p) && maskImage(p) == maskValue)
154 outputImage.setValue(p, inputImage(p) );
160template<
typename TImage,
typename TImageMask>
162processImage(
const TImage &inputImage,
const TImageMask &maskImage,
163 typename TImageMask::Value maskValue, std::string outputFileName,
unsigned int offsetBorder ){
165 auto subDm = subDomainMasked(inputImage, maskImage, maskValue, offsetBorder);
166 TImage outputImage( subDm );
168 applyMask(inputImage, outputImage, maskImage, maskValue);
169 trace.info() <<
"writing output image...";
170 GenericWriter<TImage>::exportFile(outputFileName, outputImage);
174int main(
int argc,
char** argv )
179 std::string inputFileName;
180 std::string outputFileName {
"result.vol"};
181 std::string inputType;
182 std::string maskFileName;
183 unsigned int offsetBorder {0};
186 app.description(
"Outputs a new image from two input images, one representing the data, one representing the selection mask. The size of output image is the size of the bounding box of selected values, plus the chosen border offset. \n Typical use example:\n \t volMask ${DGtal}/examples/samples/lobster.vol lobsMasked.vol -a ${DGtal}/examples/samples/lobster.vol -m 100 \n");
189 app.add_option(
"-i,--input,1", inputFileName,
"an input 3D image vol (or ITK: .nii, mha, ... ) file." )
191 ->check(CLI::ExistingFile);
192 app.add_option(
"--inputType,-t",inputType,
"to specify the input image type (int or double).");
195 app.add_option(
"-i,--input,1", inputFileName,
"an input vol file." )
197 ->check(CLI::ExistingFile);
200 app.add_option(
"--mask,-a",maskFileName,
"the mask image that represents the elements that are copied as output in the resulting image (by default set to 1 you can change this value by using --maskValue). ")
201 ->check(CLI::ExistingFile);
202 app.add_option(
"-o,--output,2", outputFileName,
"the output masked image." );
203 app.add_option(
"--offsetBorder,-f", offsetBorder,
"add a border offset to the bounding box of the masked value domain.");
204 app.add_option(
"--maskValue,-m", maskValue,
"the masking value.");
205 app.get_formatter()->column_width(40);
206 CLI11_PARSE(app, argc, argv);
211 trace.info() <<
"Reading mask image...";
212 Image3D maskImage = DGtal::GenericReader<Image3D>::import(maskFileName);
213 trace.info() <<
"[done]"<< std::endl;
214 trace.info() <<
"Reading input image...";
216 if (inputType==
"double")
218 Image3D_D inputImage = DGtal::GenericReader<Image3D_D>::import(inputFileName);
219 trace.info() <<
"[done]"<< std::endl;
220 processImage(inputImage, maskImage, maskValue, outputFileName, offsetBorder);
222 else if (inputType==
"int")
224 Image3D_I inputImage = DGtal::GenericReader<Image3D_I>::import(inputFileName);
225 trace.info() <<
"[done]"<< std::endl;
226 processImage(inputImage, maskImage, maskValue, outputFileName, offsetBorder);
230 Image3D inputImage = DGtal::GenericReader<Image3D>::import(inputFileName);
231 trace.info() <<
"[done]"<< std::endl;
232 processImage(inputImage, maskImage, maskValue, outputFileName, offsetBorder);
235 Image3D inputImage = DGtal::GenericReader<Image3D>::import(inputFileName);
236 processImage(inputImage, maskImage, maskValue, outputFileName, offsetBorder);
239 trace.info() <<
"[Done]" << std::endl;