PlusLib  2.9.0
Software library for tracked ultrasound image acquisition, calibration, and processing.
vtkPlusTransverseProcessEnhancer.cxx
Go to the documentation of this file.
1 /*=Plus=header=begin======================================================
2 Program: Plus
3 Copyright (c) Laboratory for Percutaneous Surgery. All rights reserved.
4 See License.txt for details.
5 =========================================================Plus=header=end*/
6 
7 // Local includes
8 #include "PlusConfigure.h"
9 #include "PlusMath.h"
10 #include "igsioTrackedFrame.h"
11 #include "igsioVideoFrame.h"
12 #include "vtkIGSIOTrackedFrameList.h"
16 
17 // VTK includes
18 #include <vtkImageAccumulate.h>
19 #include <vtkImageCast.h>
20 #include <vtkImageDilateErode3D.h>
21 #include <vtkImageGaussianSmooth.h>
22 #include <vtkImageIslandRemoval2D.h>
23 #include <vtkImageSobel2D.h>
24 #include <vtkImageThreshold.h>
25 #include <vtkObjectFactory.h>
26 
27 #include <cmath>
28 
29 //----------------------------------------------------------------------------
31 
32 //----------------------------------------------------------------------------
34 {
35 }
36 
37 //----------------------------------------------------------------------------
39 {
40 }
41 
42 //----------------------------------------------------------------------------
43 void vtkPlusTransverseProcessEnhancer::PrintSelf(ostream& os, vtkIndent indent)
44 {
45  this->Superclass::PrintSelf(os, indent);
46 }
47 
48 //----------------------------------------------------------------------------
49 // Takes a vtkSmartPointer<vtkImageData> with clearly defined possible bone segments as an
50 // argument and modifies it so the bone areas that are too close to the camera's edge are removed.
51 void vtkPlusTransverseProcessEnhancer::RemoveOffCameraBones(vtkSmartPointer<vtkImageData> inputImage)
52 {
53  int dims[3] = { 0, 0, 0 };
54  inputImage->GetDimensions(dims);
55 
56  unsigned char* vOutput = 0;
57 
58  int distanceVerticalBuffer = 10; // For a bone to be valid, it must be this distance from the transducer
59  int distanceHorizontalBuffer = 20; // For a bone to be valid, it must be this distance from the horizontal sides of the frame
60  int boneMinSize = 10; // Minimum bone size a bone must have to be valid
61  std::vector<std::map<std::string, int> > boneAreas = this->BoneAreasInfo;
62 
63  int boneHalfLen;
64  bool clearArea;
65  bool foundBone;
66 
67  this->BoneAreasInfo.clear();
68 
69  for (int areaIndex = boneAreas.size() - 1; areaIndex >= 0; --areaIndex)
70  {
71  std::map<std::string, int> currentArea = boneAreas.at(areaIndex);
72 
73  clearArea = false;
74  boneHalfLen = ((currentArea["yMax"] - currentArea["yMin"]) + 1) / 2;
75 
76  //check if the bone is to close too the scan's edge
77  if (currentArea["yMax"] + distanceVerticalBuffer >= dims[1] - 1 || currentArea["yMin"] - distanceVerticalBuffer <= 0)
78  {
79  clearArea = true;
80  }
81  //check if given the size, the bone is too close to the scan's edge
82  else if (boneHalfLen + currentArea["yMax"] >= dims[1] - 1 || (currentArea["yMin"] - 1) - boneHalfLen <= 0)
83  {
84  clearArea = true;
85  }
86  //check if the bone is too close/far from the transducer
87  else if (currentArea["depth"] < distanceHorizontalBuffer || currentArea["depth"] > dims[0] - distanceHorizontalBuffer)
88  {
89  clearArea = true;
90  }
91  //check if the bone is to small
92  else if (currentArea["yMax"] - currentArea["yMin"] <= boneMinSize)
93  {
94  clearArea = true;
95  }
96 
97  //If it does not meet the criteria, remove the bones in this area
98  if (clearArea == true)
99  {
100  //search through the area where the pixels are known to be
101  for (int y = currentArea["yMax"]; y >= currentArea["yMin"]; --y)
102  {
103  int x = currentArea["xMax"] - this->BonePushBackPx;
104  foundBone = false;
105  while (x >= currentArea["xMin"] - this->BonePushBackPx && x >= 0 && foundBone == false)
106  {
107  vOutput = static_cast<unsigned char*>(inputImage->GetScalarPointer(x, y, 0));
108  if (*vOutput != 0)
109  {
110  //remove all pixels in the outline
111  *vOutput = 0;
112  for (int removeBonex = std::max(0, x - (this->BoneOutlineDepthPx - 1)); removeBonex < x; ++removeBonex)
113  {
114  vOutput = static_cast<unsigned char*>(inputImage->GetScalarPointer(removeBonex, y, 0));
115  *vOutput = 0;
116  }
117 
118  foundBone = true;
119  }
120  x--;
121  }
122  }
123  }
124  else
125  {
126  this->BoneAreasInfo.push_back(currentArea);
127  }
128  }
129 }
130 
131 //----------------------------------------------------------------------------
132 // Takes an unmodified vtkSmartPointer<vtkImageData> of an ultrasound as its first argument, and a more
133 // enhanced version of said image, with clearly defined possible bone segments as the second argument.
134 // This function modifies the second argument so as to remove any bone segments that have a higher
135 // amount of bone potential in the areas next to it than there is within the areas themselves.
136 void vtkPlusTransverseProcessEnhancer::CompareShadowAreas(vtkSmartPointer<vtkImageData> originalImage, vtkSmartPointer<vtkImageData> inputImage)
137 {
138  int dims[3] = { 0, 0, 0 };
139  inputImage->GetDimensions(dims);
140 
141  float vInput = 0;
142  unsigned char* vOutput = 0;
143 
144  //Variables used for measuring the size and intensity sum for bone, above, and below areas
145  int boneLen;
146  int boneHalfLen;
147  float boneArea;
148  float aboveSum;
149  float areaSum;
150  float belowSum;
151 
152  float aboveAvgShadow; //Shadow intensity of the above area
153  float areaAvgShadow; //Shadow intensity of the area
154  float belowAvgShadow; //Shadow intensity of the below area
155 
156  std::map<std::string, int> currentArea;
157  std::vector<std::map<std::string, int> > boneAreas = this->BoneAreasInfo;
158 
159  bool foundBone;
160  this->BoneAreasInfo.clear();
161 
162  for (int areaIndex = boneAreas.size() - 1; areaIndex >= 0; --areaIndex)
163  {
164  currentArea = boneAreas.at(areaIndex);
165 
166  aboveSum = 0;
167  areaSum = 0;
168  belowSum = 0;
169 
170  boneLen = (currentArea["yMax"] - currentArea["yMin"]) + 1;
171  boneHalfLen = boneLen / 2;
172  boneArea = boneLen * currentArea["depth"];
173 
174  //gather sum of shadow areas from above the area
175  for (int y = currentArea["yMax"] + boneHalfLen; y > currentArea["yMax"]; --y)
176  {
177  for (int x = dims[0] - 1; x >= currentArea["depth"]; --x)
178  {
179  vInput = (originalImage->GetScalarComponentAsFloat(x, y, 0, 0));
180  aboveSum += vInput;
181  }
182  }
183  //gather sum of shadow areas from the area
184  for (int y = currentArea["yMax"]; y >= currentArea["yMin"]; --y)
185  {
186  for (int x = dims[0] - 1; x >= currentArea["depth"]; --x)
187  {
188  vInput = (originalImage->GetScalarComponentAsFloat(x, y, 0, 0));
189  areaSum += vInput;
190  }
191  }
192  //gather sum of shadow areas from below the area
193  for (int y = currentArea["yMin"] - boneHalfLen; y < currentArea["yMin"]; ++y)
194  {
195  for (int x = dims[0] - 1; x >= currentArea["depth"]; --x)
196  {
197  vInput = (originalImage->GetScalarComponentAsFloat(x, y, 0, 0));
198  belowSum += vInput;
199  }
200  }
201 
202  //Calculate average shadow intensity
203  aboveAvgShadow = aboveSum / (boneArea / 2);
204  areaAvgShadow = areaSum / boneArea;
205  belowAvgShadow = belowSum / (boneArea / 2);
206 
207  //If there is a higher amount of bones around it, remove the area
208  if (aboveAvgShadow - areaAvgShadow <= areaAvgShadow / 2 || belowAvgShadow - areaAvgShadow <= areaAvgShadow / 2)
209  {
210 
211  for (int y = currentArea["yMax"]; y >= currentArea["yMin"]; --y)
212  {
213  //search through the area where the pixels are known to be
214  int x = currentArea["xMax"] - this->BonePushBackPx;
215  foundBone = false;
216  while (x >= currentArea["xMin"] - this->BonePushBackPx && x >= 0 && foundBone == false)
217  {
218  vOutput = static_cast<unsigned char*>(inputImage->GetScalarPointer(x, y, 0));
219  if (*vOutput != 0)
220  {
221  //remove all pixels in the outline
222  *vOutput = 0;
223 
224  for (int removeBonex = std::max(0, x - (this->BoneOutlineDepthPx - 1)); removeBonex < x; ++removeBonex)
225  {
226  vOutput = static_cast<unsigned char*>(inputImage->GetScalarPointer(removeBonex, y, 0));
227  *vOutput = 0;
228  }
229  foundBone = true;
230  }
231  x--;
232  }
233  }
234  }
235  else
236  {
237  this->BoneAreasInfo.push_back(currentArea);
238  }
239  }
240 }
241 
242 //----------------------------------------------------------------------------
243 PlusStatus vtkPlusTransverseProcessEnhancer::ProcessFrame(igsioTrackedFrame* inputFrame, igsioTrackedFrame* outputFrame)
244 {
245 
246  this->BoneAreasInfo.clear();
247 
248  vtkSmartPointer<vtkImageData> intermediateImage = vtkPlusBoneEnhancer::UnprocessedFrameToLinearImage(inputFrame);
249  intermediateImage->DeepCopy(this->LinesImage);
250 
251  //Save this image so that it can be used for comparison with the output image
252  vtkSmartPointer<vtkImageData> originalImage = vtkSmartPointer<vtkImageData>::New();
253  originalImage->DeepCopy(intermediateImage);
254 
255  vtkPlusBoneEnhancer::RemoveNoise(intermediateImage);
256 
257  this->RemoveOffCameraBones(intermediateImage);
258  if (this->SaveIntermediateResults)
259  {
260  this->AddIntermediateImage("_09PostFilters_2PostRemoveOffCamera", intermediateImage);
261  }
262  this->CompareShadowAreas(originalImage, intermediateImage);
263  if (this->SaveIntermediateResults)
264  {
265  this->AddIntermediateImage("_09PostFilters_3PostCompareShadowAreas", intermediateImage);
266  }
267  vtkPlusBoneEnhancer::LinearToFanImage(intermediateImage, outputFrame);
268 
269  return PLUS_SUCCESS;
270 }
Localize transverse process bone surfaces in ultrasound images.
void RemoveOffCameraBones(vtkSmartPointer< vtkImageData > inputImage)
igsioStatus PlusStatus
Definition: PlusCommon.h:40
vtkStandardNewMacro(vtkPlusTransverseProcessEnhancer)
#define PLUS_SUCCESS
Definition: PlusCommon.h:44
virtual void PrintSelf(ostream &os, vtkIndent indent)
virtual void PrintSelf(ostream &os, vtkIndent indent)
void AddIntermediateImage(char *fileNamePostfix, vtkSmartPointer< vtkImageData > image)
int x
Definition: phidget22.h:4265
void CompareShadowAreas(vtkSmartPointer< vtkImageData > originalImage, vtkSmartPointer< vtkImageData > inputImage)
PlusStatus ProcessFrame(igsioTrackedFrame *inputFrame, igsioTrackedFrame *outputFrame)
Direction vectors of rods y
Definition: algo3.m:15
void LinearToFanImage(vtkSmartPointer< vtkImageData > inputImage, igsioTrackedFrame *outputFrame)
vtkSmartPointer< vtkImageData > UnprocessedFrameToLinearImage(igsioTrackedFrame *inputFrame)
std::vector< std::map< std::string, int > > BoneAreasInfo
vtkSmartPointer< vtkImageData > LinesImage
void RemoveNoise(vtkSmartPointer< vtkImageData > inputImage)
Localize bone surfaces in ultrasound images.