8 #include "PlusConfigure.h" 16 #include <vtkImageDilateErode3D.h> 17 #include <vtkImageGaussianSmooth.h> 18 #include <vtkImageIslandRemoval2D.h> 19 #include <vtkImageSobel2D.h> 20 #include <vtkImageThreshold.h> 21 #include <vtkObjectFactory.h> 22 #include "vtkImageAlgorithm.h" 24 #include <igsioTrackedFrame.h> 25 #include <igsioVideoFrame.h> 26 #include <vtkIGSIOTrackedFrameList.h> 36 : ScanConverter(NULL),
38 NumberOfSamplesPerScanLine(0),
48 BinaryImageForMorphology(NULL),
53 ConversionImage(NULL),
54 IslandAreaThreshold(-1),
55 BoneOutlineDepthPx(3),
59 ProcessedLinesImage(NULL),
62 SaveIntermediateResults(false)
65 this->
GaussianSmooth = vtkSmartPointer<vtkImageGaussianSmooth>::New();
66 this->
EdgeDetector = vtkSmartPointer<vtkImageSobel2D>::New();
69 this->
IslandRemover = vtkSmartPointer<vtkImageIslandRemoval2D>::New();
70 this->
ImageEroder = vtkSmartPointer<vtkImageDilateErode3D>::New();
71 this->
ImageDialator = vtkSmartPointer<vtkImageDilateErode3D>::New();
101 this->
LinesImage = vtkSmartPointer<vtkImageData>::New();
104 this->
LinesImage->SetExtent(0, 0, 0, 0, 0, 0);
127 XML_VERIFY_ELEMENT(processingElement, this->
GetTagName());
130 vtkSmartPointer<vtkXMLDataElement> scanConversionElement = processingElement->FindNestedElementWithName(
"ScanConversion");
131 if (scanConversionElement != NULL)
134 const char* transducerGeometry = scanConversionElement->GetAttribute(
"TransducerGeometry");
135 if (transducerGeometry == NULL)
137 LOG_ERROR(
"Scan converter TransducerGeometry is undefined");
142 LOG_INFO(
"Scan converter is defined.");
145 vtkSmartPointer<vtkPlusUsScanConvert> scanConverter;
146 if (STRCASECMP(transducerGeometry,
"CURVILINEAR") == 0)
150 else if (STRCASECMP(transducerGeometry,
"LINEAR") == 0)
156 LOG_ERROR(
"Invalid scan converter TransducerGeometry: " << transducerGeometry);
159 this->
ScanConverter->ReadConfiguration(scanConversionElement);
161 XML_READ_SCALAR_ATTRIBUTE_OPTIONAL(
int,
RadiusStartMm, scanConversionElement);
162 XML_READ_SCALAR_ATTRIBUTE_OPTIONAL(
int,
RadiusStopMm, scanConversionElement);
163 XML_READ_SCALAR_ATTRIBUTE_OPTIONAL(
int,
ThetaStartDeg, scanConversionElement);
164 XML_READ_SCALAR_ATTRIBUTE_OPTIONAL(
int,
ThetaStopDeg, scanConversionElement);
168 LOG_INFO(
"ScanConversion section not found in config file!");
172 vtkXMLDataElement* imageProcessingOperations = processingElement->FindNestedElementWithName(
"ImageProcessingOperations");
173 if (imageProcessingOperations != NULL)
177 vtkSmartPointer<vtkXMLDataElement> saveIntermediateResultsBool = imageProcessingOperations->FindNestedElementWithName(
"SaveIntermediateResults");
178 if (saveIntermediateResultsBool == NULL)
180 LOG_WARNING(
"Unable to locate SaveIntermediateResults element. Using default value: " << std::boolalpha << (this->
SaveIntermediateResults));
188 vtkSmartPointer<vtkXMLDataElement> gaussianParameters = imageProcessingOperations->FindNestedElementWithName(
"GaussianSmoothing");
189 if (gaussianParameters == NULL)
191 LOG_WARNING(
"Unable to locate GaussianSmoothing parameters element. Using default values.");
195 XML_READ_SCALAR_ATTRIBUTE_REQUIRED(
double,
GaussianStdDev, gaussianParameters);
200 vtkSmartPointer<vtkXMLDataElement> islandRemovalParameters = imageProcessingOperations->FindNestedElementWithName(
"IslandRemoval");
201 if (islandRemovalParameters == NULL)
203 LOG_WARNING(
"Unable to locate IslandRemoval parameters element. Using default values.");
211 vtkSmartPointer<vtkXMLDataElement> erosionParameters = imageProcessingOperations->FindNestedElementWithName(
"Erosion");
212 if (erosionParameters == NULL)
214 LOG_WARNING(
"Unable to locate Erosion paramters element. Using default values.");
218 XML_READ_VECTOR_ATTRIBUTE_REQUIRED(
int, 2,
ErosionKernelSize, erosionParameters);
222 vtkSmartPointer<vtkXMLDataElement> dilationParameters = imageProcessingOperations->FindNestedElementWithName(
"Dilation");
223 if (dilationParameters == NULL)
225 LOG_WARNING(
"Unable to locate Dilation parameters element. Using default values.");
235 LOG_INFO(
"ImageProcessingOperations section not found in config file");
236 LOG_INFO(
"Enabling all filters and using default values.");
253 XML_VERIFY_ELEMENT(processingElement, this->
GetTagName());
260 XML_FIND_NESTED_ELEMENT_CREATE_IF_MISSING(scanConversionElement, processingElement,
"ScanConversion");
261 this->
ScanConverter->WriteConfiguration(scanConversionElement);
262 scanConversionElement->SetDoubleAttribute(
"RadiusStartMm", this->
RadiusStartMm);
263 scanConversionElement->SetDoubleAttribute(
"RadiusStopMm", this->
RadiusStopMm);
264 scanConversionElement->SetIntAttribute(
"ThetaStartDeg", this->
ThetaStartDeg);
265 scanConversionElement->SetIntAttribute(
"ThetaStopDeg", this->
ThetaStopDeg);
268 XML_FIND_NESTED_ELEMENT_CREATE_IF_MISSING(imageProcessingOperations, processingElement,
"ImageProcessingOperations");
270 XML_FIND_NESTED_ELEMENT_CREATE_IF_MISSING(saveIntermediateResultsBool, imageProcessingOperations,
"SaveIntermediateResults");
273 XML_FIND_NESTED_ELEMENT_CREATE_IF_MISSING(gaussianParameters, imageProcessingOperations,
"GaussianSmoothing");
274 gaussianParameters->SetDoubleAttribute(
"GaussianStdDev", this->
GaussianStdDev);
275 gaussianParameters->SetDoubleAttribute(
"GaussianKernelSize", this->
GaussianKernelSize);
277 XML_FIND_NESTED_ELEMENT_CREATE_IF_MISSING(islandRemovalParameters, imageProcessingOperations,
"IslandRemoval");
280 XML_FIND_NESTED_ELEMENT_CREATE_IF_MISSING(erosionParameters, imageProcessingOperations,
"Erosion");
281 erosionParameters->SetVectorAttribute(
"ErosionKernelSize", 2, this->
ErosionKernelSize);
283 XML_FIND_NESTED_ELEMENT_CREATE_IF_MISSING(dilationParameters, imageProcessingOperations,
"Dilation");
284 dilationParameters->SetVectorAttribute(
"DilationKernelSize", 2, this->
DilationKernelSize);
293 int* linesImageExtent = this->
ScanConverter->GetInputImageExtent();
295 LOG_DEBUG(
"Lines image extent: " 296 << linesImageExtent[0] <<
", " << linesImageExtent[1]
297 <<
", " << linesImageExtent[2] <<
", " << linesImageExtent[3]
298 <<
", " << linesImageExtent[4] <<
", " << linesImageExtent[5]);
303 this->
LinesImage->SetExtent(linesImageExtent);
304 this->
LinesImage->AllocateScalars(VTK_UNSIGNED_CHAR, 1);
307 int dims[3] = { 0, 0, 0 };
318 int* linesImageExtent = this->
ScanConverter->GetInputImageExtent();
319 int lineLengthPx = linesImageExtent[1] - linesImageExtent[0] + 1;
320 int numScanLines = linesImageExtent[3] - linesImageExtent[2] + 1;
326 double sumSquareDiff = 0.0;
328 double currentValue = 0.0;
329 double valueMeanDiff = 0.0;
331 double directionVectorX;
332 double directionVectorY;
336 int* inputExtent = inputImageData->GetExtent();
337 for (
int scanLine = 0; scanLine < numScanLines; ++scanLine)
339 double start[4] = { 0, 0, 0, 0 };
340 double end[4] = { 0, 0, 0, 0 };
343 directionVectorX = static_cast<double>(end[0] -
start[0]) / (lineLengthPx - 1);
344 directionVectorY = static_cast<double>(end[1] -
start[1]) / (lineLengthPx - 1);
345 for (
int pointIndex = 0; pointIndex < lineLengthPx; ++pointIndex)
347 pixelCoordX =
start[0] + directionVectorX * pointIndex;
348 pixelCoordY =
start[1] + directionVectorY * pointIndex;
349 if (pixelCoordX < inputExtent[0] || pixelCoordX > inputExtent[1]
350 || pixelCoordY < inputExtent[2] || pixelCoordY > inputExtent[3])
352 this->
LinesImage->SetScalarComponentFromFloat(pointIndex, scanLine, 0, 0, 0);
355 currentValue = inputImageData->GetScalarComponentAsDouble(pixelCoordX, pixelCoordY, 0, 0);
356 this->
LinesImage->SetScalarComponentFromFloat(pointIndex, scanLine, 0, 0, currentValue);
359 valueMeanDiff = currentValue - mean;
360 mean = mean + valueMeanDiff / pixelCount;
361 sumSquareDiff = sumSquareDiff + valueMeanDiff * (currentValue - mean);
369 unsigned char* vOutput = 0;
370 unsigned char edgeDetectorOutput0;
371 unsigned char edgeDetectorOutput1;
375 int dims[3] = { 0, 0, 0 };
379 for (
int y = dims[1] - 1;
y >= 0; --
y)
383 for (
int x = dims[0] - 1;
x >= 0; --
x)
385 edgeDetectorOutput0 = static_cast<unsigned char>(inputImage->GetScalarComponentAsFloat(
x,
y, 0, 0));
386 edgeDetectorOutput1 = static_cast<unsigned char>(inputImage->GetScalarComponentAsFloat(
x,
y, 0, 1));
387 vOutput = static_cast<unsigned char*>(this->
ConversionImage->GetScalarPointer(
x,
y, 0));
388 output = (float)(edgeDetectorOutput0 + edgeDetectorOutput1) / (float)2;
390 *vOutput = (
unsigned char)std::max(0, std::min(255, (
int)output));
402 int dims[3] = { 0, 0, 0 };
403 inputImage->GetDimensions(dims);
407 unsigned char* vOutput;
409 int lastVistedValue = 0;
412 std::map<std::string, int> currentBoneArea;
413 int boneAreaStart = dims[1] - 1;
414 int boneDepthSum = 0;
415 int boneMaxDepth = dims[0] - 1;
416 int boneMinDepth = 0;
417 int boneAreaDifferenceSlope = 3;
419 for (
int y = dims[1] - 1;
y >= 0; --
y)
426 for (
int x = dims[0] - 1;
x >= 0; --
x)
428 vOutput = static_cast<unsigned char*>(inputImage->GetScalarPointer(
x,
y, 0));
440 if (foundBone ==
false)
446 if (std::abs(
x - lastVistedValue) >= boneAreaDifferenceSlope &&
y != dims[1] - 1)
449 if (boneDepthSum != 0)
452 currentBoneArea[
"depth"] = boneDepthSum / (boneAreaStart -
y);
453 currentBoneArea[
"xMax"] = boneMaxDepth;
455 currentBoneArea[
"yMax"] = boneAreaStart;
456 currentBoneArea[
"yMin"] =
y + 1;
458 currentBoneArea.clear();
467 if (
x > boneMaxDepth)
471 if (
x < boneMinDepth)
482 if (foundBone ==
true && keepInfoCounter != 0)
493 if (foundBone ==
false)
496 if (boneDepthSum != 0)
499 currentBoneArea[
"depth"] = boneDepthSum / (boneAreaStart -
y);
500 currentBoneArea[
"xMax"] = boneMaxDepth;
502 currentBoneArea[
"yMax"] = boneAreaStart;
503 currentBoneArea[
"yMin"] =
y + 1;
506 currentBoneArea.clear();
508 boneMaxDepth = dims[0] - 1;
511 boneAreaStart =
y - 1;
516 if (boneDepthSum != 0)
519 currentBoneArea[
"depth"] = boneDepthSum / (boneAreaStart + 1);
520 currentBoneArea[
"xMax"] = boneMaxDepth;
522 currentBoneArea[
"yMax"] = boneAreaStart;
523 currentBoneArea[
"yMin"] = 0;
525 currentBoneArea.clear();
533 int fatLayerToCut = 20;
536 unsigned char* vOutput = 0;
538 int dims[3] = { 0, 0, 0 };
539 inputImage->GetDimensions(dims);
548 float meanDiffAverage;
549 float thresholdValue;
551 for (
int y = dims[1] - 1;
y >= 0; --
y)
560 for (
int x = dims[0] - 1;
x >= fatLayerToCut; --
x)
562 vInput = inputImage->GetScalarComponentAsFloat(
x,
y, 0, 0);
564 squearSum += vInput * vInput;
571 pixelAverage = pixelSum / (dims[0] - fatLayerToCut);
574 meanDiffSum = squearSum + (dims[0] - fatLayerToCut) * pixelAverage * pixelAverage + (-2 * pixelAverage * pixelSum);
575 meanDiffAverage = meanDiffSum / (dims[0] - fatLayerToCut);
576 thresholdValue = max - 3 * pow(meanDiffAverage, 0.5f);
582 for (
int x = dims[0] - 1;
x >= 0; --
x)
584 vOutput = static_cast<unsigned char*>(inputImage->GetScalarPointer(
x,
y, 0));
585 if (*vOutput < thresholdValue && *vOutput != 0)
599 unsigned char* inputPixelPointer = 0;
601 int dims[3] = { 0, 0, 0 };
604 for (
int y = dims[1] - 1;
y >= 0; --
y)
608 for (
int x = dims[0] - 1;
x >= 0; --
x)
610 if (static_cast<unsigned char>(MaskImage->GetScalarComponentAsFloat(
x,
y, 0, 0)) > 0)
616 inputPixelPointer = static_cast<unsigned char*>(InputImage->GetScalarPointer(
x,
y, 0));
617 *inputPixelPointer = 0;
642 igsioVideoFrame* outputImage = outputFrame->GetImageData();
647 outputImage->DeepCopyFrom(inputImage);
662 igsioVideoFrame* inputImage = inputFrame->GetImageData();
664 vtkSmartPointer<vtkImageData> intermediateImage = vtkSmartPointer<vtkImageData>::New();
678 intermediateImage->DeepCopy(this->
LinesImage);
680 return intermediateImage;
771 for (
int postfixIndex = this->
IntermediatePostfixes.size() - 1; postfixIndex >= 0; postfixIndex -= 1)
788 std::map<char*, vtkSmartPointer<vtkIGSIOTrackedFrameList> >::iterator indexIterator = this->
IntermediateImageMap.find(fileNamePostfix);
794 LOG_ERROR(
"An issue occured when trying to save the intermediate image with the postfix: " << fileNamePostfix);
799 LOG_INFO(
"Sucessfully wrote the intermediate image with the postfix: " << fileNamePostfix);
809 if (fileNamePostfix ==
"")
811 LOG_WARNING(
"The empty string was given as an intermediate image file postfix.");
815 std::map<char*, vtkSmartPointer<vtkIGSIOTrackedFrameList> >::iterator indexIterator = this->
IntermediateImageMap.find(fileNamePostfix);
826 igsioVideoFrame linesVideoFrame;
827 linesVideoFrame.DeepCopyFrom(image);
828 igsioTrackedFrame linesTrackedFrame;
829 linesTrackedFrame.SetImageData(linesVideoFrame);
837 if (fileNamePostfix ==
"")
839 LOG_WARNING(
"The empty string was given as an intermediate image file postfix.");
842 vtkSmartPointer<vtkImageData> tempOutputImage = vtkSmartPointer<vtkImageData>::New();
843 imageFilter->SetOutput(tempOutputImage);
844 imageFilter->Update();
866 if (islandAreaThreshold < 0)
vtkSmartPointer< vtkImageGaussianSmooth > GaussianSmooth
vtkSmartPointer< vtkImageSobel2D > EdgeDetector
void FillLinesImage(vtkSmartPointer< vtkImageData > inputImageData)
void VectorImageToUchar(vtkSmartPointer< vtkImageData > inputImage)
vtkSmartPointer< vtkImageDilateErode3D > ImageDialator
virtual PlusStatus ProcessImageExtents()
void ImageConjunction(vtkSmartPointer< vtkImageData > inputImage, vtkSmartPointer< vtkImageData > maskImage)
virtual PlusStatus WriteConfiguration(vtkSmartPointer< vtkXMLDataElement > processingElement)
int DilationKernelSize[2]
double GaussianKernelSize
PlusStatus SaveAllIntermediateResultsToFile()
vtkSmartPointer< vtkPlusUsScanConvert > ScanConverter
void MarkShadowOutline(vtkSmartPointer< vtkImageData > inputImage)
static vtkPlusUsScanConvertLinear * New()
virtual void PrintSelf(ostream &os, vtkIndent indent) VTK_OVERRIDE
virtual const char * GetProcessorTypeName()
vtkStandardNewMacro(vtkPlusBoneEnhancer)
vtkSmartPointer< vtkImageThreshold > ImageBinarizer
virtual ~vtkPlusBoneEnhancer()
static igsioStatus Write(const std::string &filename, igsioTrackedFrame *frame, US_IMAGE_ORIENTATION orientationInFile=US_IMG_ORIENT_MF, bool useCompression=true, bool EnableImageDataWrite=true)
vtkSmartPointer< vtkImageData > ProcessedLinesImage
vtkSmartPointer< vtkImageIslandRemoval2D > IslandRemover
static vtkPlusUsScanConvertCurvilinear * New()
void AddIntermediateFromFilter(char *fileNamePostfix, vtkImageAlgorithm *imageAlgorithm)
std::vector< char * > IntermediatePostfixes
virtual void PrintSelf(ostream &os, vtkIndent indent)
void AddIntermediateImage(char *fileNamePostfix, vtkSmartPointer< vtkImageData > image)
virtual void SetDilationKernelSize(int, int)
void SetGaussianStdDev(double GaussianStdDev)
virtual void SetErosionKernelSize(int, int)
virtual PlusStatus ProcessFrame(igsioTrackedFrame *inputFrame, igsioTrackedFrame *outputFrame)
PlusStatus SaveIntermediateResultToFile(char *fileNamePostfix)
std::string IntermediateImageFileName
Direction vectors of rods y
void LinearToFanImage(vtkSmartPointer< vtkImageData > inputImage, igsioTrackedFrame *outputFrame)
void ThresholdViaStdDeviation(vtkSmartPointer< vtkImageData > inputImage)
static const char * GetTagName()
void SetGaussianKernelSize(double GaussianKernelSize)
vtkSmartPointer< vtkImageData > ConversionImage
vtkSmartPointer< vtkImageDilateErode3D > ImageEroder
std::map< char *, vtkSmartPointer< vtkIGSIOTrackedFrameList > > IntermediateImageMap
bool SaveIntermediateResults
vtkSmartPointer< vtkImageData > UnprocessedFrameToLinearImage(igsioTrackedFrame *inputFrame)
std::vector< std::map< std::string, int > > BoneAreasInfo
vtkSmartPointer< vtkImageData > BinaryImageForMorphology
void SetIslandAreaThreshold(int islandAreaThreshold)
int NumberOfSamplesPerScanLine
vtkSmartPointer< vtkImageData > LinesImage
virtual PlusStatus ReadConfiguration(vtkSmartPointer< vtkXMLDataElement > processingElement)
void RemoveNoise(vtkSmartPointer< vtkImageData > inputImage)
Localize bone surfaces in ultrasound images.