17 #include <vtkImageData.h> 38 mPatientModelService(patientModelService)
53 std::vector<std::vector<vtkImageDataPtr> > frames = mFileData.
mUsRaw->initializeFrames(angio);
55 std::vector<ProcessedUSInputDataPtr> retval;
57 for (
unsigned i=0; i<angio.size(); ++i)
64 QFileInfo(mFileData.
mFilename).completeBaseName() ));
65 CX_ASSERT(Eigen::Array3i(frames[i][0]->GetDimensions()).isApprox(Eigen::Array3i(mFileData.
getMask()->GetDimensions())));
66 retval.push_back(input);
73 bool within(
int x,
int min,
int max)
75 return (x >= min) && (x <= max);
88 void ReconstructPreprocessor::calibrateTimeStamps(
double offset,
double scale)
90 for (
unsigned int i = 0; i < mFileData.
mPositions.size(); i++)
102 void ReconstructPreprocessor::alignTimeSeries()
104 report(
"Generate time calibration based on input time stamps.");
105 double framesSpan = mFileData.
mFrames.back().mTime - mFileData.
mFrames.front().mTime;
107 double scale = framesSpan / positionsSpan;
109 double offset = mFileData.
mFrames.front().mTime - scale * mFileData.
mPositions.front().mTime;
111 this->calibrateTimeStamps(offset, scale);
117 void ReconstructPreprocessor::cropInputData()
122 cropbox = this->reduceCropboxToImageSize(cropbox, sector.
getSize());
123 Eigen::Vector3i shift = cropbox.
corner(0,0,0).cast<
int>();
124 Eigen::Vector3i size = cropbox.range().cast<
int>() + Eigen::Vector3i(1,1,0);
125 mFileData.
mUsRaw->setCropBox(cropbox);
130 for (
unsigned i=0; i<3; ++i)
132 clipRect_p[2*i] -= shift[i];
133 clipRect_p[2*i+1] -= shift[i];
134 origin_p[i] -= shift[i];
139 sector.
setSize(QSize(size[0], size[1]));
145 cropbox[0] = std::max(cropbox[0], 0);
146 cropbox[2] = std::max(cropbox[2], 0);
147 cropbox[4] = std::max(cropbox[4], 0);
149 cropbox[1] = std::min(cropbox[1], size.width() - 1);
150 cropbox[3] = std::min(cropbox[3], size.height() - 1);
164 void ReconstructPreprocessor::applyTimeCalibration()
174 this->calibrateTimeStamps(timeshift, 1.0);
179 this->alignTimeSeries();
187 void add(
double _err) { ++count; err=((err<0)?_err:std::min(_err, err)); }
192 void ReconstructPreprocessor::filterPositions()
194 int filterStrength = mInput.mPosFilterStrength;
196 if (filterStrength > 0)
198 int filterLength(1+2*filterStrength);
199 int nPositions(mFileData.mPositions.size());
200 if (nPositions > filterLength)
203 int nQuaternions = nPositions+(2*filterStrength);
204 Eigen::ArrayXXd qPosArray(7,nQuaternions);
207 for (
unsigned int i = 0; i < nQuaternions; i++)
209 unsigned int sourceIdx = (i > filterStrength) ? (i-filterStrength) : 0;
210 sourceIdx = (sourceIdx < nPositions) ? sourceIdx : (nPositions-1);
215 Eigen::ArrayXXd qPosFiltered = Eigen::ArrayXXd::Zero(7,nPositions);
216 for (
unsigned int i = 0; i < filterLength; i++)
218 qPosFiltered = qPosFiltered + qPosArray.block(0,i,7,nPositions);
220 qPosFiltered = qPosFiltered / filterLength;
223 for (
unsigned int i = 0; i < mFileData.mPositions.size(); i++)
233 void ReconstructPreprocessor::positionThinning()
247 void ReconstructPreprocessor::interpolatePositions()
249 mFileData.mUsRaw->resetRemovedFrames();
250 int startFrames = mFileData.mFrames.size();
252 std::map<int,RemoveDataType> removedData;
254 for (
unsigned i_frame = 0; i_frame < mFileData.mFrames.size();)
256 std::vector<TimedPosition>::iterator posIter;
257 posIter = lower_bound(mFileData.mPositions.begin(), mFileData.mPositions.end(), mFileData.mFrames[i_frame]);
259 unsigned i_pos = distance(mFileData.mPositions.begin(), posIter);
263 if (i_pos >= mFileData.mPositions.size() - 1)
264 i_pos = mFileData.mPositions.size() - 2;
268 double timeToPos1 = timeToPosition(i_frame, i_pos);
269 double timeToPos2 = timeToPosition(i_frame, i_pos+1);
270 if ((timeToPos1 > mMaxTimeDiff) || (timeToPos2 > mMaxTimeDiff))
272 removedData[i_frame].add(std::max(timeToPos1, timeToPos2));
274 mFileData.mFrames.erase(mFileData.mFrames.begin() + i_frame);
275 mFileData.mUsRaw->removeFrame(i_frame);
279 double t_delta_tracking = mFileData.mPositions[i_pos + 1].mTime - mFileData.mPositions[i_pos].mTime;
281 if (!
similar(t_delta_tracking, 0))
282 t = (mFileData.mFrames[i_frame].mTime - mFileData.mPositions[i_pos].mTime) / t_delta_tracking;
290 for (std::map<int,RemoveDataType>::iterator iter=removedData.begin(); iter!=removedData.end(); ++iter)
292 int first = iter->first+removeCount;
293 int last = first + iter->second.count-1;
294 report(QString(
"Removed input frame [%1-%2]. Time diff=%3").arg(first).arg(last).arg(iter->second.err, 0,
'f', 1));
295 removeCount += iter->second.count;
298 double removed = double(startFrames - mFileData.mFrames.size()) /
double(startFrames);
301 double percent = removed * 100;
308 report(
"Removed " + QString::number(percent,
'f', 1) +
"% of the " +
qstring_cast(startFrames) +
" frames.");
314 double ReconstructPreprocessor::timeToPosition(
unsigned i_frame,
unsigned i_pos)
316 return fabs(mFileData.mFrames[i_frame].mTime - mFileData.mPositions[i_pos].mTime);
322 std::vector<Vector3D> ReconstructPreprocessor::generateInputRectangle()
324 std::vector<Vector3D> retval(4);
328 reportError(
"Reconstructer::generateInputRectangle() + requires mask");
331 Eigen::Array3i dims = mFileData.mUsRaw->getDimensions();
332 Vector3D spacing = mFileData.mUsRaw->getSpacing();
334 Eigen::Array3i maskDims(mask->GetDimensions());
336 if (( maskDims[0]<dims[0] )||( maskDims[1]<dims[1] ))
337 reportError(QString(
"input data (%1) and mask (%2) dim mimatch")
341 int xmin = maskDims[0];
343 int ymin = maskDims[1];
346 unsigned char* ptr =
static_cast<unsigned char*
> (mask->GetScalarPointer());
347 for (
int x = 0; x < maskDims[0]; x++)
348 for (
int y = 0; y < maskDims[1]; y++)
350 unsigned char val = ptr[x + y * maskDims[0]];
353 xmin = std::min(xmin, x);
354 ymin = std::min(ymin, y);
355 xmax = std::max(xmax, x);
356 ymax = std::max(ymax, y);
362 double red = mInput.mMaskReduce;
363 int reduceX = (xmax - xmin) * (red / 100);
364 int reduceY = (ymax - ymin) * (red / 100);
371 retval[0] =
Vector3D(xmin * spacing[0], ymin * spacing[1], 0);
372 retval[1] =
Vector3D(xmax * spacing[0], ymin * spacing[1], 0);
373 retval[2] =
Vector3D(xmin * spacing[0], ymax * spacing[1], 0);
374 retval[3] =
Vector3D(xmax * spacing[0], ymax * spacing[1], 0);
385 Transform3D ReconstructPreprocessor::applyOutputOrientation()
389 if (mInput.mOrientation ==
"PatientReference")
393 else if (mInput.mOrientation ==
"MiddleFrame")
395 prMdd = mFileData.mFrames[mFileData.mFrames.size() / 2].mPos;
399 reportError(
"no orientation algorithm selected in reconstruction");
404 for (
unsigned i = 0; i < mFileData.mFrames.size(); i++)
407 mFileData.mFrames[i].mPos = ddMpr * mFileData.mFrames[i].mPos;
423 void ReconstructPreprocessor::findExtentAndOutputTransform()
425 if (mFileData.mFrames.empty())
428 Transform3D prMdd = this->applyOutputOrientation();
432 std::vector<Vector3D> inputRect = this->generateInputRectangle();
433 std::vector<Vector3D> outputRect;
434 for (
unsigned slice = 0; slice < mFileData.mFrames.size(); slice++)
437 for (
unsigned i = 0; i < inputRect.size(); i++)
439 outputRect.push_back(dMu.coord(inputRect[i]));
448 for (
unsigned i = 0; i < mFileData.mFrames.size(); i++)
450 mFileData.mFrames[i].mPos = T_origo.inv() * mFileData.mFrames[i].mPos;
454 double inputSpacing = std::min(mFileData.mUsRaw->getSpacing()[0], mFileData.mUsRaw->getSpacing()[1]);
455 mOutputVolumeParams =
OutputVolumeParams(extent, inputSpacing, mInput.mMaxOutputVolumeSize);
457 mOutputVolumeParams.set_rMd((mPatientModelService->get_rMpr()) * prMd);
463 void ReconstructPreprocessor::updateFromOriginalFileData()
466 this->cropInputData();
474 this->applyTimeCalibration();
479 this->filterPositions();
484 this->interpolatePositions();
487 if (mFileData.mFrames.empty())
490 this->findExtentAndOutputTransform();
497 mFileData = fileData;
498 this->updateFromOriginalFileData();
QString qstring_cast(const T &val)
Transform3D quaternionToMatrix(Eigen::ArrayXd qArray)
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.
Eigen::ArrayXd matrixToQuaternion(Transform3D Tx)
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.