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