38 #include <vtkImageData.h> 56 mPatientModelService(patientModelService)
68 std::vector<std::vector<vtkImageDataPtr> > frames = mFileData.
mUsRaw->initializeFrames(angio);
70 std::vector<ProcessedUSInputDataPtr> retval;
72 for (
unsigned i=0; i<angio.size(); ++i)
79 QFileInfo(mFileData.
mFilename).completeBaseName() ));
80 CX_ASSERT(Eigen::Array3i(frames[i][0]->GetDimensions()).isApprox(Eigen::Array3i(mFileData.
getMask()->GetDimensions())));
81 retval.push_back(input);
88 bool within(
int x,
int min,
int max)
90 return (x >= min) && (x <= max);
103 void ReconstructPreprocessor::calibrateTimeStamps(
double offset,
double scale)
105 for (
unsigned int i = 0; i < mFileData.
mPositions.size(); i++)
117 void ReconstructPreprocessor::alignTimeSeries()
119 report(
"Generate time calibration based on input time stamps.");
120 double framesSpan = mFileData.
mFrames.back().mTime - mFileData.
mFrames.front().mTime;
122 double scale = framesSpan / positionsSpan;
124 double offset = mFileData.
mFrames.front().mTime - scale * mFileData.
mPositions.front().mTime;
126 this->calibrateTimeStamps(offset, scale);
132 void ReconstructPreprocessor::cropInputData()
137 cropbox = this->reduceCropboxToImageSize(cropbox, sector.
getSize());
138 Eigen::Vector3i shift = cropbox.
corner(0,0,0).cast<
int>();
139 Eigen::Vector3i size = cropbox.range().cast<
int>() + Eigen::Vector3i(1,1,0);
140 mFileData.
mUsRaw->setCropBox(cropbox);
145 for (
unsigned i=0; i<3; ++i)
147 clipRect_p[2*i] -= shift[i];
148 clipRect_p[2*i+1] -= shift[i];
149 origin_p[i] -= shift[i];
154 sector.
setSize(QSize(size[0], size[1]));
160 cropbox[0] = std::max(cropbox[0], 0);
161 cropbox[2] = std::max(cropbox[2], 0);
162 cropbox[4] = std::max(cropbox[4], 0);
164 cropbox[1] = std::min(cropbox[1], size.width() - 1);
165 cropbox[3] = std::min(cropbox[3], size.height() - 1);
179 void ReconstructPreprocessor::applyTimeCalibration()
189 this->calibrateTimeStamps(timeshift, 1.0);
194 this->alignTimeSeries();
202 void add(
double _err) { ++count; err=((err<0)?_err:std::min(_err, err)); }
213 void ReconstructPreprocessor::interpolatePositions()
215 mFileData.mUsRaw->resetRemovedFrames();
216 int startFrames = mFileData.mFrames.size();
218 std::map<int,RemoveDataType> removedData;
220 for (
unsigned i_frame = 0; i_frame < mFileData.mFrames.size();)
222 std::vector<TimedPosition>::iterator posIter;
223 posIter = lower_bound(mFileData.mPositions.begin(), mFileData.mPositions.end(), mFileData.mFrames[i_frame]);
225 unsigned i_pos = distance(mFileData.mPositions.begin(), posIter);
229 if (i_pos >= mFileData.mPositions.size() - 1)
230 i_pos = mFileData.mPositions.size() - 2;
234 double timeToPos1 = timeToPosition(i_frame, i_pos);
235 double timeToPos2 = timeToPosition(i_frame, i_pos+1);
236 if ((timeToPos1 > mMaxTimeDiff) || (timeToPos2 > mMaxTimeDiff))
238 removedData[i_frame].add(std::max(timeToPos1, timeToPos2));
240 mFileData.mFrames.erase(mFileData.mFrames.begin() + i_frame);
241 mFileData.mUsRaw->removeFrame(i_frame);
245 double t_delta_tracking = mFileData.mPositions[i_pos + 1].mTime - mFileData.mPositions[i_pos].mTime;
247 if (!
similar(t_delta_tracking, 0))
248 t = (mFileData.mFrames[i_frame].mTime - mFileData.mPositions[i_pos].mTime) / t_delta_tracking;
256 for (std::map<int,RemoveDataType>::iterator iter=removedData.begin(); iter!=removedData.end(); ++iter)
258 int first = iter->first+removeCount;
259 int last = first + iter->second.count-1;
260 report(QString(
"Removed input frame [%1-%2]. Time diff=%3").arg(first).arg(last).arg(iter->second.err, 0,
'f', 1));
261 removeCount += iter->second.count;
264 double removed = double(startFrames - mFileData.mFrames.size()) /
double(startFrames);
267 double percent = removed * 100;
274 report(
"Removed " + QString::number(percent,
'f', 1) +
"% of the " +
qstring_cast(startFrames) +
" frames.");
280 double ReconstructPreprocessor::timeToPosition(
unsigned i_frame,
unsigned i_pos)
282 return fabs(mFileData.mFrames[i_frame].mTime - mFileData.mPositions[i_pos].mTime);
288 std::vector<Vector3D> ReconstructPreprocessor::generateInputRectangle()
290 std::vector<Vector3D> retval(4);
294 reportError(
"Reconstructer::generateInputRectangle() + requires mask");
297 Eigen::Array3i dims = mFileData.mUsRaw->getDimensions();
298 Vector3D spacing = mFileData.mUsRaw->getSpacing();
300 Eigen::Array3i maskDims(mask->GetDimensions());
302 if (( maskDims[0]<dims[0] )||( maskDims[1]<dims[1] ))
303 reportError(QString(
"input data (%1) and mask (%2) dim mimatch")
307 int xmin = maskDims[0];
309 int ymin = maskDims[1];
312 unsigned char* ptr =
static_cast<unsigned char*
> (mask->GetScalarPointer());
313 for (
int x = 0; x < maskDims[0]; x++)
314 for (
int y = 0; y < maskDims[1]; y++)
316 unsigned char val = ptr[x + y * maskDims[0]];
319 xmin = std::min(xmin, x);
320 ymin = std::min(ymin, y);
321 xmax = std::max(xmax, x);
322 ymax = std::max(ymax, y);
328 double red = mInput.mMaskReduce;
329 int reduceX = (xmax - xmin) * (red / 100);
330 int reduceY = (ymax - ymin) * (red / 100);
337 retval[0] =
Vector3D(xmin * spacing[0], ymin * spacing[1], 0);
338 retval[1] =
Vector3D(xmax * spacing[0], ymin * spacing[1], 0);
339 retval[2] =
Vector3D(xmin * spacing[0], ymax * spacing[1], 0);
340 retval[3] =
Vector3D(xmax * spacing[0], ymax * spacing[1], 0);
351 Transform3D ReconstructPreprocessor::applyOutputOrientation()
355 if (mInput.mOrientation ==
"PatientReference")
359 else if (mInput.mOrientation ==
"MiddleFrame")
361 prMdd = mFileData.mFrames[mFileData.mFrames.size() / 2].mPos;
365 reportError(
"no orientation algorithm selected in reconstruction");
370 for (
unsigned i = 0; i < mFileData.mFrames.size(); i++)
373 mFileData.mFrames[i].mPos = ddMpr * mFileData.mFrames[i].mPos;
389 void ReconstructPreprocessor::findExtentAndOutputTransform()
391 if (mFileData.mFrames.empty())
394 Transform3D prMdd = this->applyOutputOrientation();
398 std::vector<Vector3D> inputRect = this->generateInputRectangle();
399 std::vector<Vector3D> outputRect;
400 for (
unsigned slice = 0; slice < mFileData.mFrames.size(); slice++)
403 for (
unsigned i = 0; i < inputRect.size(); i++)
405 outputRect.push_back(dMu.coord(inputRect[i]));
414 for (
unsigned i = 0; i < mFileData.mFrames.size(); i++)
416 mFileData.mFrames[i].mPos = T_origo.inv() * mFileData.mFrames[i].mPos;
420 double inputSpacing = std::min(mFileData.mUsRaw->getSpacing()[0], mFileData.mUsRaw->getSpacing()[1]);
421 mOutputVolumeParams =
OutputVolumeParams(extent, inputSpacing, mInput.mMaxOutputVolumeSize);
423 mOutputVolumeParams.set_rMd((mPatientModelService->get_rMpr()) * prMd);
429 void ReconstructPreprocessor::updateFromOriginalFileData()
432 this->cropInputData();
440 this->applyTimeCalibration();
445 this->interpolatePositions();
448 if (mFileData.mFrames.empty())
451 this->findExtentAndOutputTransform();
458 mFileData = fileData;
459 this->updateFromOriginalFileData();
QString qstring_cast(const T &val)
void reportError(QString msg)
Vector3D corner(int x, int y, int z) const
#define CX_ASSERT(statement)
Transform3D Transform3D
Transform3D is a representation of an affine 3D transform.
Helper struct for sending and controlling output volume properties.
static DoubleBoundingBox3D fromCloud(std::vector< Vector3D > cloud)
Vector3D getOrigin_p() const
void setOrigin_p(Vector3D origin_p)
ReconstructPreprocessor(PatientModelServicePtr patientModelService)
void reportWarning(QString msg)
void setClipRect_p(DoubleBoundingBox3D clipRect_p)
boost::shared_ptr< class PatientModelService > PatientModelServicePtr
virtual ~ReconstructPreprocessor()
Transform3D createTransformTranslate(const Vector3D &translation)
std::vector< ProcessedUSInputDataPtr > createProcessedInput(std::vector< bool > angio)
Representation of an integer bounding box in 3D. The data are stored as {xmin,xmax,ymin,ymax,zmin,zmax}, in order to simplify communication with vtk.
Representation of a floating-point bounding box in 3D. The data are stored as {xmin,xmax,ymin,ymax,zmin,zmax}, in order to simplify communication with vtk.
Eigen::Vector3d Vector3D
Vector3D is a representation of a point or vector in 3D.
Definition of characteristics for an Ultrasound Probe Sector.
Eigen::Vector3i corner(int x, int y, int z) const
bool similar(const CameraInfo &lhs, const CameraInfo &rhs, double tol)
DoubleBoundingBox3D getClipRect_p() const
boost::shared_ptr< class ProcessedUSInputData > ProcessedUSInputDataPtr
void initialize(ReconstructCore::InputParams input, USReconstructInputData fileData)
Algorithm part of reconstruction - no dependencies on parameter classes.
void setData(ProbeDefinition data)
Namespace for all CustusX production code.