예제 #1
0
static void doSeparate(Options& opts, StringVector& args) {
    if (!opts.GetBool("--separate")) {
        return;
    }

    ImageIO<DisplacementFieldType> io;
    DisplacementFieldType::Pointer input = io.ReadImage(args[0]);

    for (int i = 0; i < DisplacementFieldType::PixelType::Length; i++) {
        ImageIO<RealImage> realIO;
        RealImage::Pointer output = realIO.NewImageS<DisplacementFieldType>(input);

        RealImage::PixelType* oBuf = output->GetBufferPointer();
        itk::ImageRegionConstIteratorWithIndex<DisplacementFieldType> iter(input, input->GetBufferedRegion());

        int j = 0;
        for (iter.GoToBegin(); !iter.IsAtEnd(); ++iter, j++) {
            DisplacementFieldType::PixelType p = iter.Get();
            oBuf[j] = p[i];
        }

        realIO.WriteImage(args[i+1], output);
    }
    end();
}
예제 #2
0
파일: krgb.cpp 프로젝트: fayhot/gradworks
int main(int argc, char* argv[]) {
    CSimpleOpt::SOption specs[] = {
        { 0, "-o", SO_REQ_SEP },
        SO_END_OF_OPTIONS
    };

    Options argParser;
    StringVector args = argParser.ParseOptions(argc, argv, specs);

    if (args.size() < 1) {
        cout << argv[0] << " [input-vector] [output-rgb]" << endl;
        return 1;
    }

    ImageIO<DeformFieldImageType> io;
    DeformFieldImageType::Pointer img = io.ReadImage(args[0]);

//    itk::UnaryFunctorImageFilter<DeformFieldImageType,RGBImageType> CastFilter;
    typedef itk::UnaryFunctorImageFilter<DeformFieldImageType, RGBImageType, Vector2RGB> CastFilter;
    CastFilter::Pointer caster = CastFilter::New();
    caster->SetInput(img);
    caster->Update();
    RGBImageType::Pointer rgbImg = caster->GetOutput();

    rgbImg->Print(cout);
    io.WriteImageS<RGBImageType>(args[1], rgbImg);

    return 0;
}
예제 #3
0
// draw gaussian like line
void runExpr1(StringVector &args) {
    if (args.size() < 2) {
        cout << "--expr1 [output-real-image] [bending-height]" << endl;
        return;
    }

    float bendingHeight = atof(args[1].c_str());
    int bandWidth = 12;

    ImageIO<RealImage2> io;
    RealImage2::Pointer canvas = io.NewImageT(300, 200, 1);

    for (int x = 25; x < 275; x++) {
        double xx = (x - 150) * 0.1;
        double y = 150 - bendingHeight * exp(-xx*xx/100);

        RealImage2::IndexType realIdx;
        for (int j = y; j >= y - bandWidth; j--) {
            realIdx[0] = x;
            realIdx[1] = j;
            canvas->SetPixel(realIdx, 1);
        }
    }

    io.WriteImage(args[0], canvas);
}
예제 #4
0
void DrawPolyList(const char *filename, list<TPPLPoly> *polys) {
	Image img(500,500);
	Image::Pixel white={255,255,255};
	img.Clear(white);

	ImageIO io;
	list<TPPLPoly>::iterator iter;

	tppl_float xmin = std::numeric_limits<tppl_float>::max();
	tppl_float xmax = std::numeric_limits<tppl_float>::min();
	tppl_float ymin = std::numeric_limits<tppl_float>::max();
	tppl_float ymax = std::numeric_limits<tppl_float>::min();
	for(iter=polys->begin(); iter!=polys->end(); iter++) {
		for(int i=0;i<iter->GetNumPoints();i++) {
			if(iter->GetPoint(i).x < xmin) xmin = iter->GetPoint(i).x;
			if(iter->GetPoint(i).x > xmax) xmax = iter->GetPoint(i).x;
			if(iter->GetPoint(i).y < ymin) ymin = iter->GetPoint(i).y;
			if(iter->GetPoint(i).y > ymax) ymax = iter->GetPoint(i).y;
		}
		//if(iter->GetOrientation() == TPPL_CCW) printf("CCW\n");
		//else if (iter->GetOrientation() == TPPL_CW) printf("CW\n");
		//else printf("gfdgdg\n");
	}
	//printf("\n");

	for(iter=polys->begin(); iter!=polys->end(); iter++) {
		DrawPoly(&img, &(*iter), xmin, xmax, ymin, ymax);
	}

	io.SaveImage(filename,&img);
}
예제 #5
0
void runVector2Mat(StringVector& args) {
    ImageIO<VectorImage2> io;
    VectorImage2::Pointer inputImage = io.ReadImage(args[0]);

    typedef itk::ImageRegionConstIteratorWithIndex<VectorImage2> VectorImageIteratorType;
    VectorImageIteratorType iter(inputImage, inputImage->GetBufferedRegion());

    ofstream ofs[2];
    ofs[0].open(args[1].c_str());
    ofs[1].open(args[2].c_str());

    VectorImage2::SizeType inputSize = inputImage->GetBufferedRegion().GetSize();

    VectorType* buffer = inputImage->GetBufferPointer();
    for (int j = 0; j < inputSize[1]; j++) {
        for (int i = 0; i < inputSize[0]; i++) {
            VectorType& vv = *buffer;
            for (int k = 0; k < 2; k++) {
                ofs[k] << vv[k] << " ";
            }
            ++buffer;
        }
        for (int k = 0; k < 2; k++) {
            ofs[k] << endl;
        }
    }

    for (int k = 0; k < 2; k++) {
        ofs[k].close();
    }
}
예제 #6
0
static void doSlice(Options& opts, StringVector& args) {
    if (!opts.GetBool("--slice")) {
        return;
    }
    if (args.size() < 4) {
        cout << "--slice dim index imagefile outputfile" << endl;
        die();
    }

    int dim = atoi(args[0].c_str());
    int slice = atoi(args[1].c_str());

    ImageIO<RealImage3> io;
    ImageInfo info;
    RealImage3::Pointer image = io.ReadCastedImage(args[2], info);
    RealImage2Vector sliceImages = SliceVolume(image, dim);

    if (slice < sliceImages.size()) {
        ImageIO<RealImage2> wio;
        wio.WriteCastedImage(args[3], sliceImages[slice], info.componenttype);
    } else {
        cout << "slice index is out of range" << endl;
    }
    end();
}
예제 #7
0
/// utility function
void zeroCrossing(Options& parser, StringVector& args) {
    if (args.size() < 2) {
        cout << "--zercorssing requires [srcimg] [dstimg]" << endl;
        return;
    }
    string srcImg = args[0];
    string dstImg = args[1];


    ImageProcessing proc;
    LabelImage::Pointer label = labelIO.ReadImage(args[0].c_str());
    LabelImage::Pointer zeroCross = proc.ZeroCrossing(label);
    labelIO.WriteImage(args[1].c_str(), zeroCross);

    return;
}
shared_ptr<Codec> SixFringeCodecOptionsController::getCodec(void)
{
  QString sourceFilename = sourceFileBox->text();
  string str = sourceFilename.toLocal8Bit().constData();

  shared_ptr<SixFringeDecoder> codec = shared_ptr<SixFringeDecoder>(new SixFringeDecoder(str));
  codec->setGammaCutoff(gammaCutoffBox->value());
  codec->setScalingFactor(scalingBox->value());

  if(loadReferenceCheckbox->isChecked() && !shortReferenceFileBox->text().isEmpty() && !longReferenceFileBox->text().isEmpty())
  {
	ImageIO io;
	shared_ptr<IplImage> shortImage(io.readImage(shortReferenceFileBox->text().toAscii().constData()), [](IplImage* ptr) { cvReleaseImage(&ptr); });
	shared_ptr<IplImage> longImage(io.readImage(longReferenceFileBox->text().toAscii().constData()), [](IplImage* ptr) { cvReleaseImage(&ptr); });

	codec->setReferencePlane(shortImage, longImage);
  }

  return codec;
}
예제 #9
0
void computeHistogram(Options& parser, StringVector& args) {
    ImageProcessing proc;
    int nbin = 16;
    int rmin = 0;
    int rmax = 10000;
    parser.GetIntTo("--nbin", nbin);
    parser.GetIntTo("--rmin", rmin);
    parser.GetIntTo("--rmax", rmax);
    cout << proc.ComputeHistogramToString(realIO.ReadImage(args[0].c_str()), nbin, rmin, rmax) << endl;
    return;
}
예제 #10
0
void DrawPoly(const char *filename, TPPLPoly *poly) {
	Image img(500,500);
	Image::Pixel white={255,255,255};
	img.Clear(white);
	ImageIO io;

	tppl_float xmin = std::numeric_limits<tppl_float>::max();
	tppl_float xmax = std::numeric_limits<tppl_float>::min();
	tppl_float ymin = std::numeric_limits<tppl_float>::max();
	tppl_float ymax = std::numeric_limits<tppl_float>::min();
	for(int i=0;i<poly->GetNumPoints();i++) {
		if(poly->GetPoint(i).x < xmin) xmin = poly->GetPoint(i).x;
		if(poly->GetPoint(i).x > xmax) xmax = poly->GetPoint(i).x;
		if(poly->GetPoint(i).y < ymin) ymin = poly->GetPoint(i).y;
		if(poly->GetPoint(i).y > ymax) ymax = poly->GetPoint(i).y;
	}

	DrawPoly(&img, poly, xmin, xmax, ymin, ymax);

	io.SaveImage(filename,&img);
}
예제 #11
0
    RealImage::Pointer SIFTImagePCAComputer::computePCImage(SIFTImage* image, int k) {
        ImageIO<RealImage> io;
        RealImage::Pointer outputImg = io.NewImageT(image->GetBufferedRegion().GetSize());

        SIFTFeature* feature = image->GetBufferPointer();
        DataReal* output = outputImg->GetBufferPointer();
        const uint size = image->GetPixelContainer()->Size();
        const uint featureSize = feature[0].GetNumberOfComponents();
        for (uint i = 0; i < size; i++) {
            uchar* data = feature->GetDataPointer();
            float sum = 0;
            for (uint j = 0; j < featureSize; j++) {
                sum += this->V[j][featureSize - 1 - k] * data[j];
            }
            *output = std::abs(sum);

            output++;
            feature++;
        }
        return outputImg;
    }
예제 #12
0
파일: emutil.cpp 프로젝트: jgalaz84/eman2
int EMUtil::get_image_count(const string & filename)
{
	ENTERFUNC;

	Assert(filename != "");

	int nimg = 0;

	ImageIO *imageio = get_imageio(filename, ImageIO::READ_ONLY);

	if (imageio) {
		nimg = imageio->get_nimg();
	}

   EMUtil::close_imageio(filename, imageio);

	imageio = NULL;

	EXITFUNC;

	return nimg;
}
예제 #13
0
/// create a new image which has the same attributes with the reference image
///
int runPointMarks(pi::Options& opts, pi::StringVector& args) {
    vtkPolyDataReader* reader = vtkPolyDataReader::New();
    reader->SetFileName(args[0].c_str());
    reader->Update();

    vtkPolyData*pd = reader->GetOutput();

    // load an image
    ImageIO<RealImage> imageIO;
    RealImage::Pointer refImage = imageIO.ReadImage(args[1].c_str());


    // create an empty image
    ImageIO<LabelImage> labelIO;
    LabelImage::Pointer markImage = labelIO.NewImageS<RealImage>(refImage);
    markImage->FillBuffer(0);

    // point flipping
    for (int i = 0; i < pd->GetNumberOfPoints(); i++) {
        RealImage::PointType p;
        pd->GetPoint(i, p.GetDataPointer());
        p[0] = -p[0];
        p[1] = -p[1];
        pd->GetPoints()->SetPoint(i, p.GetDataPointer());

        // point to index
        RealImage::IndexType idx;
        refImage->TransformPhysicalPointToIndex(p, idx);

        // mark image
        markImage->SetPixel(idx, 255);
    }

    labelIO.WriteImage(args[2], markImage);
    return EXIT_SUCCESS;
}
예제 #14
0
void ObjMeshRender::Texture::loadTextureImage(string fullPath, int * width, int * height, int * bpp, unsigned char ** texData)
{
  ImageIO imageIO;
  ImageIO::fileFormatType fileFormat;
  // automatically determines the file format type from the filename extension; see imageIO class
  ImageIO::errorType errorCode = imageIO.load(fullPath.c_str(), &fileFormat);
  if (errorCode != ImageIO::OK)
  {
    printf("Warning: unable to load texture %s.\n", fullPath.c_str());
    return;
  }

  *width = imageIO.getWidth();
  *height = imageIO.getHeight();
  *bpp = imageIO.getBytesPerPixel();
  *texData = (unsigned char*) malloc (sizeof(unsigned char) * *width * *height * *bpp);
  memcpy(*texData, imageIO.getPixels(), sizeof(unsigned char) * *width * *height * *bpp);
}
예제 #15
0
void Image::load(const std::string& filename)
{
    ImageIO iio;
    iio.load(*this, filename);
}
예제 #16
0
파일: emdata_io.cpp 프로젝트: C-CINA/2dx
void EMData::read_binedimage(const string & filename, int img_index, int binfactor, bool fast, bool is_3d)
{
	ENTERFUNC;
	
	ImageIO *imageio = EMUtil::get_imageio(filename, ImageIO::READ_ONLY);
	
	if (!imageio) {
		throw ImageFormatException("cannot create an image io");
	}
	else {
		int err = imageio->read_header(attr_dict, img_index, 0, is_3d);
		if (err) {
			throw ImageReadException(filename, "imageio read header failed");
		}
		else {
			attr_dict["source_path"] = filename;
			attr_dict["source_n"] = img_index;
			if (imageio->is_complex_mode()) {
				set_complex(true);
				set_fftpad(true);
			}
			if (attr_dict.has_key("is_fftodd") && (int)attr_dict["is_fftodd"] == 1) {
				set_fftodd(true);
			}
			if ((int) attr_dict["is_complex_ri"] == 1) {
				set_ri(true);
			}
			save_byteorder_to_dict(imageio);

			int ori_nx = nx = attr_dict["nx"];
			int ori_ny = ny = attr_dict["ny"];
			int ori_nz = nz = attr_dict["nz"];
			attr_dict.erase("nx");
			attr_dict.erase("ny");
			attr_dict.erase("nz");
			
			// At this point nx, ny and nz are all reduced by binfactor
			set_size(nx/binfactor, ny/binfactor, nz/binfactor);

			//here is where we read in the binned data
			EMData* tempdata = new EMData();
			size_t sizeofslice = nx*ny*sizeof(float);
			
			//zbin factor use 1 to speed binning(but don't benfit by averaging in Z)
			int zbin = binfactor;
			if(fast) zbin = 1;
			//verbose
			float percent = 0.1f;
			for(int k = 0; k < ori_nz; k+=binfactor){
				if(k > ori_nz*percent){	
					cout << float(k)/float(ori_nz) << "% Done!" << endl;
					percent+=0.1f;
				}
				// read in a slice region
				const Region* binregion = new Region(0,0,k,ori_nx,ori_ny,zbin);
				tempdata->read_image(filename, 0, false, binregion);
				// shrink the slice
				if (binfactor > 1) tempdata->process_inplace("math.meanshrink",Dict("n",binfactor));
				size_t offset = nx*ny*k/binfactor;
				//add slice to total
				EMUtil::em_memcpy(get_data()+offset,tempdata->get_data(),sizeofslice);
				delete binregion;
			}
			
			delete tempdata;
			update();
		}
	}

#ifndef IMAGEIO_CACHE
	if( imageio )
	{
#ifdef HDFIO_CACHE
		if(dynamic_cast<HdfIO2*>(imageio)==NULL && dynamic_cast<HdfIO*>(imageio)==NULL) {
#endif	//HDFIO_CACHE
			delete imageio;
			imageio = 0;
#ifdef HDFIO_CACHE
		}
#endif	//HDFIO_CACHE
	}
#endif	//IMAGEIO_CACHE

	EXITFUNC;
}
예제 #17
0
파일: emdata_io.cpp 프로젝트: C-CINA/2dx
void EMData::write_image(const string & filename, int img_index,
						 EMUtil::ImageType imgtype,
						 bool header_only, const Region * region,
						 EMUtil::EMDataType filestoragetype,
						 bool use_host_endian)
{
	ENTERFUNC;

	struct stat fileinfo;
	if ( region && stat(filename.c_str(),&fileinfo) != 0 ) throw UnexpectedBehaviorException("To write an image using a region the file must already exist and be the correct dimensions");

	if (is_complex() && is_shuffled())
		fft_shuffle();

	if (imgtype == EMUtil::IMAGE_UNKNOWN) {
		const char *ext = strrchr(filename.c_str(), '.');
		if (ext) {
			ext++;
			imgtype = EMUtil::get_image_ext_type(ext);
		}
	}
	ImageIO::IOMode rwmode = ImageIO::READ_WRITE;

	//set "nx", "ny", "nz" and "changecount" in attr_dict, since they are taken out of attribute dictionary
	attr_dict["nx"] = nx;
	attr_dict["ny"] = ny;
	attr_dict["nz"] = nz;
	attr_dict["changecount"] = changecount;

#ifndef HDFIO_CACHE
	if (Util::is_file_exist(filename)) {
		LOGVAR("file exists");
		if (!header_only && region == 0) {
			ImageIO * tmp_imageio = EMUtil::get_imageio(filename, ImageIO::READ_ONLY,
														imgtype);
			if (tmp_imageio->is_single_image_format()) {
				rwmode = ImageIO::WRITE_ONLY;
			}

#ifndef IMAGEIO_CACHE
			if( tmp_imageio )
			{
				delete tmp_imageio;
				tmp_imageio = 0;
			}
#endif	//IMAGEIO_CACHE
		}
	}
#endif	//HDFIO_CACHE

	LOGVAR("getimageio %d",rwmode);
	ImageIO *imageio = EMUtil::get_imageio(filename, rwmode, imgtype);
	if (!imageio) {
		throw ImageFormatException("cannot create an image io");
	}
	else {
		update_stat();
		/* Let each image format decide how to deal with negative image_index*/
//		if (img_index < 0) {
//			img_index = imageio->get_nimg();
//		}
		LOGVAR("header write %d",img_index);

		switch(filestoragetype) {
		case EMUtil::EM_UINT:
			attr_dict["datatype"] = (int)EMUtil::EM_UINT;
			break;
		case EMUtil::EM_USHORT:
			attr_dict["datatype"] = (int)EMUtil::EM_USHORT;
			break;
		case EMUtil::EM_SHORT:
			attr_dict["datatype"] = (int)EMUtil::EM_SHORT;
			break;
		case EMUtil::EM_CHAR:
			attr_dict["datatype"] = (int)EMUtil::EM_CHAR;
			break;
		case EMUtil::EM_UCHAR:
			attr_dict["datatype"] = (int)EMUtil::EM_UCHAR;
			break;
		default:
			attr_dict["datatype"] = (int)EMUtil::EM_FLOAT;;	//default float
		}

		int err = imageio->write_header(attr_dict, img_index, region, filestoragetype,
										use_host_endian);
		if (err) {
			throw ImageWriteException(filename, "imageio write header failed");
		}
		else {
			if (!header_only) {
				if (imgtype == EMUtil::IMAGE_LST) {
					const char *reffile = attr_dict["LST.reffile"];
					if (strcmp(reffile, "") == 0) {
						reffile = path.c_str();
					}
					int refn = attr_dict["LST.refn"];
					if (refn < 0) {
						refn = pathnum;
					}

					const char *comment = attr_dict["LST.comment"];
					char *lstdata = new char[1024];
					sprintf(lstdata, "%d\t%s", refn, reffile);
					if(strcmp(comment, "") != 0) {
						sprintf(lstdata+strlen(lstdata), "\t%s\n", comment);
					}
					else {
						strcat(lstdata, "\n");
					}
					err = imageio->write_data((float*)lstdata, img_index,
											  region, filestoragetype, use_host_endian);
					if( lstdata )
					{
						delete [] lstdata;
						lstdata = 0;
					}
				}
				if (imgtype == EMUtil::IMAGE_LSTFAST) {
					const char *reffile = attr_dict["LST.reffile"];
					if (strcmp(reffile, "") == 0) {
						reffile = path.c_str();
					}
					int refn = attr_dict["LST.refn"];
					if (refn < 0) {
						refn = pathnum;
					}

					const char *comment = attr_dict["LST.comment"];
					char *lstdata = new char[1024];
					sprintf(lstdata, "%d\t%s", refn, reffile);
					if(strcmp(comment, "") != 0) {
						sprintf(lstdata+strlen(lstdata), "\t%s\n", comment);
					}
					else {
						strcat(lstdata, "\n");
					}
					err = imageio->write_data((float*)lstdata, img_index,
											  region, filestoragetype, use_host_endian);
					if( lstdata )
					{
						delete [] lstdata;
						lstdata = 0;
					}
				}
				else {
					err = imageio->write_data(get_data(), img_index, region, filestoragetype,
											  use_host_endian);
				}
				if (err) {
					imageio->flush();
					throw ImageWriteException(filename, "imageio write data failed");
				}
			}
		}
	}
	//PNG image already do cleaning in write_data function.
	if (!(imgtype == EMUtil::IMAGE_PNG)) {
		imageio->flush();
	}

#ifndef IMAGEIO_CACHE
	if( imageio )
	{
#ifdef HDFIO_CACHE
		if(dynamic_cast<HdfIO2*>(imageio)==NULL && dynamic_cast<HdfIO*>(imageio)==NULL) {
#endif	//HDFIO_CACHE
			delete imageio;
			imageio = 0;
#ifdef HDFIO_CACHE
		}
#endif	//HDFIO_CACHE
	}
#endif	//IMAGEIO_CACHE

	EXITFUNC;
}
예제 #18
0
int main(int argc, char* argv[]) {
    CSimpleOpt::SOption specs[] = {
        { 9, "--seeConfig", SO_NONE },
        { 1000, "--json", SO_REQ_SEP },
        { 1001, "--config", SO_REQ_SEP },
        { 1002, "--run", SO_NONE },
        { 1, "-w", SO_NONE },
        { 8, "-d", SO_NONE },
        { 2, "-o", SO_REQ_SEP },
        { 3, "--mean", SO_NONE },
        { 4, "--srcidx", SO_REQ_SEP },
        { 7, "--dstidx", SO_REQ_SEP },
        { 6, "--noTrace", SO_NONE },
        { 10, "--markTrace", SO_NONE },
        { 23, "--markOutput", SO_NONE },
        { 11, "--srcsubj", SO_REQ_SEP },
        { 12, "--inputimage", SO_REQ_SEP },
        { 13, "--inputlabel", SO_REQ_SEP },
        { 14, "--normalize", SO_NONE },
        { 15, "--magnitude", SO_NONE },
        { 16, "--distancemap", SO_NONE },
        { 17, "--createmask", SO_NONE },
        { 18, "--rescaletoshort", SO_NONE },
        { 19, "--mask", SO_REQ_SEP },
        { 20, "--align", SO_NONE },
        { 21, "--warp", SO_NONE },
        { 22, "--norigidalign", SO_NONE },
        { 24, "--onlyrigidalign", SO_NONE },
        { 25, "--showpoints", SO_NONE },
        { 26, "--eval", SO_NONE },
        { 27, "--histo", SO_NONE },
        { 28, "--nbin", SO_NONE },
        { 29, "--rmin", SO_NONE },
        { 30, "--rmax", SO_NONE },
        { 31, "--removeborder", SO_NONE },
        { 32, "--size", SO_REQ_SEP },
        { 33, "--traceWarp", SO_NONE },
        { 34, "--interval", SO_REQ_SEP },
        { 35, "--zerocrossing", SO_NONE },
        { 36, "--meanwarp", SO_NONE },
        { 41, "--magnitude2", SO_NONE },
        { 42, "--vector2mat", SO_NONE },

        // Experiment #1
        { 37, "--expr1", SO_NONE },
        { 39, "--expr2", SO_NONE },
        { 40, "--bspline2d", SO_NONE },
        { 43, "--particleExpr", SO_NONE },

        // Image Processing
        { 100, "--doGaussian", SO_REQ_SEP },
        { 101, "--doBlur2", SO_NONE },
        { 102, "--ellipse", SO_NONE },
        { 103, "--affineReg", SO_NONE },
        { 104, "--gradhist", SO_NONE },
        { 105, "--testgradreg", SO_NONE },
        { 106, "--gradmag", SO_NONE },
        { 107, "--transform2", SO_NONE },
        { 108, "--boundingbox", SO_NONE },
        { 109, "--crop", SO_REQ_SEP },
        { 110, "--slice", SO_NONE },
        { 111, "--padding", SO_REQ_SEP },
        { 112, "--deform", SO_NONE },
        { 113, "--testdisplacementfield", SO_NONE },
        { 114, "--distmap2contour", SO_NONE },

        // Test Main
        { 200, "--newuoa", SO_NONE },
        { 201, "--boost", SO_NONE },
        { 202, "--testconfig", SO_NONE },

        // Particle Tools
        { 300, "--coverlabel", SO_NONE },
        { 301, "--p2mat", SO_NONE },

        // Options Test
        { 400, "--testjson", SO_NONE },

        // PatchCompare
        { 500, "--demons", SO_NONE },
        { 501, "--makeGradientPatch", SO_NONE },
        { 502, "--opticalFlow", SO_NONE },
        { 503, "--patchtest", SO_NONE },

        SO_END_OF_OPTIONS
    };

    cout << argv[0] << " version compiled at " << __TIMESTAMP__ << endl;
    Options parser;
    parser.ParseOptions(argc, argv, specs);
    StringVector& args = parser.GetStringVector("args");
    string output = parser.GetString("-o", "");

    ParticleSystemSolver solver;
    ParticleSystem& system = solver.m_System;
    Options& options = solver.m_Options;


    srcIdx = atoi(parser.GetString("--srcidx", "1").c_str());
    dstIdx = atoi(parser.GetString("--dstidx", "0").c_str());

    if (parser.GetBool("--run")) {
        executeParticleRunner(parser, args);
        return 0;
    } else if (parser.GetBool("--demons")) {
        executeDemonsRunner(parser, args);
    } else if (parser.GetBool("--expr1")) {
        runExpr1(args);
    } else if (parser.GetBool("--expr2")) {
        runExpr2(args);
    } else if (parser.GetBool("--bspline2d")) {
        runBspline2D(args);
    } else if (parser.GetBool("--vector2mat")) {
        runVector2Mat(args);
    } else if (parser.GetBool("--particleExpr")) {
        runParticleExperiments(args);
    } else if (parser.GetBool("--seeConfig")) {
        solver.LoadConfig(args[0].c_str());
        cout << "Option Contents:\n\n" << options << endl;
        if (args.size() > 1) {
            solver.SaveConfig(args[1].c_str());
        }
    } else if (parser.GetBool("-w", false)) {
        if (args.size() < 1 || output == "") {
            cout << "warping requires [config.txt] -o [outputimage]" << endl;
            return 0;
        }

        // load data
        solver.LoadConfig(args[0].c_str());

        // bspline resampling
        ParticleBSpline particleTransform;
        particleTransform.SetReferenceImage(solver.m_System[0].GetLabel());

        int srcIdx = atoi(parser.GetString("--srcidx", "1").c_str());
        int dstIdx = atoi(parser.GetString("--dstidx", "0").c_str());

        if (parser.GetBool("--mean")) {
            system.ComputeXMeanSubject();
            particleTransform.EstimateTransform(system.GetMeanSubject(), system[srcIdx]);
        } else {
            cout << "warping from " << srcIdx << " to " << dstIdx << endl;
            particleTransform.EstimateTransform(system[dstIdx], system[srcIdx]);
        }


        string input = parser.GetString("--inputimage", "");
        string label = parser.GetString("--inputlabel", "");

        cout << parser << endl;

        bool doingSomething = false;
        if (label != "") {
            // write image
            ImageIO<LabelImage> io;
            LabelImage::Pointer outputImage = particleTransform.WarpLabel(io.ReadImage(label.c_str()));
            io.WriteImage(output.c_str(), outputImage);
            doingSomething = true;
        }
        if (input != "") {
            ImageIO<RealImage> io;
            RealImage::Pointer outputImage = particleTransform.WarpImage(io.ReadImage(input.c_str()));
            io.WriteImage(output.c_str(), outputImage);
            doingSomething = true;
        }
        if (!doingSomething) {
            cout << "-w requires --inputimage or --inputlabel to warp" << endl;
        }
    } else if (parser.GetBool("--warp")) {
        if (args.size() < 2) {
            cout << "--warp requires [output.txt] --inputimage|inputlabel [source-image] --reference [reference] [warped-output-image]" << endl;
            return 0;
        }

        PRINT_IDX();
        string outputName = args[1];
        string inputImage, inputLabel, refImageName;
        parser.GetStringTo("--inputimage", inputImage);
        parser.GetStringTo("--inputlabel", inputLabel);
        parser.GetStringTo("--reference", refImageName);

        solver.LoadConfig(args[0].c_str());


        if (system.size() < 2) {
            cout << "system is not loaded successfully" << endl;
            return 0;
        }
        if (inputImage != "") {
            RealImage::Pointer refImage;
            // warp from srcidx to dstidx
            if (refImageName != "") {
                refImage = realIO.ReadImage(refImageName.c_str());
            }
            RealImage::Pointer output = warp_image<RealImage>(system[dstIdx], system[srcIdx], realIO.ReadImage(inputImage.c_str()), refImage, false, parser.GetBool("--norigidalign"), parser.GetBool("--onlyrigidalign"));
            realIO.WriteImage(outputName.c_str(), output);
        }
        if (inputLabel != "") {
            LabelImage::Pointer refImage;
            // warp from srcidx to dstidx
            if (refImageName != "") {
                refImage = labelIO.ReadImage(refImageName.c_str());
            }
            LabelImage::Pointer output = warp_image<LabelImage>(system[dstIdx], system[srcIdx], labelIO.ReadImage(inputLabel.c_str()), refImage, true, parser.GetBool("--norigidalign"), parser.GetBool("--onlyrigidalign"));
            labelIO.WriteImage(outputName.c_str(), output);
        }
    } else if (parser.GetBool("--meanwarp")) {
        if (args.size() < 2) {
            cout << "--meanwarp requires [output.txt] --inputimage|--inputlabel [source-image] [warped-output-image]" << endl;
            return 0;
        }

        PRINT_IDX();
        string outputName = args[1];
        string inputImage, inputLabel, refImageName;
        parser.GetStringTo("--inputimage", inputImage);
        parser.GetStringTo("--inputlabel", inputLabel);
        parser.GetStringTo("--reference", refImageName);

        solver.LoadConfig(args[0].c_str());


        ParticleSubject meanSubj = system.ComputeXMeanSubject();

        if (system.size() < 2) {
            cout << "system is not loaded successfully" << endl;
            return 0;
        }
        if (inputImage != "") {
            RealImage::Pointer refImage;
            // warp from srcidx to dstidx
            if (refImageName != "") {
                refImage = realIO.ReadImage(refImageName.c_str());
            }
            RealImage::Pointer output = warp_image<RealImage>(meanSubj, system[srcIdx], realIO.ReadImage(inputImage.c_str()), refImage, false, parser.GetBool("--norigidalign"), parser.GetBool("--onlyrigidalign"));
            realIO.WriteImage(outputName.c_str(), output);
        }
        if (inputLabel != "") {
            LabelImage::Pointer refImage;
            // warp from srcidx to dstidx
            if (refImageName != "") {
                refImage = labelIO.ReadImage(refImageName.c_str());
            }
            LabelImage::Pointer output = warp_image<LabelImage>(meanSubj, system[srcIdx], labelIO.ReadImage(inputLabel.c_str()), refImage, true, parser.GetBool("--norigidalign"), parser.GetBool("--onlyrigidalign"));
            labelIO.WriteImage(outputName.c_str(), output);
        }

    } else if (parser.GetBool("--markTrace")) {
        if (args.size() < 2) {
            cout << "--meanwarp requires [output.txt] [reference-image] [output-image] --srcidx [point-index] --srcsubj [subject-index]" << endl;
            return 0;
        }
        ifstream in(args[0].c_str());
        ParticleTrace trace;
        trace.Read(in);
        in.close();
        cout << trace << endl;

        int srcIdx = atoi(parser.GetString("--srcidx", "-1").c_str());
        int srcSubj = atoi(parser.GetString("--srcsubj", "-1").c_str());

        ImageIO<LabelImage> io;
        LabelImage::Pointer ref = io.ReadImage(args[1].c_str());
        LabelImage::Pointer canvas = io.NewImage(ref);
        for (int i = 0; i < trace.system.size(); i++) {
            if (srcSubj == -1 || srcSubj == i) {
                for (int j = 0; j < trace.system[i].timeSeries.size(); j++) {
                    for (int k = 0; k <= trace.system[i].maxIdx; k++) {
                        if (srcIdx == -1 || srcIdx == k) {
                            Particle& p = trace.system[i].timeSeries[j][k];
                            IntIndex idx;
                            fordim (l) {
                                idx[l] = p.x[l] + 0.5;
                            }
                            (*canvas)[idx] = j;
                        }
                    }
                }
            }
        }
    } else if (parser.GetBool("--markOutput")) {
예제 #19
0
파일: emdata_io.cpp 프로젝트: C-CINA/2dx
void EMData::read_image(const string & filename, int img_index, bool nodata,
						const Region * region, bool is_3d)
{
	ENTERFUNC;

	ImageIO *imageio = EMUtil::get_imageio(filename, ImageIO::READ_ONLY);

	if (!imageio) {
		throw ImageFormatException("cannot create an image io");
	}
	else {
		int err = imageio->read_header(attr_dict, img_index, region, is_3d);
		if (err) {
			throw ImageReadException(filename, "imageio read header failed");
		}
		else {
			LstIO * myLstIO = dynamic_cast<LstIO *>(imageio);
			if(!myLstIO)	attr_dict["source_path"] = filename;	//"source_path" is set to full path of reference image for LstIO, so skip this statement
			attr_dict["source_n"] = img_index;
			if (imageio->is_complex_mode()) {
				set_complex(true);
				set_fftpad(true);
			}
			if (attr_dict.has_key("is_fftodd") && (int)attr_dict["is_fftodd"] == 1) {
				set_fftodd(true);
			}
			if ((int) attr_dict["is_complex_ri"] == 1) {
				set_ri(true);
			}
			save_byteorder_to_dict(imageio);

			nx = attr_dict["nx"];
			ny = attr_dict["ny"];
			nz = attr_dict["nz"];
			attr_dict.erase("nx");
			attr_dict.erase("ny");
			attr_dict.erase("nz");

			if (!nodata) {

				if (region) {
					nx = (int)region->get_width();
					if (nx <= 0) nx = 1;
					ny = (int)region->get_height();
					if (ny <= 0) ny = 1;
					nz = (int)region->get_depth();
					if (nz <= 0) nz = 1;
					set_size(nx,ny,nz);
					to_zero(); // This could be avoided in favor of setting only the regions that were not read to to zero... but tedious
				} // else the dimensions of the file being read match those of this
				else {
					set_size(nx, ny, nz);
				}

				// If GPU features are enabled there is  danger that rdata will
				// not be allocated, but set_size takes care of this, so this
				// should be safe.
				int err = imageio->read_data(get_data(), img_index, region, is_3d);
				if (err) {
					throw ImageReadException(filename, "imageio read data failed");
				}
				else {
					update();
				}
			}
			else {
				if (rdata!=0) EMUtil::em_free(rdata);
				rdata=0;
			}
				
		}
	}

#ifndef IMAGEIO_CACHE
	if( imageio )
	{
#ifdef HDFIO_CACHE
		if(dynamic_cast<HdfIO2*>(imageio)==NULL && dynamic_cast<HdfIO*>(imageio)==NULL) {
#endif	//HDFIO_CACHE
			delete imageio;
			imageio = 0;
#ifdef HDFIO_CACHE
		}
#endif	//HDFIO_CACHE
	}
#endif	//IMAGEIO_CACHE

	EXITFUNC;
}
예제 #20
0
// perform B-spline registration for 2D image
void runBspline2D(StringVector& args) {
    typedef itk::BSplineTransform<double, 2, 3> TransformType;
    typedef itk::LBFGSOptimizer OptimizerType;
    typedef itk::MeanSquaresImageToImageMetric<RealImage2, RealImage2> MetricType;
    typedef itk:: LinearInterpolateImageFunction<RealImage2, double> InterpolatorType;
    typedef itk::ImageRegistrationMethod<RealImage2, RealImage2> RegistrationType;

    MetricType::Pointer         metric        = MetricType::New();
    OptimizerType::Pointer      optimizer     = OptimizerType::New();
    InterpolatorType::Pointer   interpolator  = InterpolatorType::New();
    RegistrationType::Pointer   registration  = RegistrationType::New();

    // The old registration framework has problems with multi-threading
    // For now, we set the number of threads to 1
    registration->SetNumberOfThreads(1);

    registration->SetMetric(        metric        );
    registration->SetOptimizer(     optimizer     );
    registration->SetInterpolator(  interpolator  );

    TransformType::Pointer  transform = TransformType::New();
    registration->SetTransform( transform );


    ImageIO<RealImage2> io;

    // Create the synthetic images
    RealImage2::Pointer  fixedImage  = io.ReadImage(args[0]);
    RealImage2::Pointer  movingImage  = io.ReadImage(args[1]);

    // Setup the registration
    registration->SetFixedImage(  fixedImage   );
    registration->SetMovingImage(   movingImage);

    RealImage2::RegionType fixedRegion = fixedImage->GetBufferedRegion();
    registration->SetFixedImageRegion( fixedRegion );

    TransformType::PhysicalDimensionsType   fixedPhysicalDimensions;
    TransformType::MeshSizeType             meshSize;
    for( unsigned int i=0; i < 2; i++ )
    {
        fixedPhysicalDimensions[i] = fixedImage->GetSpacing()[i] *
        static_cast<double>(
                            fixedImage->GetLargestPossibleRegion().GetSize()[i] - 1 );
    }
    unsigned int numberOfGridNodesInOneDimension = 18;
    meshSize.Fill( numberOfGridNodesInOneDimension - 3 );
    transform->SetTransformDomainOrigin( fixedImage->GetOrigin() );
    transform->SetTransformDomainPhysicalDimensions( fixedPhysicalDimensions );
    transform->SetTransformDomainMeshSize( meshSize );
    transform->SetTransformDomainDirection( fixedImage->GetDirection() );

    typedef TransformType::ParametersType     ParametersType;

    const unsigned int numberOfParameters =
    transform->GetNumberOfParameters();

    ParametersType parameters( numberOfParameters );

    parameters.Fill( 0.0 );

    transform->SetParameters( parameters );

    //  We now pass the parameters of the current transform as the initial
    //  parameters to be used when the registration process starts.

    registration->SetInitialTransformParameters( transform->GetParameters() );

    std::cout << "Intial Parameters = " << std::endl;
    std::cout << transform->GetParameters() << std::endl;

    //  Next we set the parameters of the LBFGS Optimizer.

    optimizer->SetGradientConvergenceTolerance( 0.005 );
    optimizer->SetLineSearchAccuracy( 0.9 );
    optimizer->SetDefaultStepLength( .1 );
    optimizer->TraceOn();
    optimizer->SetMaximumNumberOfFunctionEvaluations( 1000 );

    std::cout << std::endl << "Starting Registration" << std::endl;

    try
    {
        registration->Update();
        std::cout << "Optimizer stop condition = "
        << registration->GetOptimizer()->GetStopConditionDescription()
        << std::endl;
    }
    catch( itk::ExceptionObject & err )
    {
        std::cerr << "ExceptionObject caught !" << std::endl;
        std::cerr << err << std::endl;
        return;
    }

    OptimizerType::ParametersType finalParameters =
    registration->GetLastTransformParameters();

    std::cout << "Last Transform Parameters" << std::endl;
    std::cout << finalParameters << std::endl;

    transform->SetParameters( finalParameters );

    typedef itk::ResampleImageFilter<RealImage2, RealImage2> ResampleFilterType;

    ResampleFilterType::Pointer resample = ResampleFilterType::New();

    resample->SetTransform( transform );
    resample->SetInput( movingImage );

    resample->SetSize(    fixedImage->GetLargestPossibleRegion().GetSize() );
    resample->SetOutputOrigin(  fixedImage->GetOrigin() );
    resample->SetOutputSpacing( fixedImage->GetSpacing() );
    resample->SetOutputDirection( fixedImage->GetDirection() );
    resample->SetDefaultPixelValue( 100 );
    resample->Update();

    io.WriteImage(args[2], resample->GetOutput());
}
예제 #21
0
/// perform scan conversion
/// [input-vtk] [reference-image] [output-image]
///
int runScanConversion(pi::Options& opts, pi::StringVector& args) {
    vtkPolyDataReader* reader = vtkPolyDataReader::New();
    reader->SetFileName(args[0].c_str());
    reader->Update();

    vtkPolyData*pd = reader->GetOutput();

    // point flipping
    for (int i = 0; i < pd->GetNumberOfPoints(); i++) {
        double p[3];
        pd->GetPoint(i, p);
        p[0] = -p[0];
        p[1] = -p[1];
        pd->GetPoints()->SetPoint(i, p);
    }

    vtkSmartPointer<vtkImageData> whiteImage = vtkSmartPointer<vtkImageData>::New();

    ImageIO<RealImage> imageIO;
    RealImage::Pointer refImage = imageIO.ReadImage(args[1].c_str());


    // compute bounding box
    RealImage::RegionType region = refImage->GetBufferedRegion();
    RealImage::IndexType lowerIndex = region.GetIndex();
    RealImage::IndexType upperIndex = region.GetUpperIndex();

    RealImage::PointType lowerPoint, upperPoint;
    refImage->TransformIndexToPhysicalPoint(lowerIndex, lowerPoint);
    refImage->TransformIndexToPhysicalPoint(upperIndex, upperPoint);

    // mesh bounds
    double bounds[6];

    // image bounds
    bounds[0] = lowerPoint[0];
    bounds[1] = upperPoint[0];
    bounds[2] = lowerPoint[1];
    bounds[3] = upperPoint[1];
    bounds[4] = lowerPoint[2];
    bounds[5] = upperPoint[2];


    // print bounds
    for (int i = 0; i < 6; i++) {
        cout << bounds[i] << ", ";
    }
    cout << endl;


    // make the same spacing as refImage
    double spacing[3]; // desired volume spacing
    for (int i = 0; i < 3; i++) {
        spacing[i] = refImage->GetSpacing()[i];
    }
    whiteImage->SetSpacing(spacing);

    // compute dimensions
    int dim[3];
    for (int i = 0; i < 3; i++)
    {
        dim[i] = static_cast<int>(ceil((bounds[i * 2 + 1] - bounds[i * 2]) / spacing[i])) + 1;
    }
    whiteImage->SetDimensions(dim);
    whiteImage->SetExtent(0, dim[0] - 1, 0, dim[1] - 1, 0, dim[2] - 1);

    double origin[3];
    origin[0] = bounds[0] + spacing[0] / 2;
    origin[1] = bounds[2] + spacing[1] / 2;
    origin[2] = bounds[4] + spacing[2] / 2;
    whiteImage->SetOrigin(origin);

#if VTK_MAJOR_VERSION <= 5
    whiteImage->SetScalarTypeToUnsignedChar();
    whiteImage->AllocateScalars();
#else
    whiteImage->AllocateScalars(VTK_UNSIGNED_CHAR,1);
#endif
    // fill the image with foreground voxels:
    unsigned char inval = 255;
    unsigned char outval = 0;
    vtkIdType count = whiteImage->GetNumberOfPoints();
    for (vtkIdType i = 0; i < count; ++i)
    {
        whiteImage->GetPointData()->GetScalars()->SetTuple1(i, inval);
    }

    // polygonal data --> image stencil:
    vtkSmartPointer<vtkPolyDataToImageStencil> pol2stenc =
    vtkSmartPointer<vtkPolyDataToImageStencil>::New();
#if VTK_MAJOR_VERSION <= 5
    pol2stenc->SetInput(pd);
#else
    pol2stenc->SetInputData(pd);
#endif
    pol2stenc->SetOutputOrigin(origin);
    pol2stenc->SetOutputSpacing(spacing);
    pol2stenc->SetOutputWholeExtent(whiteImage->GetExtent());
    pol2stenc->Update();

    // cut the corresponding white image and set the background:
    vtkSmartPointer<vtkImageStencil> imgstenc =
    vtkSmartPointer<vtkImageStencil>::New();
#if VTK_MAJOR_VERSION <= 5
    imgstenc->SetInput(whiteImage);
    imgstenc->SetStencil(pol2stenc->GetOutput());
#else
    imgstenc->SetInputData(whiteImage);
    imgstenc->SetStencilConnection(pol2stenc->GetOutputPort());
#endif
    imgstenc->ReverseStencilOff();
    imgstenc->SetBackgroundValue(outval);
    imgstenc->Update();

    vtkSmartPointer<vtkMetaImageWriter> writer =
    vtkSmartPointer<vtkMetaImageWriter>::New();
    writer->SetFileName("SphereVolume.mhd");
#if VTK_MAJOR_VERSION <= 5
    writer->SetInput(imgstenc->GetOutput());
#else
    writer->SetInputData(imgstenc->GetOutput());
#endif
    writer->Write();
    
    return EXIT_SUCCESS;
}
예제 #22
0
파일: kcalc.cpp 프로젝트: fayhot/gradworks
int main(int argc, char* argv[]) {
    Options argParser;
    argParser.addOption("-i", "print image information as ImageStat --info option", SO_NONE);
    argParser.addOption("-e", "The equation to compute each output pixel.", "-e (A+B)", SO_REQ_SEP);
    argParser.addOption("-o", "output filename (the same data type with the last input)", "-o output.nrrd", SO_REQ_SEP);
    argParser.addOption("-h", "print this message", SO_NONE);

    StringVector args = argParser.ParseOptions(argc, argv, NULL);
    string eq = argParser.GetString("-e");
    string outputFilename = argParser.GetString("-o");
    
    if (argParser.GetBool("-i") && args.size() > 0) {
        ImageInfo lastImageInfo;
        imgIo.ReadCastedImage(args[0], lastImageInfo);
        printf("Filename: %s\n", args[0].c_str());
        printf("Dims: %d %d %d\n", lastImageInfo.dimensions[0], lastImageInfo.dimensions[1], lastImageInfo.dimensions[2]);
        printf("Pixdims: %.2f %.2f %.2f\n", lastImageInfo.spacing[0], lastImageInfo.spacing[1], lastImageInfo.spacing[2]);
        printf("Origins: %.2f %.2f %.2f\n", lastImageInfo.origin[0], lastImageInfo.origin[1], lastImageInfo.origin[2]);
        return 0;
    }

    if (argParser.GetBool("-h") || eq == "" || args.size() == 0 || outputFilename == "") {
        cout << "## kcalc usage \n"
            "\tkcalc [-e equation] [-o output-file] input1:A input2:B ...\n\n"
            "The kcalc performs a pixel-wise arithmetic. The pixel value of each input image is given as variables, A,B,C,D, and E. Several functions implemented in [MuParser](http://muparser.beltoforion.de/) includes +,-,*,/, and ? as well as trigonometric functions.\n\n"
            "Also, there are the min, max values of each input image for the use of scaling and other purposes, which are given as AMIN, AMAX, BMIN, BMAX, and etc.\n\n"
            "Note that the output data type is the same with the last input file. The order of images may produce different results, if images with different types are used.\n\n"
            "Some examples are:\n"
            "* **Addition**: kcalc -e \"(A+B)\" input1.nrrd input2.nrrd -o output.nrrd\n"
            "* **Averaging**: kcalc -e \"(A+B)/2\" input1.nrrd input2.nrrd -o output.nrrd\n"
            "* **Thresholding**: kcalc -e \"(A>10?1:0)\" input.nrrd -o output.nrrd\n"
            "* **Scaling**: -e (A-AMIN)/AMAX*255\n"
            "* **Masking**: -e (A==8?B:0)\n"
            "* ...\n\n"
            "### Options\n";
        argParser.PrintUsage();
        cout << endl;
        return 0;
    }

    if (argParser.GetBool("-2")) {
        cout << "Working on 2D images" << endl;
        ImageIO<Image2D> io2;
        ImageInfo lastImageInfo;
        PixelMathImageFilter<Image2D, Image2D>::Pointer pixelFilter = PixelMathImageFilter<Image2D, Image2D>::New();
        pixelFilter->SetEquation(eq);
        for (int i = 0; i < args.size(); i++) {
            pixelFilter->PushBackInput(io2.ReadCastedImage(args[i], lastImageInfo));
        }
        try {
            pixelFilter->Update();
        } catch (itk::ExceptionObject& e) {
            cout << e.what() << endl;
        }
        io2.WriteCastedImage(outputFilename, pixelFilter->GetOutput(), lastImageInfo.componenttype);
    } else {
        ImageInfo lastImageInfo;
        PixelMathImageFilter<ImageType, ImageType>::Pointer pixelFilter = PixelMathImageFilter<ImageType, ImageType>::New();
        pixelFilter->SetEquation(eq);
        for (int i = 0; i < args.size(); i++) {
            pixelFilter->PushBackInput(imgIo.ReadCastedImage(args[i], lastImageInfo));
        }
        try {
            pixelFilter->Update();
        } catch (itk::ExceptionObject& e) {
            cout << e.what() << endl;
        }

        imgIo.WriteCastedImage(outputFilename, pixelFilter->GetOutput(), lastImageInfo.componenttype);
    }
    return 0;
}
예제 #23
0
void Image::save(const std::string& filename) const
{
    ImageIO iio;
    iio.save(*this, filename);
}