7 #include "PlusConfigure.h" 16 #include "itkRGBPixel.h" 18 #include "itkImageFileReader.h" 19 #include "itkImageFileWriter.h" 20 #include "itkPNGImageIO.h" 45 : m_UseOriginalImageIntensityForDotIntensityScore(false)
46 , m_NumberOfMaximumFiducialPointCandidates(DEFAULT_NUMBER_OF_MAXIMUM_FIDUCIAL_POINT_CANDIDATES)
47 , m_ThresholdImagePercent(-1)
48 , m_MorphologicalOpeningBarSizeMm(-1)
49 , m_MorphologicalOpeningCircleRadiusMm(-1)
50 , m_PossibleFiducialsImageFilename(
"")
51 , m_FiducialGeometry(CALIBRATION_PHANTOM_6_POINT)
52 , m_ApproximateSpacingMmPerPixel(-1)
59 , m_DebugOutput(false)
71 for (
int i = 0 ;
i < 4 ;
i++)
76 for (
int i = 0 ;
i < 3 ;
i++)
81 for (
int i = 0 ;
i < 6 ;
i++)
86 for (
int i = 0 ;
i < 16 ;
i++)
106 LOG_TRACE(
"FidSegmentation::UpdateParameters");
111 for (
int x = -radiuspx;
x <= radiuspx;
x++)
113 for (
int y = -radiuspx;
y <= radiuspx;
y++)
115 if (sqrt(pow(
x, 2.0) + pow(
y, 2.0)) <= radiuspx)
130 LOG_TRACE(
"FidSegmentation::ReadConfiguration");
132 XML_FIND_NESTED_ELEMENT_REQUIRED(phantomDefinition, configData,
"PhantomDefinition");
133 XML_FIND_NESTED_ELEMENT_REQUIRED(description, phantomDefinition,
"Description");
136 XML_FIND_NESTED_ELEMENT_OPTIONAL(segmentationParameters, configData,
"Segmentation");
137 if (!segmentationParameters)
139 segmentationParameters = igsioXmlUtils::GetNestedElementWithName(configData,
"Segmentation");
143 XML_READ_SCALAR_ATTRIBUTE_WARNING(
double, ApproximateSpacingMmPerPixel, segmentationParameters);
144 XML_READ_SCALAR_ATTRIBUTE_WARNING(
double, MorphologicalOpeningCircleRadiusMm, segmentationParameters);
145 XML_READ_SCALAR_ATTRIBUTE_WARNING(
double, MorphologicalOpeningBarSizeMm, segmentationParameters);
148 int clipOrigin[2] = {0};
149 int clipSize[2] = {0};
150 if (segmentationParameters->GetVectorAttribute(
"ClipRectangleOrigin", 2, clipOrigin) &&
151 segmentationParameters->GetVectorAttribute(
"ClipRectangleSize", 2, clipSize))
160 LOG_INFO(
"Cannot find ClipRectangleOrigin or ClipRectangleSize attribute in the SegmentationParameters configuration file; Using the largest ROI possible.");
163 XML_READ_SCALAR_ATTRIBUTE_WARNING(
double, ThresholdImagePercent, segmentationParameters);
165 int intUseOriginalImageIntensityForDotIntensityScore = 0;
166 if (segmentationParameters->GetScalarAttribute(
"UseOriginalImageIntensityForDotIntensityScore", intUseOriginalImageIntensityForDotIntensityScore))
168 LOG_WARNING(
"UseOriginalImageIntensityForDotIntensityScore attribute expected to have 'TRUE' or 'FALSE' value. Numerical values ('1' or '0') are deprecated.");
173 XML_READ_BOOL_ATTRIBUTE_OPTIONAL(UseOriginalImageIntensityForDotIntensityScore, segmentationParameters);
178 int computeSegmentationParametersFromPhantomDefinition(0);
179 if (segmentationParameters->GetScalarAttribute(
"ComputeSegmentationParametersFromPhantomDefinition", computeSegmentationParametersFromPhantomDefinition)
180 && computeSegmentationParametersFromPhantomDefinition != 0)
182 double imageScalingTolerancePercent[4] = {0};
183 if (segmentationParameters->GetVectorAttribute(
"ImageScalingTolerancePercent", 4, imageScalingTolerancePercent))
185 for (
int i = 0;
i < 4 ;
i++)
192 LOG_WARNING(
"Could not read imageScalingTolerancePercent from configuration file.");
195 double imageNormalVectorInPhantomFrameEstimation[3] = {0};
196 if (segmentationParameters->GetVectorAttribute(
"ImageNormalVectorInPhantomFrameEstimation", 3, imageNormalVectorInPhantomFrameEstimation))
204 LOG_WARNING(
"Could not read imageNormalVectorInPhantomFrameEstimation from configuration file.");
208 XML_READ_SCALAR_ATTRIBUTE_OPTIONAL(
int, NumberOfMaximumFiducialPointCandidates, segmentationParameters);
219 LOG_TRACE(
"FidSegmentation::SetFrameSize(" << frameSize[0] <<
", " << frameSize[1] <<
")");
261 LOG_WARNING(
"The region of interest is too big, bar size is " << barSize);
266 LOG_WARNING(
"The region of interest is too big, bar size is " << barSize);
271 LOG_WARNING(
"The region of interest is too big, bar size is " << barSize);
276 LOG_WARNING(
"The region of interest is too big, bar size is " << barSize);
309 unsigned int p_max = ir *
m_FrameSize[0] + ic + barSize;
312 for (;
p <= p_max;
p++)
343 dest[p_base + ic] = dval;
350 dval = new_val <= dval ? new_val :
351 del_val > dval ? std::min(dval, new_val) :
368 unsigned int p = (ir + barSize) *
m_FrameSize[0] + ic - barSize;
369 unsigned int p_max = (ir - barSize) *
m_FrameSize[0] + ic + barSize;
397 unsigned int ir = sr;
408 dval = new_val <= dval ? new_val :
409 del_val > dval ? std::min(dval, new_val) :
419 unsigned int ic = sc;
430 dval = new_val <= dval ? new_val :
431 del_val > dval ? std::min(dval, new_val) :
448 unsigned int p_max = (ir + barSize) *
m_FrameSize[0] + ic;
486 dval = new_val <= dval ? new_val :
487 del_val > dval ? std::min(dval, new_val) :
503 unsigned int p = (ir - barSize) *
m_FrameSize[0] + ic - barSize;
504 unsigned int p_max = (ir + barSize) *
m_FrameSize[0] + ic + barSize;
533 unsigned int ir = sr;
544 dval = new_val <= dval ? new_val :
545 del_val > dval ? std::min(dval, new_val) :
555 unsigned int ic = sc;
566 dval = new_val <= dval ? new_val :
567 del_val > dval ? std::min(dval, new_val) :
590 for (
unsigned int sp = 0; sp < slen; sp++)
621 unsigned int p_max = ir *
m_FrameSize[0] + ic + barSize;
623 for (;
p <= p_max;
p++)
657 dval = new_val >= dval ? new_val :
658 (del_val < dval ? std::max(dval, new_val) :
673 unsigned int p = (ir + barSize) *
m_FrameSize[0] + ic - barSize;
674 unsigned int p_max = (ir - barSize) *
m_FrameSize[0] + ic + barSize;
708 unsigned int ir = sr;
718 dval = new_val >= dval ? new_val :
719 (del_val < dval ? std::max(dval, new_val) :
728 unsigned int ic = sc;
738 dval = new_val >= dval ? new_val :
739 (del_val < dval ? std::max(dval, new_val) :
755 unsigned int p_max = (ir + barSize) *
m_FrameSize[0] + ic;
787 dval = new_val >= dval ? new_val :
788 (del_val < dval ? std::max(dval, new_val) :
804 unsigned int p = (ir - barSize) *
m_FrameSize[0] + ic - barSize;
805 unsigned int p_max = (ir + barSize) *
m_FrameSize[0] + ic + barSize;
829 unsigned int ir = sr;
839 dval = new_val >= dval ? new_val :
840 (del_val < dval ? std::max(dval, new_val) :
849 unsigned int ic = sc;
859 dval = new_val >= dval ? new_val :
860 (del_val < dval ? std::max(dval, new_val) :
874 for (
int sp = 0; sp < slen; sp++)
876 unsigned int sr = ir + shape[sp].
Y;
877 unsigned int sc = ic + shape[sp].
X;
897 for (
unsigned int i = 0;
i < slen;
i++)
905 bool* sr_exist =
new bool[slen];
907 memset(sr_exist, 0, slen *
sizeof(
bool));
908 for (
unsigned int si = 0; si < slen; si++)
916 sr_exist[si] =
true, n++;
924 int nNewDots = 0, nOldDots = 0;
925 for (
unsigned int si = 0; si < slen; si++)
929 oldDots[nOldDots++] = shape[si];
933 newDots[nNewDots++] = shape[si];
953 for (
int sp = 0; sp < nOldDots; sp++)
955 unsigned int sr = ir + oldDots[sp].
Y;
956 unsigned int sc = ic + oldDots[sp].
X;
980 for (
unsigned int si = 0; si < shape.size(); si++)
982 if (shape[si] == point)
997 const unsigned int Dimension = 2;
999 typedef itk::Image< PlusFidSegmentation::PixelType, Dimension > ImageType;
1000 auto modImage = ImageType::New();
1001 ImageType::SizeType size;
1005 ImageType::IndexType
start;
1009 ImageType::RegionType wholeImage;
1010 wholeImage.SetSize(size);
1011 wholeImage.SetIndex(
start);
1013 modImage->SetRegions(wholeImage);
1014 modImage->Allocate();
1016 typedef itk::ImageFileWriter< ImageType > WriterType;
1017 auto pngImageIO = itk::PNGImageIO::New();
1018 pngImageIO->SetCompressionLevel(0);
1020 auto writer = WriterType::New();
1021 writer->SetImageIO(pngImageIO);
1022 writer->SetFileName(outImageName);
1025 typedef itk::ImageRegionIterator<ImageType> IterType;
1026 IterType
iter(modImage, modImage->GetRequestedRegion());
1031 while (!
iter.IsAtEnd())
1038 writer->SetInput(modImage);
1044 catch (itk::ExceptionObject& err)
1046 LOG_ERROR(
"Exception! writer did not update");
1056 if (!segmentationDataElement)
1061 segmentationDataElement->SetName(
"Segmentation");
1076 std::stringstream clipOriginSS;
1078 std::string clipOriginString = clipOriginSS.str();
1079 segmentationDataElement->SetAttribute(
"ClipRectangleOrigin", clipOriginString.c_str());
1081 std::stringstream clipSizeSS;
1083 std::string clipSizeString = clipSizeSS.str();
1084 segmentationDataElement->SetAttribute(
"ClipRectangleSize", clipSizeString.c_str());
1093 typedef itk::RGBPixel< unsigned char > ColorPixelType;
1094 typedef itk::Image< ColorPixelType, 2 > ImageType;
1096 auto possibleFiducials = ImageType::New();
1098 ImageType::SizeType size;
1102 ImageType::IndexType
start;
1106 ImageType::RegionType wholeImage;
1107 wholeImage.SetSize(size);
1108 wholeImage.SetIndex(
start);
1110 possibleFiducials->SetRegions(wholeImage);
1111 possibleFiducials->Allocate();
1113 ImageType::IndexType pixelLocation;
1115 ImageType::PixelType pixelValue;
1123 pixelValue[1] = unalteredImage[r *
m_FrameSize[0] + c];
1124 pixelValue[2] = unalteredImage[r *
m_FrameSize[0] + c];
1125 pixelLocation[0] = c;
1126 pixelLocation[1] = r;
1127 possibleFiducials->SetPixel(pixelLocation, pixelValue);
1132 for (
unsigned int numDots = 0; numDots < fiducials.size(); numDots++)
1134 const int markerPosCount = 5;
1135 const int markerPos[markerPosCount][2] = {{0, 0}, { +1, 0}, { -1, 0}, {0, +1}, {0, -1}};
1137 for (
int i = 0;
i < markerPosCount;
i++)
1139 pixelLocation[0] = fiducials[numDots].GetX() + markerPos[
i][0];
1140 pixelLocation[1] = fiducials[numDots].GetY() + markerPos[
i][1];
1141 int clusterMarkerIntensity = fiducials[numDots].GetDotIntensity() * 10;
1142 if (clusterMarkerIntensity > 255)
1144 clusterMarkerIntensity = 255;
1146 pixelValue[0] = clusterMarkerIntensity;
1149 possibleFiducials->SetPixel(pixelLocation, pixelValue);
1152 std::ostringstream possibleFiducialsImageFilename;
1153 possibleFiducialsImageFilename << namePrefix << std::setw(3) << std::setfill(
'0') << frameIndex <<
".bmp" << std::ends;
1157 typedef itk::ImageFileWriter< ImageType > WriterType;
1158 auto writeImage = WriterType::New();
1161 writeImage->SetInput(possibleFiducials);
1165 writeImage->Update();
1167 catch (itk::ExceptionObject& err)
1169 LOG_ERROR(
"Exception! writer did not update");
1178 std::vector<PlusFidDot> dots;
1179 for (
unsigned int numDots = 0; numDots < fiducials.size(); numDots++)
1182 newDot.
SetX(fiducials[numDots][0]);
1183 newDot.
SetY(fiducials[numDots][1]);
1185 dots.push_back(newDot);
1198 *image = *vals > *image ? 0 : *image - *vals;
1212 LOG_TRACE(
"FidSegmentation::Suppress");
1238 for (
int i = 0;
i < pixelCount;
i++)
1240 if (*pixel < thresh)
1265 testPosition.push_back(dot);
1266 setPosition.push_back(dot);
1267 valuesOfPosition.push_back(image[r *
m_FrameSize[0] + c]);
1296 LOG_TRACE(
"FidSegmentation::Cluster");
1297 tooManyCandidates =
false;
1299 std::vector<PlusFidDot> testPosition;
1300 std::vector<PlusFidDot> setPosition;
1301 std::vector<PlusFidSegmentation::PixelType> valuesOfPosition;
1309 testPosition.clear();
1314 testPosition.push_back(dot);
1316 setPosition.clear();
1317 setPosition.push_back(dot);
1319 valuesOfPosition.clear();
1324 while (testPosition.size() > 0)
1327 testPosition.pop_back();
1341 double dest_r = 0, dest_c = 0, total = 0;
1342 for (
unsigned int p = 0;
p < setPosition.size();
p++)
1344 double amount = (double)valuesOfPosition[
p] / (
double)UCHAR_MAX;
1345 dest_r += setPosition[
p].GetY() * amount;
1346 dest_c += setPosition[
p].GetX() * amount;
1350 dot.
SetY(dest_r / total);
1351 dot.
SetX(dest_c / total);
1359 const double dotRadius2 = 3.0 * 3.0;
1360 double dest_r = 0, dest_c = 0, total = 0;
1361 for (
unsigned int p = 0;
p < setPosition.size();
p++)
1363 if ((setPosition[
p].GetY() - dot.
GetY()) * (setPosition[
p].GetY() - dot.
GetY()) + (setPosition[
p].GetX() - dot.
GetX()) * (setPosition[
p].GetX() - dot.
GetX()) <= dotRadius2)
1367 dest_r += setPosition[
p].GetY() * amount;
1368 dest_c += setPosition[
p].GetX() * amount;
1386 tooManyCandidates =
true;
1396 LOG_TRACE(
"FidSegmentation::MorphologicalOperations");
1506 LOG_TRACE(
"FidSegmentation::SetRegionOfInterest(" << xMin <<
", " << yMin <<
", " << xMax <<
", " << yMax <<
")");
1530 LOG_TRACE(
"FidSegmentation::ValidateRegionOfInterest");
bool ShapeContains(std::vector< PlusCoordinate2D > &shape, PlusCoordinate2D point)
static void WritePng(PlusFidSegmentation::PixelType *modifiedImage, std::string outImageName, int cols, int rows)
unsigned int m_NumberOfMaximumFiducialPointCandidates
static const double DEFAULT_MAX_ANGLE_DIFFERENCE_DEGREES
unsigned int GetMorphologicalOpeningBarSizePx()
PlusFidSegmentation::PixelType * m_Dilated
void SetPossibleFiducialsImageFilename(std::string value)
std::vector< PlusFidDot > m_DotsVector
FrameSizeType m_FrameSize
static const double DEFAULT_THRESHOLD_IMAGE_PERCENT
void ClusteringAddNeighbors(PlusFidSegmentation::PixelType *image, int r, int c, std::vector< PlusFidDot > &m_Test, std::vector< PlusFidDot > &m_Set, std::vector< PlusFidSegmentation::PixelType > &m_Vals)
void SetNumberOfMaximumFiducialPointCandidates(int aValue)
static const short MAX_CLUSTER_VALS
double m_MorphologicalOpeningCircleRadiusMm
void ErodeCircle(PlusFidSegmentation::PixelType *dest, PlusFidSegmentation::PixelType *image)
void Subtract(PlusFidSegmentation::PixelType *image, PlusFidSegmentation::PixelType *vals)
void SetUseOriginalImageIntensityForDotIntensityScore(bool value)
void GetRegionOfInterest(unsigned int &xMin, unsigned int &yMin, unsigned int &xMax, unsigned int &yMax)
PlusFidSegmentation::PixelType DilatePoint90(PlusFidSegmentation::PixelType *image, unsigned int ir, unsigned int ic)
PlusFidSegmentation::PixelType ErodePoint45(PlusFidSegmentation::PixelType *image, unsigned int ir, unsigned int ic)
void Dilate45(PlusFidSegmentation::PixelType *dest, PlusFidSegmentation::PixelType *image)
void WritePossibleFiducialOverlayImage(const std::vector< std::vector< double > > &fiducials, PlusFidSegmentation::PixelType *unalteredImage, const char *namePrefix, int frameIndex)
PlusFidSegmentation::PixelType ErodePoint0(PlusFidSegmentation::PixelType *image, unsigned int ir, unsigned int ic)
void SetFiducialGeometry(FiducialGeometryType geometryType)
bool AcceptDot(PlusFidDot &dot)
std::string m_PossibleFiducialsImageFilename
static const double DEFAULT_MAX_LINE_PAIR_DISTANCE_ERROR_PERCENT
static const double DEFAULT_MORPHOLOGICAL_OPENING_CIRCLE_RADIUS_MM
PlusFidSegmentation::PixelType DilatePoint45(PlusFidSegmentation::PixelType *image, unsigned int ir, unsigned int ic)
PlusFidSegmentation::PixelType ErodePoint135(PlusFidSegmentation::PixelType *image, unsigned int ir, unsigned int ic)
std::array< unsigned int, 4 > m_RegionOfInterest
PlusFidSegmentation::PixelType * m_UnalteredImage
double m_ImageNormalVectorInPhantomFrameEstimation[3]
void Dilate135(PlusFidSegmentation::PixelType *dest, PlusFidSegmentation::PixelType *image)
static const double DEFAULT_MAX_LINE_SHIFT_MM
static const int DEFAULT_CLIP_ORIGIN[2]
void MorphologicalOperations()
bool m_UseOriginalImageIntensityForDotIntensityScore
double m_ImageToPhantomTransform[16]
double m_ImageScalingTolerancePercent[4]
static const double DEFAULT_APPROXIMATE_SPACING_MM_PER_PIXEL
PlusFidSegmentation::PixelType DilatePoint(PlusFidSegmentation::PixelType *image, unsigned int ir, unsigned int ic, PlusCoordinate2D *shape, int slen)
static const short MIN_WINDOW_DIST
static const double DEFAULT_ANGLE_TOLERANCE_DEGREES
void Erode135(PlusFidSegmentation::PixelType *dest, PlusFidSegmentation::PixelType *image)
static const double DEFAULT_COLLINEAR_POINTS_MAX_DISTANCE_FROM_LINE_MM
bool Cluster(bool &tooManyCandidates)
void DilateCircle(PlusFidSegmentation::PixelType *dest, PlusFidSegmentation::PixelType *image)
std::vector< PlusCoordinate2D > m_MorphologicalCircle
double m_ImageNormalVectorInPhantomFrameMaximumRotationAngleDeg[6]
PlusFidSegmentation::PixelType DilatePoint135(PlusFidSegmentation::PixelType *image, unsigned int ir, unsigned int ic)
void Dilate90(PlusFidSegmentation::PixelType *dest, PlusFidSegmentation::PixelType *image)
Phidget_ChannelClass uint32_t * count
static const int DEFAULT_NUMBER_OF_MAXIMUM_FIDUCIAL_POINT_CANDIDATES
void Dilate0(PlusFidSegmentation::PixelType *dest, PlusFidSegmentation::PixelType *image)
void ValidateRegionOfInterest()
static const double DEFAULT_MAX_THETA_DEGREES
static void SetDefaultSegmentationParameters(vtkXMLDataElement *segmentationElement)
void Erode0(PlusFidSegmentation::PixelType *dest, PlusFidSegmentation::PixelType *image)
void Erode90(PlusFidSegmentation::PixelType *dest, PlusFidSegmentation::PixelType *image)
static const double DEFAULT_MORPHOLOGICAL_OPENING_BAR_SIZE_MM
static bool IntensityLessThan(const PlusFidDot &dot1, const PlusFidDot &dot2)
FiducialGeometryType m_FiducialGeometry
Direction vectors of rods y
virtual ~PlusFidSegmentation()
PlusStatus ReadConfiguration(vtkXMLDataElement *rootConfigElement)
void SetFrameSize(const FrameSizeType &frameSize)
PlusFidSegmentation::PixelType DilatePoint0(PlusFidSegmentation::PixelType *image, unsigned int ir, unsigned int ic)
static const char * DEFAULT_USE_ORIGINAL_IMAGE_INTENSITY_FOR_DOT_INTENSITY_SCORE
static const double DEFAULT_MIN_THETA_DEGREES
void Suppress(PlusFidSegmentation::PixelType *image, double percent_thresh)
double m_MorphologicalOpeningBarSizeMm
void SetRegionOfInterest(unsigned int xMin, unsigned int yMin, unsigned int xMax, unsigned int yMax)
void SetDotIntensity(double value)
double m_ApproximateSpacingMmPerPixel
PlusFidSegmentation::PixelType * m_Eroded
PlusFidSegmentation::PixelType ErodePoint90(PlusFidSegmentation::PixelType *image, unsigned int ir, unsigned int ic)
std::vector< PlusFidDot > m_CandidateFidValues
static const int DEFAULT_CLIP_SIZE[2]
PlusFidSegmentation::PixelType * m_Working
void Erode45(PlusFidSegmentation::PixelType *dest, PlusFidSegmentation::PixelType *image)