1 /*=========================================================================
2
3 Program: Visualization Toolkit
4 Module: vtkImageSeedConnectivity.cxx
5
6 Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7 All rights reserved.
8 See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9
10 This software is distributed WITHOUT ANY WARRANTY; without even
11 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12 PURPOSE. See the above copyright notice for more information.
13
14 =========================================================================*/
15 #include "vtkImageSeedConnectivity.h"
16
17 #include "vtkImageConnector.h"
18 #include "vtkImageData.h"
19 #include "vtkInformation.h"
20 #include "vtkInformationVector.h"
21 #include "vtkObjectFactory.h"
22 #include "vtkStreamingDemandDrivenPipeline.h"
23
24 vtkStandardNewMacro(vtkImageSeedConnectivity);
25
26 //----------------------------------------------------------------------------
vtkImageSeedConnectivity()27 vtkImageSeedConnectivity::vtkImageSeedConnectivity()
28 {
29 this->InputConnectValue = 255;
30 this->OutputConnectedValue = 255;
31 this->OutputUnconnectedValue = 0;
32 this->Seeds = NULL;
33 this->Connector = vtkImageConnector::New();
34 this->Dimensionality = 3;
35 }
36
37 //----------------------------------------------------------------------------
~vtkImageSeedConnectivity()38 vtkImageSeedConnectivity::~vtkImageSeedConnectivity()
39 {
40 this->Connector->Delete();
41 this->RemoveAllSeeds();
42 }
43
44 //----------------------------------------------------------------------------
RemoveAllSeeds()45 void vtkImageSeedConnectivity::RemoveAllSeeds()
46 {
47 vtkImageConnectorSeed *temp;
48 while (this->Seeds)
49 {
50 temp = this->Seeds;
51 this->Seeds = temp->Next;
52 delete temp;
53 }
54 }
55
56 //----------------------------------------------------------------------------
AddSeed(int num,int * index)57 void vtkImageSeedConnectivity::AddSeed(int num, int *index)
58 {
59 int idx, newIndex[3];
60 vtkImageConnectorSeed *seed;
61
62 if (num > 3)
63 {
64 num = 3;
65 }
66 for (idx = 0; idx < num; ++idx)
67 {
68 newIndex[idx] = index[idx];
69 }
70 for (idx = num; idx < 3; ++idx)
71 {
72 newIndex[idx] = 0;
73 }
74 seed = this->Connector->NewSeed(newIndex, NULL);
75 seed->Next = this->Seeds;
76 this->Seeds = seed;
77 this->Modified();
78 }
79
80 //----------------------------------------------------------------------------
AddSeed(int i0,int i1,int i2)81 void vtkImageSeedConnectivity::AddSeed(int i0, int i1, int i2)
82 {
83 int index[3];
84
85 index[0] = i0;
86 index[1] = i1;
87 index[2] = i2;
88 this->AddSeed(3, index);
89 }
90
91 //----------------------------------------------------------------------------
AddSeed(int i0,int i1)92 void vtkImageSeedConnectivity::AddSeed(int i0, int i1)
93 {
94 int index[2];
95
96 index[0] = i0;
97 index[1] = i1;
98 this->AddSeed(2, index);
99 }
100
101 //----------------------------------------------------------------------------
RequestUpdateExtent(vtkInformation * vtkNotUsed (request),vtkInformationVector ** inputVector,vtkInformationVector * vtkNotUsed (outputVector))102 int vtkImageSeedConnectivity::RequestUpdateExtent(
103 vtkInformation *vtkNotUsed(request),
104 vtkInformationVector **inputVector,
105 vtkInformationVector *vtkNotUsed(outputVector))
106 {
107 vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
108 inInfo->Set(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT(),
109 inInfo->Get(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT()),
110 6);
111
112 return 1;
113 }
114
115 //----------------------------------------------------------------------------
RequestData(vtkInformation * vtkNotUsed (request),vtkInformationVector ** inputVector,vtkInformationVector * outputVector)116 int vtkImageSeedConnectivity::RequestData(
117 vtkInformation *vtkNotUsed(request),
118 vtkInformationVector **inputVector,
119 vtkInformationVector *outputVector)
120 {
121 vtkInformation *inInfo = inputVector[0]->GetInformationObject(0);
122 vtkInformation *outInfo = outputVector->GetInformationObject(0);
123
124 vtkImageData *inData = vtkImageData::SafeDownCast(
125 inInfo->Get(vtkDataObject::DATA_OBJECT()));
126 vtkImageData *outData = vtkImageData::SafeDownCast(
127 outInfo->Get(vtkDataObject::DATA_OBJECT()));
128
129 vtkImageConnectorSeed *seed;
130 int idx0, idx1, idx2;
131 vtkIdType inInc0, inInc1, inInc2;
132 vtkIdType outInc0, outInc1, outInc2;
133 int min0, max0, min1, max1, min2, max2;
134 unsigned char *inPtr0, *inPtr1, *inPtr2;
135 unsigned char *outPtr0, *outPtr1, *outPtr2;
136 unsigned char temp1, temp2;
137 int temp;
138
139 outData->SetExtent(
140 outInfo->Get(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT()));
141 outData->AllocateScalars(outInfo);
142
143 if (inData->GetScalarType() != VTK_UNSIGNED_CHAR ||
144 outData->GetScalarType() != VTK_UNSIGNED_CHAR)
145 {
146 vtkErrorMacro("Execute: Both input and output must have scalar type UnsignedChar");
147 return 1;
148 }
149
150 // Pick an intermediate value (In some cases, we could eliminate the last threshold.)
151 temp1 = 1;
152 while (temp1 == this->InputConnectValue ||
153 temp1 == this->OutputUnconnectedValue ||
154 temp1 == this->OutputConnectedValue)
155 {
156 ++temp1;
157 }
158 temp2 = temp1 + 1;
159 while (temp2 == this->InputConnectValue ||
160 temp2 == this->OutputUnconnectedValue ||
161 temp2 == this->OutputConnectedValue)
162 {
163 ++temp2;
164 }
165
166 //-------
167 // threshold to eliminate unknown values ( only intermediate and 0)
168 inData->GetIncrements(inInc0, inInc1, inInc2);
169 this->GetOutput()->GetExtent(min0, max0, min1, max1, min2, max2);
170 outData->GetIncrements(outInc0, outInc1, outInc2);
171 inPtr2 = static_cast<unsigned char *>(
172 inData->GetScalarPointer(min0,min1,min2));
173 outPtr2 = static_cast<unsigned char *>(
174 outData->GetScalarPointer(min0,min1,min2));
175 for (idx2 = min2; idx2 <= max2; ++idx2)
176 {
177 inPtr1 = inPtr2;
178 outPtr1 = outPtr2;
179 for (idx1 = min1; idx1 <= max1; ++idx1)
180 {
181 inPtr0 = inPtr1;
182 outPtr0 = outPtr1;
183 for (idx0 = min0; idx0 <= max0; ++idx0)
184 {
185 if (*inPtr0 == this->InputConnectValue)
186 {
187 *outPtr0 = temp1;
188 }
189 else
190 {
191 *outPtr0 = 0;
192 }
193 inPtr0 += inInc0;
194 outPtr0 += outInc0;
195 }
196 inPtr1 += inInc1;
197 outPtr1 += outInc1;
198 }
199 inPtr2 += inInc2;
200 outPtr2 += outInc2;
201 }
202
203 this->UpdateProgress(0.2);
204 if (this->AbortExecute)
205 {
206 return 1;
207 }
208
209 //-------
210 // find actual seeds in this image. (only scan along the first axis for now)
211 this->Connector->RemoveAllSeeds();
212 seed = this->Seeds;
213 while (seed)
214 {
215 temp = seed->Index[0];
216 // make sure z value of seed is acceptable
217 if (seed->Index[2] < min2)
218 {
219 seed->Index[2] = min2;
220 }
221 if (seed->Index[2] > max2)
222 {
223 seed->Index[2] = max2;
224 }
225 outPtr0 = static_cast<unsigned char *>(
226 outData->GetScalarPointer(seed->Index));
227 for (idx0 = temp; idx0 <= max0; ++idx0)
228 {
229 if (*outPtr0 == temp1)
230 { // we found our seed
231 seed->Index[0] = idx0;
232 this->Connector->AddSeed(this->Connector->NewSeed(seed->Index, outPtr0));
233 seed->Index[0] = temp;
234 break;
235 }
236 outPtr0 += outInc0;
237 }
238 seed = seed->Next;
239 }
240
241 this->UpdateProgress(0.5);
242 if (this->AbortExecute)
243 {
244 return 1;
245 }
246
247 //-------
248 // connect
249 this->Connector->SetUnconnectedValue(temp1);
250 this->Connector->SetConnectedValue(temp2);
251 this->Connector->MarkData(outData, this->Dimensionality,
252 this->GetOutput()->GetExtent());
253
254 this->UpdateProgress(0.9);
255 if (this->AbortExecute)
256 {
257 return 1;
258 }
259
260 //-------
261 // Threshold to convert intermediate values into OutputUnconnectedValues
262 outPtr2 = static_cast<unsigned char *>(
263 outData->GetScalarPointer(min0,min1,min2));
264 for (idx2 = min2; idx2 <= max2; ++idx2)
265 {
266 outPtr1 = outPtr2;
267 for (idx1 = min1; idx1 <= max1; ++idx1)
268 {
269 outPtr0 = outPtr1;
270 for (idx0 = min0; idx0 <= max0; ++idx0)
271 {
272 if (*outPtr0 == temp2)
273 {
274 *outPtr0 = this->OutputConnectedValue;
275 }
276 else
277 {
278 *outPtr0 = this->OutputUnconnectedValue;
279 }
280 outPtr0 += outInc0;
281 }
282 outPtr1 += outInc1;
283 }
284 outPtr2 += outInc2;
285 }
286
287 return 1;
288 }
289
PrintSelf(ostream & os,vtkIndent indent)290 void vtkImageSeedConnectivity::PrintSelf(ostream& os, vtkIndent indent)
291 {
292 this->Superclass::PrintSelf(os,indent);
293
294 if ( this->Connector )
295 {
296 os << indent << "Connector: " << this->Connector << "\n";
297 }
298 else
299 {
300 os << indent << "Connector: (none)\n";
301 }
302
303 os << indent << "Dimensionality: " << this->Dimensionality << "\n";
304 os << indent << "InputConnectValue: " << this->InputConnectValue << "\n";
305 os << indent << "OutputConnectedValue: " << this->OutputConnectedValue << "\n";
306 os << indent << "OutputUnconnectedValue: " << this->OutputUnconnectedValue << "\n";
307 }
308