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) :
398 unsigned int ir = sr;
409 dval = new_val <= dval ? new_val :
410 del_val > dval ? std::min(dval, new_val) :
420 unsigned int ic = sc;
431 dval = new_val <= dval ? new_val :
432 del_val > dval ? std::min(dval, new_val) :
449 unsigned int p_max = (ir + barSize) *
m_FrameSize[0] + ic;
487 dval = new_val <= dval ? new_val :
488 del_val > dval ? std::min(dval, new_val) :
505 unsigned int p_max = (ir + barSize) *
m_FrameSize[0] + ic + barSize;
534 unsigned int ir = sr;
545 dval = new_val <= dval ? new_val :
546 del_val > dval ? std::min(dval, new_val) :
556 unsigned int ic = sc;
567 dval = new_val <= dval ? new_val :
568 del_val > dval ? std::min(dval, new_val) :
591 for (
unsigned int sp = 0; sp < slen; sp++)
622 unsigned int p_max = ir *
m_FrameSize[0] + ic + barSize;
624 for (;
p <= p_max;
p++)
658 dval = new_val >= dval ? new_val :
659 (del_val < dval ? std::max(dval, new_val) :
698 int irMinusBar = (
int)ir - (
int)barSize;
699 return (
unsigned int)irMinusBar < 0 ? 0 : irMinusBar;
714 unsigned int ir = sr;
725 dval = new_val >= dval ? new_val :
726 (del_val < dval ? std::max(dval, new_val) :
735 unsigned int ic = sc;
745 dval = new_val >= dval ? new_val :
746 (del_val < dval ? std::max(dval, new_val) :
762 unsigned int p_max = (ir + barSize) *
m_FrameSize[0] + ic;
794 dval = new_val >= dval ? new_val :
795 (del_val < dval ? std::max(dval, new_val) :
812 unsigned int p_max = (ir + barSize) *
m_FrameSize[0] + ic + barSize;
836 unsigned int ir = sr;
846 dval = new_val >= dval ? new_val :
847 (del_val < dval ? std::max(dval, new_val) :
856 unsigned int ic = sc;
866 dval = new_val >= dval ? new_val :
867 (del_val < dval ? std::max(dval, new_val) :
881 for (
int sp = 0; sp < slen; sp++)
883 unsigned int sr = ir + shape[sp].
Y;
884 unsigned int sc = ic + shape[sp].
X;
904 for (
unsigned int i = 0;
i < slen;
i++)
912 bool* sr_exist =
new bool[slen];
914 memset(sr_exist, 0, slen *
sizeof(
bool));
915 for (
unsigned int si = 0; si < slen; si++)
923 sr_exist[si] =
true, n++;
931 int nNewDots = 0, nOldDots = 0;
932 for (
unsigned int si = 0; si < slen; si++)
936 oldDots[nOldDots++] = shape[si];
940 newDots[nNewDots++] = shape[si];
960 for (
int sp = 0; sp < nOldDots; sp++)
962 unsigned int sr = ir + oldDots[sp].
Y;
963 unsigned int sc = ic + oldDots[sp].
X;
987 for (
unsigned int si = 0; si < shape.size(); si++)
989 if (shape[si] == point)
1004 const unsigned int Dimension = 2;
1006 typedef itk::Image< PlusFidSegmentation::PixelType, Dimension > ImageType;
1007 auto modImage = ImageType::New();
1008 ImageType::SizeType size;
1012 ImageType::IndexType
start;
1016 ImageType::RegionType wholeImage;
1017 wholeImage.SetSize(size);
1018 wholeImage.SetIndex(
start);
1020 modImage->SetRegions(wholeImage);
1021 modImage->Allocate();
1023 typedef itk::ImageFileWriter< ImageType > WriterType;
1024 auto pngImageIO = itk::PNGImageIO::New();
1025 pngImageIO->SetCompressionLevel(0);
1027 auto writer = WriterType::New();
1028 writer->SetImageIO(pngImageIO);
1029 writer->SetFileName(outImageName);
1032 typedef itk::ImageRegionIterator<ImageType> IterType;
1033 IterType
iter(modImage, modImage->GetRequestedRegion());
1038 while (!
iter.IsAtEnd())
1045 writer->SetInput(modImage);
1051 catch (itk::ExceptionObject& err)
1053 LOG_ERROR(
"Exception! writer did not update");
1063 if (!segmentationDataElement)
1068 segmentationDataElement->SetName(
"Segmentation");
1083 std::stringstream clipOriginSS;
1085 std::string clipOriginString = clipOriginSS.str();
1086 segmentationDataElement->SetAttribute(
"ClipRectangleOrigin", clipOriginString.c_str());
1088 std::stringstream clipSizeSS;
1090 std::string clipSizeString = clipSizeSS.str();
1091 segmentationDataElement->SetAttribute(
"ClipRectangleSize", clipSizeString.c_str());
1100 typedef itk::RGBPixel< unsigned char > ColorPixelType;
1101 typedef itk::Image< ColorPixelType, 2 > ImageType;
1103 auto possibleFiducials = ImageType::New();
1105 ImageType::SizeType size;
1109 ImageType::IndexType
start;
1113 ImageType::RegionType wholeImage;
1114 wholeImage.SetSize(size);
1115 wholeImage.SetIndex(
start);
1117 possibleFiducials->SetRegions(wholeImage);
1118 possibleFiducials->Allocate();
1120 ImageType::IndexType pixelLocation;
1122 ImageType::PixelType pixelValue;
1130 pixelValue[1] = unalteredImage[r *
m_FrameSize[0] + c];
1131 pixelValue[2] = unalteredImage[r *
m_FrameSize[0] + c];
1132 pixelLocation[0] = c;
1133 pixelLocation[1] = r;
1134 possibleFiducials->SetPixel(pixelLocation, pixelValue);
1139 for (
unsigned int numDots = 0; numDots < fiducials.size(); numDots++)
1141 const int markerPosCount = 5;
1142 const int markerPos[markerPosCount][2] = {{0, 0}, { +1, 0}, { -1, 0}, {0, +1}, {0, -1}};
1144 for (
int i = 0;
i < markerPosCount;
i++)
1146 pixelLocation[0] = fiducials[numDots].GetX() + markerPos[
i][0];
1147 pixelLocation[1] = fiducials[numDots].GetY() + markerPos[
i][1];
1148 int clusterMarkerIntensity = fiducials[numDots].GetDotIntensity() * 10;
1149 if (clusterMarkerIntensity > 255)
1151 clusterMarkerIntensity = 255;
1153 pixelValue[0] = clusterMarkerIntensity;
1156 possibleFiducials->SetPixel(pixelLocation, pixelValue);
1159 std::ostringstream possibleFiducialsImageFilename;
1160 possibleFiducialsImageFilename << namePrefix << std::setw(3) << std::setfill(
'0') << frameIndex <<
".bmp" << std::ends;
1164 typedef itk::ImageFileWriter< ImageType > WriterType;
1165 auto writeImage = WriterType::New();
1168 writeImage->SetInput(possibleFiducials);
1172 writeImage->Update();
1174 catch (itk::ExceptionObject& err)
1176 LOG_ERROR(
"Exception! writer did not update");
1185 std::vector<PlusFidDot> dots;
1186 for (
unsigned int numDots = 0; numDots < fiducials.size(); numDots++)
1189 newDot.
SetX(fiducials[numDots][0]);
1190 newDot.
SetY(fiducials[numDots][1]);
1192 dots.push_back(newDot);
1205 *image = *vals > *image ? 0 : *image - *vals;
1219 LOG_TRACE(
"FidSegmentation::Suppress");
1245 for (
int i = 0;
i < pixelCount;
i++)
1247 if (*pixel < thresh)
1272 testPosition.push_back(dot);
1273 setPosition.push_back(dot);
1274 valuesOfPosition.push_back(image[r *
m_FrameSize[0] + c]);
1303 LOG_TRACE(
"FidSegmentation::Cluster");
1304 tooManyCandidates =
false;
1306 std::vector<PlusFidDot> testPosition;
1307 std::vector<PlusFidDot> setPosition;
1308 std::vector<PlusFidSegmentation::PixelType> valuesOfPosition;
1316 testPosition.clear();
1321 testPosition.push_back(dot);
1323 setPosition.clear();
1324 setPosition.push_back(dot);
1326 valuesOfPosition.clear();
1331 while (testPosition.size() > 0)
1334 testPosition.pop_back();
1348 double dest_r = 0, dest_c = 0, total = 0;
1349 for (
unsigned int p = 0;
p < setPosition.size();
p++)
1351 double amount = (double)valuesOfPosition[
p] / (
double)UCHAR_MAX;
1352 dest_r += setPosition[
p].GetY() * amount;
1353 dest_c += setPosition[
p].GetX() * amount;
1357 dot.
SetY(dest_r / total);
1358 dot.
SetX(dest_c / total);
1366 const double dotRadius2 = 3.0 * 3.0;
1367 double dest_r = 0, dest_c = 0, total = 0;
1368 for (
unsigned int p = 0;
p < setPosition.size();
p++)
1370 if ((setPosition[
p].GetY() - dot.
GetY()) * (setPosition[
p].GetY() - dot.
GetY()) + (setPosition[
p].GetX() - dot.
GetX()) * (setPosition[
p].GetX() - dot.
GetX()) <= dotRadius2)
1374 dest_r += setPosition[
p].GetY() * amount;
1375 dest_c += setPosition[
p].GetX() * amount;
1393 tooManyCandidates =
true;
1403 LOG_TRACE(
"FidSegmentation::MorphologicalOperations");
1513 LOG_TRACE(
"FidSegmentation::SetRegionOfInterest(" << xMin <<
", " << yMin <<
", " << xMax <<
", " << yMax <<
")");
1537 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()
unsigned int clampMinBarSize(unsigned int ir, unsigned int barSize)
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)