/*========================================================================= * * Copyright NumFOCUS * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0.txt * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *=========================================================================*/ #define ITK_TEMPLATE_EXPLICIT_TxtTransformIO #include "itkTxtTransformIO.h" #include "itksys/SystemTools.hxx" #include "vnl/vnl_matlab_read.h" #include "vnl/vnl_matlab_write.h" #include "itkTransformFileReader.h" #include "itkCompositeTransform.h" #include "itkCompositeTransformIOHelper.h" #include "itkNumberToString.h" #include namespace itk { template TxtTransformIOTemplate::TxtTransformIOTemplate() = default; template TxtTransformIOTemplate::~TxtTransformIOTemplate() = default; template bool TxtTransformIOTemplate::CanReadFile(const char * fileName) { bool recognizedExtension = false; recognizedExtension |= (itksys::SystemTools::GetFilenameLastExtension(fileName) == ".txt"); recognizedExtension |= (itksys::SystemTools::GetFilenameLastExtension(fileName) == ".tfm"); return recognizedExtension; } template bool TxtTransformIOTemplate::CanWriteFile(const char * fileName) { bool recognizedExtension = false; recognizedExtension |= (itksys::SystemTools::GetFilenameLastExtension(fileName) == ".txt"); recognizedExtension |= (itksys::SystemTools::GetFilenameLastExtension(fileName) == ".tfm"); return recognizedExtension; } template std::string TxtTransformIOTemplate::trim(std::string const & source, char const * delims) { std::string result(source); std::string::size_type index = result.find_last_not_of(delims); if (index != std::string::npos) { result.erase(++index); } index = result.find_first_not_of(delims); if (index != std::string::npos) { result.erase(0, index); } else { result.erase(); } return result; } template void TxtTransformIOTemplate::ReadComponentFile(std::string Value) { /* Used for reading component files listed in a composite transform * file, which should be read by CompositeTransformReader for assembly * into a CompositeTransform. * The component filenames are listed w/out paths, and are expected * to be in the same path as the master file. */ std::string filePath = itksys::SystemTools::GetFilenamePath(this->GetFileName()) + "/"; /* Use TransformFileReader to read each component file. */ typename TransformFileReaderTemplate::Pointer reader = TransformFileReaderTemplate::New(); std::string componentFullPath = filePath + Value; reader->SetFileName(componentFullPath); try { reader->Update(); } catch (const itk::ExceptionObject & ex) { itkExceptionMacro("Error reading component file: " << Value << std::endl << ex); } TransformPointer transform = reader->GetTransformList()->front().GetPointer(); this->GetReadTransformList().push_back(transform); } template void TxtTransformIOTemplate::Read() { TransformPointer transform; std::ifstream in; in.open(this->GetFileName(), std::ios::in | std::ios::binary); if (in.fail()) { in.close(); itkExceptionMacro("The file could not be opened for read access " << std::endl << "Filename: \"" << this->GetFileName() << '"'); } itkDebugMacro("Read file transform Data"); // Read line by line typename TransformType::ParametersType VectorBuffer; typename TransformType::ParametersType TmpParameterArray; TmpParameterArray.clear(); typename TransformType::FixedParametersType TmpFixedParameterArray; TmpFixedParameterArray.clear(); bool haveFixedParameters = false; bool haveParameters = false; std::string line; while (std::getline(in, line)) { line = trim(line); itkDebugMacro("Found line: \"" << line << '"'); if (line.length() == 0) { continue; } if (line[0] == '#' || std::string::npos == line.find_first_not_of(" \t")) { // Skip lines beginning with #, or blank lines continue; } // Get the name const std::string::size_type end = line.find(":"); if (end == std::string::npos) { // Throw an error itkExceptionMacro("Tags must be delimited by :"); } std::string Name = trim(line.substr(0, end)); std::string Value = trim(line.substr(end + 1, line.length())); // Push back itkDebugMacro("Name: \"" << Name << '"'); itkDebugMacro("Value: \"" << Value << '"'); std::istringstream parse(Value); VectorBuffer.clear(); if (Name == "Transform") { // Transform name should be modified to have the output precision type. Superclass::CorrectTransformPrecisionType(Value); this->CreateTransform(transform, Value); this->GetReadTransformList().push_back(transform); } else if (Name == "ComponentTransformFile") { /* Used by CompositeTransform file */ ReadComponentFile(Value); } else if (Name == "Parameters" || Name == "FixedParameters") { VectorBuffer.clear(); // Read them parse >> VectorBuffer; itkDebugMacro("Parsed: " << VectorBuffer); if (Name == "Parameters") { TmpParameterArray = VectorBuffer; itkDebugMacro("Setting Parameters: " << TmpParameterArray); if (haveFixedParameters) { transform->SetFixedParameters(TmpFixedParameterArray); itkDebugMacro("Set Transform Fixed Parameters"); transform->SetParametersByValue(TmpParameterArray); itkDebugMacro("Set Transform Parameters"); TmpParameterArray.clear(); TmpFixedParameterArray.clear(); haveFixedParameters = false; haveParameters = false; } else { haveParameters = true; } } else if (Name == "FixedParameters") { TmpFixedParameterArray = VectorBuffer; itkDebugMacro("Setting Fixed Parameters: " << TmpFixedParameterArray); if (!transform) { itkExceptionMacro("Please set the transform before parameters" "or fixed parameters"); } if (haveParameters) { transform->SetFixedParameters(TmpFixedParameterArray); itkDebugMacro("Set Transform Fixed Parameters"); transform->SetParametersByValue(TmpParameterArray); itkDebugMacro("Set Transform Parameters"); TmpParameterArray.clear(); TmpFixedParameterArray.clear(); haveFixedParameters = false; haveParameters = false; } else { haveFixedParameters = true; } } } } } namespace itk_impl_details { template inline void print_vector(std::ofstream & s, vnl_vector const & v) { for (unsigned int i = 0; i + 1 < v.size(); ++i) { s << ConvertNumberToString(v[i]) << ' '; } if (!v.empty()) { s << ConvertNumberToString(v.back()); } } } // namespace itk_impl_details template void TxtTransformIOTemplate::Write() { ConstTransformListType & transformList = this->GetWriteTransformList(); std::ofstream out; this->OpenStream(out, false); out << "#Insight Transform File V1.0" << std::endl; const std::string CompositeTransformTypeName = transformList.front()->GetTransformTypeAsString(); // // if the first transform in the list is a // composite transform, use its internal list // instead of the IO CompositeTransformIOHelperTemplate helper; if (CompositeTransformTypeName.find("CompositeTransform") != std::string::npos) { transformList = helper.GetTransformList(transformList.front().GetPointer()); } int count = 0; typename ConstTransformListType::const_iterator end = transformList.end(); for (typename ConstTransformListType::const_iterator it = transformList.begin(); it != end; ++it, ++count) { const std::string TransformTypeName = (*it)->GetTransformTypeAsString(); out << "#Transform " << count << std::endl << "Transform: " << (*it)->GetTransformTypeAsString() << std::endl; // // Composite Transforms are not written out with parameters; // their parameters are the union of all their component // transforms' parameters. if (TransformTypeName.find("CompositeTransform") != std::string::npos) { if (count > 0) { itkExceptionMacro("Composite Transform can only be 1st transform in a file"); } } else { { vnl_vector TempArray = (*it)->GetParameters(); out << "Parameters: "; // << TempArray << std::endl; itk_impl_details::print_vector(out, TempArray); out << std::endl; } { vnl_vector FixedTempArray = (*it)->GetFixedParameters(); out << "FixedParameters: "; // << FixedTempArray << std::endl; itk_impl_details::print_vector(out, FixedTempArray); out << std::endl; } } } out.close(); } ITK_GCC_PRAGMA_DIAG_PUSH() ITK_GCC_PRAGMA_DIAG(ignored "-Wattributes") template class ITKIOTransformInsightLegacy_EXPORT TxtTransformIOTemplate; template class ITKIOTransformInsightLegacy_EXPORT TxtTransformIOTemplate; ITK_GCC_PRAGMA_DIAG_POP() } // end namespace itk