From: David Sarrut Date: Wed, 1 Feb 2012 06:20:06 +0000 (+0100) Subject: Merge branch 'master' of git.creatis.insa-lyon.fr:clitk X-Git-Tag: v1.3.0~104^2~13 X-Git-Url: https://git.creatis.insa-lyon.fr/pubgit/?a=commitdiff_plain;h=9a4dda175415c133b547eec505cd0497d3181f8d;hp=0421996ed3a4457ce867332574a192d5e214ea31;p=clitk.git Merge branch 'master' of git.creatis.insa-lyon.fr:clitk --- diff --git a/itk/clitkBoundingBoxUtils.h b/itk/clitkBoundingBoxUtils.h index 311e67d..2fcaddd 100644 --- a/itk/clitkBoundingBoxUtils.h +++ b/itk/clitkBoundingBoxUtils.h @@ -40,6 +40,13 @@ namespace clitk { typename itk::BoundingBox::Pointer bbi1, typename itk::BoundingBox::Pointer bbi2); + //-------------------------------------------------------------------- + template + void ComputeBBIntersection(typename itk::BoundingBox::Pointer bbo, + typename itk::BoundingBox::Pointer bbi1, + typename itk::BoundingBox::Pointer bbi2, + int dimension); + //-------------------------------------------------------------------- template void ComputeBBUnion(typename itk::BoundingBox::Pointer bbo, diff --git a/itk/clitkBoundingBoxUtils.txx b/itk/clitkBoundingBoxUtils.txx index d6fbc24..9f277cb 100644 --- a/itk/clitkBoundingBoxUtils.txx +++ b/itk/clitkBoundingBoxUtils.txx @@ -67,6 +67,24 @@ namespace clitk { ///-------------------------------------------------------------------- template + void ComputeBBIntersection(typename itk::BoundingBox::Pointer bbo, + typename itk::BoundingBox::Pointer bbi1, + typename itk::BoundingBox::Pointer bbi2, + int dimension) { + typedef itk::BoundingBox BBType; + typedef typename BBType::PointType PointType; + PointType lastPoint; + PointType firstPoint; + firstPoint[dimension] = std::max(bbi1->GetMinimum()[dimension], bbi2->GetMinimum()[dimension]); + lastPoint[dimension] = std::min(bbi1->GetMaximum()[dimension], bbi2->GetMaximum()[dimension]); + bbo->SetMaximum(lastPoint); + bbo->SetMinimum(firstPoint); + } + //-------------------------------------------------------------------- + + + //-------------------------------------------------------------------- + template void ComputeBBUnion(typename itk::BoundingBox::Pointer bbo, typename itk::BoundingBox::Pointer bbi1, typename itk::BoundingBox::Pointer bbi2) { diff --git a/itk/clitkRelativePositionAnalyzerFilter.txx b/itk/clitkRelativePositionAnalyzerFilter.txx index df12ea3..63af119 100644 --- a/itk/clitkRelativePositionAnalyzerFilter.txx +++ b/itk/clitkRelativePositionAnalyzerFilter.txx @@ -103,12 +103,17 @@ GenerateData() { ImagePointer temp = dynamic_cast(itk::ProcessObject::GetInput(0)); m_Object = dynamic_cast(itk::ProcessObject::GetInput(1)); - m_Target = dynamic_cast(itk::ProcessObject::GetInput(2)); + ImagePointer temp2 = dynamic_cast(itk::ProcessObject::GetInput(2)); // Remove object from support (keep initial image) m_Support = clitk::Clone(temp); clitk::AndNot(m_Support, m_Object, GetBackgroundValue()); + // Remove object from target. Important because sometimes, there is + // overlap between target and object. + m_Target = clitk::Clone(temp2); + clitk::AndNot(m_Target, m_Object, GetBackgroundValue()); + // Define filter to compute statics on mask image typedef itk::LabelStatisticsImageFilter StatFilterType; typename StatFilterType::Pointer statFilter = StatFilterType::New(); @@ -142,6 +147,9 @@ GenerateData() double mReverseThreshold=1.0; ComputeOptimalThresholds(map, m_Target, bins, tolerance, mThreshold, mReverseThreshold); + // DD(mThreshold); + // DD(mReverseThreshold); + // Use the threshold to compute new support int s1 = GetSupportSize(); if (mThreshold > 0.0) { @@ -176,6 +184,13 @@ GenerateData() s2 = statFilter->GetCount(GetForegroundValue()); } + // Check threshold, if we gain nothing, we force to max/min thresholds + // DD(GetSupportSize()); + // DD(s1); + // DD(s2); + if (s1 >= GetSupportSize()) mThreshold = 0.0; + if (s2 >= GetSupportSize()) mReverseThreshold = 1.0; + // Set results values m_Info.threshold = mThreshold; m_Info.sizeAfterThreshold = s1; @@ -210,15 +225,19 @@ ComputeFuzzyMap(ImageType * object, ImageType * target, ImageType * support, dou // sliceRelPosFilter->PrintOptions(); sliceRelPosFilter->Update(); typename FloatImageType::Pointer map = sliceRelPosFilter->GetFuzzyMap(); + writeImage(map, "fuzzy_0_"+toString(clitk::rad2deg(angle))+".mha"); - // Resize map like object to allow SetBackground - map = clitk::ResizeImageLike(map, object, GetBackgroundValue()); + // Resize object like map to allow SetBackground + ImagePointer temp = clitk::ResizeImageLike(object, map, GetBackgroundValue()); + // writeImage(map, "fuzzy_1_"+toString(clitk::rad2deg(angle))+".mha"); // Remove initial object from the fuzzy map - map = clitk::SetBackground(map, object, GetForegroundValue(), 0.0, true); + map = clitk::SetBackground(map, temp, GetForegroundValue(), 0.0, true); + writeImage(map, "fuzzy_2_"+toString(clitk::rad2deg(angle))+".mha"); // Resize the fuzzy map like the target, put 2.0 when outside map = clitk::ResizeImageLike(map, target, 2.0); // Put 2.0 when out of initial map + writeImage(map, "fuzzy_3_"+toString(clitk::rad2deg(angle))+".mha"); // end return map; @@ -239,9 +258,10 @@ ComputeOptimalThresholds(FloatImageType * map, ImageType * target, int bins, dou f->SetInput(map); f->SetLabelInput(target); f->UseHistogramsOn(); - f->SetHistogramParameters(bins, 0.0, 1.1); + f->SetHistogramParameters(bins, 0.0-(1.0/bins), 1.0+(1.0/bins)); f->Update(); int count = f->GetCount(GetForegroundValue()); + // DD(count); typename FloatStatFilterType::HistogramPointer h = f->GetHistogram(GetForegroundValue()); // Debug : dump histogram @@ -253,18 +273,34 @@ ComputeOptimalThresholds(FloatImageType * map, ImageType * target, int bins, dou << "\t" << (double)h->GetFrequency(j)/(double)count << std::endl; } histogramFile.close(); + std::ofstream histogramFile2(std::string("fuzzy_histo_R_"+toString(i)+".txt").c_str()); + for(int j=bins-1; j>=0; j--) { + histogramFile2 << h->GetMeasurement(j,0) + << "\t" << h->GetFrequency(j) + << "\t" << (double)h->GetFrequency(j)/(double)count << std::endl; + } + histogramFile2.close(); i++; // Analyze the histogram (direct) double sum = 0.0; bool found = false; threshold = 0.0; - for(int j=0; jGetFrequency(j)/(double)count); + // DD(j); + // DD(sum); + // DD(threshold); + // DD(h->GetBinMin(0,j)); + // DD(h->GetBinMax(0,j)); if ((!found) && (sum > tolerance)) { - if (j==0) threshold = h->GetBinMin(0,j); - else threshold = h->GetBinMin(0,j-1); // the last before reaching the threshold + // We consider as threshold the laste before current, because + if (j==0) + threshold = h->GetBinMin(0,j); + else threshold = h->GetBinMin(0,j-1); // FIXME ? the last before reaching the threshold + // DD(threshold); found = true; + j = bins; } } @@ -272,14 +308,23 @@ ComputeOptimalThresholds(FloatImageType * map, ImageType * target, int bins, dou sum = 0.0; found = false; reverseThreshold = 1.0; - for(int j=bins-1; j>=0; j--) { + for(int j=bins-1; j>0; j--) { sum += ((double)h->GetFrequency(j)/(double)count); + // DD(j); + // DD(sum); + // DD(reverseThreshold); + // DD(h->GetBinMin(0,j)); + // DD(h->GetBinMax(0,j)); if ((!found) && (sum > tolerance)) { - if (j==bins-1) reverseThreshold = h->GetBinMax(0,j); - else reverseThreshold = h->GetBinMax(0,j+1); + if (j==bins-1) + reverseThreshold = h->GetBinMax(0,j); + else reverseThreshold = h->GetBinMax(0,j-1);// FIXME ? the last before reaching the threshold + // DD(reverseThreshold); found = true; + j = -1; } } + } //-------------------------------------------------------------------- diff --git a/itk/clitkSegmentationUtils.txx b/itk/clitkSegmentationUtils.txx index 501c64f..6171030 100644 --- a/itk/clitkSegmentationUtils.txx +++ b/itk/clitkSegmentationUtils.txx @@ -766,8 +766,7 @@ namespace clitk { { assert((mainDirection==0) || (mainDirection==1)); typedef itk::ImageSliceIteratorWithIndex SliceIteratorType; - SliceIteratorType siter = SliceIteratorType(input, - input->GetLargestPossibleRegion()); + SliceIteratorType siter = SliceIteratorType(input, input->GetLargestPossibleRegion()); siter.SetFirstDirection(0); siter.SetSecondDirection(1); siter.GoToBegin(); @@ -786,7 +785,6 @@ namespace clitk { A = lA[i]; B = lB[i]; C = A; - // Check that the line is not a point (A=B) bool p = (A[0] == B[0]) && (A[1] == B[1]); diff --git a/itk/clitkSliceBySliceRelativePositionFilter.txx b/itk/clitkSliceBySliceRelativePositionFilter.txx index 0df2987..449ffff 100644 --- a/itk/clitkSliceBySliceRelativePositionFilter.txx +++ b/itk/clitkSliceBySliceRelativePositionFilter.txx @@ -127,9 +127,13 @@ GenerateOutputInformation() PrintOptions(); } + if (this->GetFuzzyMapOnlyFlag()) this->ComputeFuzzyMapFlagOn(); + // Get input pointer input = dynamic_cast(itk::ProcessObject::GetInput(0)); object = dynamic_cast(itk::ProcessObject::GetInput(1)); + m_working_object = object; + m_working_input = input; //-------------------------------------------------------------------- // Resample object to the same spacing than input @@ -138,36 +142,60 @@ GenerateOutputInformation() m_working_object = clitk::ResampleImageSpacing(object, input->GetSpacing()); this->template StopCurrentStep(m_working_object); } - else { - m_working_object = object; - } //-------------------------------------------------------------------- - // Pad object to the same size than input + // Resize image according to common area (except in Z) if (!clitk::HaveSameSizeAndSpacing(m_working_object, input)) { + this->StartNewStep("Resize images (union in XY and like input in Z)"); + + /* OLD STUFF this->StartNewStep("Pad object to the same size than input"); m_working_object = clitk::ResizeImageLike(m_working_object, - input, - this->GetObjectBackgroundValue()); + input, + this->GetObjectBackgroundValue()); this->template StopCurrentStep(m_working_object); + */ + + // Compute union of bounding boxes in X and Y + static const unsigned int dim = ImageType::ImageDimension; + typedef itk::BoundingBox BBType; + typename BBType::Pointer bb1 = BBType::New(); + ComputeBBFromImageRegion(m_working_object, m_working_object->GetLargestPossibleRegion(), bb1); + typename BBType::Pointer bb2 = BBType::New(); + ComputeBBFromImageRegion(input, input->GetLargestPossibleRegion(), bb2); + typename BBType::Pointer bbo = BBType::New(); + ComputeBBUnion(bbo, bb1, bb2); + + //We set Z BB like input + typename ImageType::PointType maxs = bbo->GetMaximum(); + typename ImageType::PointType mins = bbo->GetMinimum(); + maxs[2] = bb2->GetMaximum()[2]; + mins[2] = bb2->GetMinimum()[2]; + bbo->SetMaximum(maxs); + bbo->SetMinimum(mins); + + // Crop + m_working_input = clitk::ResizeImageLike(input, bbo, this->GetBackgroundValue()); + m_working_object = clitk::ResizeImageLike(m_working_object, + m_working_input, + this->GetObjectBackgroundValue()); + this->template StopCurrentStep(m_working_input); } - else { - } - - /* + + //-------------------------------------------------------------------- + /* Steps : - extract vector of slices in input, in object - slice by slice rel position - joint result - post process */ - //-------------------------------------------------------------------- // Extract input slices this->StartNewStep("Extract input slices"); typedef clitk::ExtractSliceFilter ExtractSliceFilterType; typename ExtractSliceFilterType::Pointer extractSliceFilter = ExtractSliceFilterType::New(); - extractSliceFilter->SetInput(input); + extractSliceFilter->SetInput(m_working_input); extractSliceFilter->SetDirection(GetDirection()); extractSliceFilter->Update(); typedef typename ExtractSliceFilterType::SliceType SliceType; @@ -179,7 +207,7 @@ GenerateOutputInformation() // Extract object slices this->StartNewStep("Extract object slices"); extractSliceFilter = ExtractSliceFilterType::New(); - extractSliceFilter->SetInput(m_working_object);//object); + extractSliceFilter->SetInput(m_working_object); extractSliceFilter->SetDirection(GetDirection()); extractSliceFilter->Update(); std::vector mObjectSlices; @@ -200,18 +228,18 @@ GenerateOutputInformation() int nb=0; mObjectSlices[i] = LabelizeAndCountNumberOfObjects(mObjectSlices[i], 0, true, 1, nb); - // If no object and empty slices : - if ((nb==0) && (this->GetFuzzyMapOnlyFlag())) { + // If no object and empty slices and if we need the full fuzzy map, create a dummy one. + if ((nb==0) && (this->GetComputeFuzzyMapFlag())) { typename FloatSliceType::Pointer one = FloatSliceType::New(); one->CopyInformation(mObjectSlices[0]); one->SetRegions(mObjectSlices[0]->GetLargestPossibleRegion()); one->Allocate(); one->FillBuffer(2.0); mFuzzyMapSlices[i] = one; - } + } // End nb==0 && GetComputeFuzzyMapFlag else { if ((!GetIgnoreEmptySliceObjectFlag()) || (nb!=0)) { - + // Select or not a single CCL ? if (GetUseTheLargestObjectCCLFlag()) { mObjectSlices[i] = KeepLabels(mObjectSlices[i], 0, 1, 1, 1, true); @@ -256,20 +284,20 @@ GenerateOutputInformation() relPosFilter->VerboseStepFlagOff(); relPosFilter->WriteStepFlagOff(); + // relPosFilter->VerboseMemoryFlagOn(); + relPosFilter->SetCurrentStepBaseId(this->GetCurrentStepId()+"-"+toString(i)); + relPosFilter->SetBackgroundValue(this->GetBackgroundValue()); relPosFilter->SetInput(mInputSlices[i]); relPosFilter->SetInputObject(mObjectSlices[i]); relPosFilter->SetRemoveObjectFlag(this->GetRemoveObjectFlag()); + // This flag (InverseOrientation) *must* be set before // AddOrientation because AddOrientation can change it. relPosFilter->SetInverseOrientationFlag(this->GetInverseOrientationFlag()); for(int j=0; jGetNumberOfAngles(); j++) { - // relPosFilter->AddOrientationTypeString(this->GetOrientationTypeString(j)); relPosFilter->AddAnglesInRad(this->GetAngle1InRad(j), this->GetAngle2InRad(j)); - // DD(this->GetOrientationTypeString(j)); } - // DD(this->GetInverseOrientationFlag()); - //relPosFilter->SetOrientationType(this->GetOrientationType()); relPosFilter->SetIntermediateSpacing(this->GetIntermediateSpacing()); relPosFilter->SetIntermediateSpacingFlag(this->GetIntermediateSpacingFlag()); relPosFilter->SetFuzzyThreshold(this->GetFuzzyThreshold()); @@ -278,26 +306,29 @@ GenerateOutputInformation() // should we stop after fuzzy map ? relPosFilter->SetFuzzyMapOnlyFlag(this->GetFuzzyMapOnlyFlag()); + relPosFilter->SetComputeFuzzyMapFlag(this->GetComputeFuzzyMapFlag()); // Go ! relPosFilter->Update(); // If we stop after the fuzzy map, store the fuzzy slices - if (this->GetFuzzyMapOnlyFlag()) { + if (this->GetComputeFuzzyMapFlag()) { mFuzzyMapSlices[i] = relPosFilter->GetFuzzyMap(); // writeImage(mFuzzyMapSlices[i], "slice_"+toString(i)+".mha"); } - else { + + // Set input slices + if (!this->GetFuzzyMapOnlyFlag()) { mInputSlices[i] = relPosFilter->GetOutput(); // Select main CC if needed if (GetUniqueConnectedComponentBySliceFlag()) { mInputSlices[i] = Labelize(mInputSlices[i], 0, true, 1); mInputSlices[i] = KeepLabels(mInputSlices[i], 0, 1, 1, 1, true); - } - + } } } + /* // Select unique CC according to the most in a given direction if (GetUniqueConnectedComponentBySliceAccordingToADirection()) { @@ -307,20 +338,22 @@ GenerateOutputInformation() ComputeCentroids } */ - } - } - // Join the fuzzy map if needed - if (this->GetFuzzyMapOnlyFlag()) { - this->m_FuzzyMap = clitk::JoinSlices(mFuzzyMapSlices, input, GetDirection()); - this->template StopCurrentStep(this->m_FuzzyMap); - return; - } + } // End nb!=0 || GetComputeFuzzyMapFlagOFF + + } // end for i mInputSlices // Join the slices - m_working_input = clitk::JoinSlices(mInputSlices, input, GetDirection()); + m_working_input = clitk::JoinSlices(mInputSlices, m_working_input, GetDirection()); this->template StopCurrentStep(m_working_input); + // Join the fuzzy map if needed + if (this->GetComputeFuzzyMapFlag()) { + this->m_FuzzyMap = clitk::JoinSlices(mFuzzyMapSlices, m_working_input, GetDirection()); + this->template StopCurrentStep(this->m_FuzzyMap); + if (this->GetFuzzyMapOnlyFlag()) return; + } + //-------------------------------------------------------------------- // Step 7: autocrop if (this->GetAutoCropFlag()) { diff --git a/segmentation/clitkExtractLymphStation_Supports.txx b/segmentation/clitkExtractLymphStation_Supports.txx index a022392..f480d84 100644 --- a/segmentation/clitkExtractLymphStation_Supports.txx +++ b/segmentation/clitkExtractLymphStation_Supports.txx @@ -19,18 +19,6 @@ ExtractStationSupports() Support_SI_Limit("inferior", "Sup_to_Carina", "inferior", "Carina", 0); Support_SI_Limit("superior", "Inf_to_Carina", "inferior", "Carina", m_Working_Support->GetSpacing()[2]); - // Initialise all others supports - // m_ListOfSupports["S1R"] = m_ListOfSupports["Sup_to_Carina"]; - // m_ListOfSupports["S1L"] = m_ListOfSupports["Sup_to_Carina"]; - // m_ListOfSupports["S2R"] = m_ListOfSupports["Sup_to_Carina"]; - // m_ListOfSupports["S2L"] = m_ListOfSupports["Sup_to_Carina"]; - // m_ListOfSupports["S3A"] = m_ListOfSupports["Sup_to_Carina"]; - // m_ListOfSupports["S3P"] = m_ListOfSupports["Sup_to_Carina"]; - // m_ListOfSupports["S4R"] = m_ListOfSupports["Sup_to_Carina"]; - // m_ListOfSupports["S4L"] = m_ListOfSupports["Sup_to_Carina"]; - // m_ListOfSupports["S5"] = m_Mediastinum; // Not above Carina - // m_ListOfSupports["S6"] = m_Mediastinum; // Not above Carina - // Read all support limits in a file and apply them ReadSupportLimits(GetSupportLimitsFilename()); for(unsigned int i=0; i here limit with + // trachea only StartNewStep("[Support] Ant limits of S3A with trachea"); m_ListOfSupports["S3A"] = LimitsWithTrachea(m_ListOfSupports["S3A"], 1, 0, -10); + + // S1RL - posterior limits when SI overlap with S3P + Support_Post_S1_S3P(); + + // S1RL - posterior limits with S2RL above sternal notch + Support_Post_S1_Ant_S2RL(); // I will do it later // Below Carina S7,8,9,10 @@ -235,6 +234,11 @@ void clitk::ExtractLymphStationsFilter:: Support_LeftRight_S1R_S1L() { + /* + Medially, station 1R and 1L are separated by the midline of the + trachea, whilst excluding the thyroid gland. + */ + // Step S1RL : Left-Right StartNewStep("[Support] Left-Right S1R S1L"); std::vector A; @@ -265,13 +269,13 @@ Support_LeftRight_S1R_S1L() // Right part clitk::SliceBySliceSetBackgroundFromLineSeparation(S1R, A, B, - GetBackgroundValue(), 0, 10); + GetBackgroundValue(), 0, -10); S1R = clitk::AutoCrop(S1R, GetBackgroundValue()); m_ListOfSupports["S1R"] = S1R; // Left part clitk::SliceBySliceSetBackgroundFromLineSeparation(S1L, A, B, - GetBackgroundValue(), 0, -10); + GetBackgroundValue(), 0, 10); S1L = clitk::AutoCrop(S1L, GetBackgroundValue()); m_ListOfSupports["S1L"] = S1L; StopCurrentStep(m_ListOfSupports["S1L"]); @@ -286,11 +290,14 @@ clitk::ExtractLymphStationsFilter:: Support_LeftRight_S2R_S2L() { // --------------------------------------------------------------------------- - /* Step : S2RL LeftRight - As for lymph node station 4R, 2R includes nodes extending to the - left lateral border of the trachea - Rod says: "For station 2 there is a shift, dividing 2R from 2L, from midline - to the left paratracheal border." + /* Step : S2RL LeftRight As for lymph node station 4R, 2R includes + nodes extending to the left lateral border of the trachea. + + Rod says: "For station 2 there is a shift in the IASLC definition + dividing 2R from 2L, from the midline to the left lateral + tracheal border. This is represented in the atlas as a vertical + line passing tangentially along the left lateral tracheal border + " */ StartNewStep("[Support] Separate 2R/2L according to Trachea"); MaskImagePointer S2R = m_ListOfSupports["S2R"]; @@ -313,15 +320,10 @@ clitk::ExtractLymphStationsFilter:: Support_LeftRight_S4R_S4L() { // --------------------------------------------------------------------------- - /* Step : S4RL LeftRight - - - 4R: includes right paratracheal nodes, and pretracheal nodes - extending to the left lateral border of trachea - - - 4L: includes nodes to the left of the left lateral border of - the trachea, medial to the ligamentum arteriosum - - => same than 2RL + /* + The medial border of station 4R is defined as an imaginary line + running vertically from the left lateral tracheal border. This is + the same medial border as was described for station 2R. */ StartNewStep("[Support] Left Right separation of 4R/4L"); @@ -409,21 +411,21 @@ LimitsWithTrachea(MaskImageType * input, int extremaDirection, int lineDirection template void clitk::ExtractLymphStationsFilter:: -Support_Post_S1S2S4() +Support_Post_S2S4() { - StartNewStep("[Support] Post limits of S1RL, S2RL, S4RL"); + StartNewStep("[Support] Post limits of S2RL, S4RL"); double m_ApexOfTheChest = FindApexOfTheChest(); // Post limits with Trachea - MaskImagePointer S1R = m_ListOfSupports["S1R"]; - MaskImagePointer S1L = m_ListOfSupports["S1L"]; + // MaskImagePointer S1R = m_ListOfSupports["S1R"]; + // MaskImagePointer S1L = m_ListOfSupports["S1L"]; MaskImagePointer S2R = m_ListOfSupports["S2R"]; MaskImagePointer S2L = m_ListOfSupports["S2L"]; MaskImagePointer S4R = m_ListOfSupports["S4R"]; MaskImagePointer S4L = m_ListOfSupports["S4L"]; - m_ListOfSupports["S1R"] = LimitsWithTrachea(S1L, 1, 0, -10, m_ApexOfTheChest); - m_ListOfSupports["S1L"] = LimitsWithTrachea(S1R, 1, 0, -10, m_ApexOfTheChest); + // m_ListOfSupports["S1R"] = LimitsWithTrachea(S1L, 1, 0, -10, m_ApexOfTheChest); + // m_ListOfSupports["S1L"] = LimitsWithTrachea(S1R, 1, 0, -10, m_ApexOfTheChest); m_ListOfSupports["S2R"] = LimitsWithTrachea(S2R, 1, 0, -10, m_ApexOfTheChest); m_ListOfSupports["S2L"] = LimitsWithTrachea(S2L, 1, 0, -10, m_ApexOfTheChest); m_ListOfSupports["S4R"] = LimitsWithTrachea(S4R, 1, 0, -10, m_ApexOfTheChest); @@ -432,3 +434,161 @@ Support_Post_S1S2S4() //-------------------------------------------------------------------- +//-------------------------------------------------------------------- +template +void +clitk::ExtractLymphStationsFilter:: +Support_Post_S1_S3P() +{ + StartNewStep("[Support] If S1RL and S3P have Sup-Inf overlap, define S1RL posterior limits with S3P anterior limits (post wall trachea)"); + + // Get current supports + MaskImagePointer S1R = m_ListOfSupports["S1R"]; + MaskImagePointer S1L = m_ListOfSupports["S1L"]; + + // Find extrema ant positions for 3P + std::vector A; + std::vector B; + + // Crop S3P like S1R + MaskImagePointer S3P = clitk::Clone(m_ListOfSupports["S3P"]); + S3P = clitk::ResizeImageLike(S3P, S1R, GetBackgroundValue()); + + // Slice by slice, build the separation line + clitk::SliceBySliceBuildLineSegmentAccordingToExtremaPosition(S3P, + GetBackgroundValue(), 2, + 1, true, // Ant-Post + 0, // Horizontal line + 0, // margins + A, B); + + // clitk::WriteListOfLandmarks(A, "A-S1S3P.txt"); + // clitk::WriteListOfLandmarks(B, "B-S1S3P.txt"); + + // Cut post to this line + clitk::SliceBySliceSetBackgroundFromLineSeparation(S1R, A, B, + GetBackgroundValue(), + 1, -10); + + // Crop S3P like S1L (Redo for S1L) + S3P = clitk::Clone(m_ListOfSupports["S3P"]); + S3P = clitk::ResizeImageLike(S3P, S1L, GetBackgroundValue()); + + // Slice by slice, build the separation line + A.clear(); + B.clear(); + clitk::SliceBySliceBuildLineSegmentAccordingToExtremaPosition(S3P, + GetBackgroundValue(), 2, + 1, true, // Ant-Post + 0, // Horizontal line + 0, // margins + A, B); + // Cut post to this line + clitk::SliceBySliceSetBackgroundFromLineSeparation(S1L, A, B, + GetBackgroundValue(), + 1, -10); + + // Crop both images + S1R = clitk::AutoCrop(S1R, GetBackgroundValue()); + S1L = clitk::AutoCrop(S1L, GetBackgroundValue()); + + StopCurrentStep(S1R); + + m_ListOfSupports["S1R"] = S1R; + m_ListOfSupports["S1L"] = S1L; +} +//-------------------------------------------------------------------- + + +//-------------------------------------------------------------------- +template +void +clitk::ExtractLymphStationsFilter:: +Support_Post_S1_Ant_S2RL() +{ + StartNewStep("[Support] Define S1RL posterior limits with S2RL anterior limits when overlap"); + + // Get RightLung + MaskImagePointer RightLung = this->GetAFDB()->template GetImage("RightLung"); + + // Find common area between S1 and S2 + MaskImagePointType p_min; + MaskImagePointType p_max; + clitk::FindExtremaPointInAGivenDirection(m_ListOfSupports["S2R"], + GetBackgroundValue(), 2, false, p_max); + clitk::FindExtremaPointInAGivenDirection(m_ListOfSupports["S1R"], + GetBackgroundValue(), 2, true, p_min); + p_min[2] -= RightLung->GetSpacing()[2]; // consider the slice below (remove lower or equal) + p_max[2] += RightLung->GetSpacing()[2]; // consider the slice abov (remove greater or equal) + + if (p_min[2] > p_max[2]) { + + // Crop RightLung + RightLung = clitk::Clone(RightLung); + RightLung = clitk::ResizeImageLike(RightLung, m_ListOfSupports["S1R"], GetBackgroundValue()); + RightLung = clitk::CropImageRemoveLowerThan(RightLung, 2, p_min[2], true, GetBackgroundValue()); + RightLung = clitk::CropImageRemoveGreaterThan(RightLung, 2, p_max[2], true, GetBackgroundValue()); + + // Find extrema ant positions for RightLung + std::vector A; + std::vector B; + clitk::SliceBySliceBuildLineSegmentAccordingToExtremaPosition(RightLung, + GetBackgroundValue(), 2, + 1, true, // Ant-Post + 0, // Horizontal line + 0, // margins + A, B); + clitk::SliceBySliceSetBackgroundFromLineSeparation(m_ListOfSupports["S1R"], + A, B, + GetBackgroundValue(), + 1, -10); + // I add one pixel to abupt S2R to S1R + for(int i=0; iGetSpacing()[1]; + B[i][1] -= RightLung->GetSpacing()[1]; + } + clitk::SliceBySliceSetBackgroundFromLineSeparation(m_ListOfSupports["S2R"], + A, B, + GetBackgroundValue(), + 1, 10); + } + + // Get LeftLung, crop + MaskImagePointer LeftLung = this->GetAFDB()->template GetImage("LeftLung"); + clitk::FindExtremaPointInAGivenDirection(m_ListOfSupports["S2L"], + GetBackgroundValue(), 2, false, p_max); + clitk::FindExtremaPointInAGivenDirection(m_ListOfSupports["S1L"], + GetBackgroundValue(), 2, true, p_min); + p_min[2] -= LeftLung->GetSpacing()[2]; // consider the slice below (remove lower or equal) + p_max[2] += LeftLung->GetSpacing()[2]; // consider the slice abov (remove greater or equal) + + if (p_min[2] > p_max[2]) { + LeftLung = clitk::ResizeImageLike(LeftLung, m_ListOfSupports["S1L"], GetBackgroundValue()); + LeftLung = clitk::CropImageRemoveLowerThan(LeftLung, 2, p_min[2], true, GetBackgroundValue()); + LeftLung = clitk::CropImageRemoveGreaterThan(LeftLung, 2, p_max[2], true, GetBackgroundValue()); + + // Find extrema ant positions for LeftLung + std::vector A; + std::vector B; + clitk::SliceBySliceBuildLineSegmentAccordingToExtremaPosition(LeftLung, + GetBackgroundValue(), 2, + 1, true, // Ant-Post + 0, // Horizontal line + 0, // margins + A, B); + clitk::SliceBySliceSetBackgroundFromLineSeparation(m_ListOfSupports["S1L"], + A, B, + GetBackgroundValue(), + 1, -10); + // I add one pixel to abupt S2R to S1R + for(int i=0; iGetSpacing()[1]; + B[i][1] -= LeftLung->GetSpacing()[1]; + } + clitk::SliceBySliceSetBackgroundFromLineSeparation(m_ListOfSupports["S2L"], + A, B, + GetBackgroundValue(), + 1, 10); + } +} +//-------------------------------------------------------------------- diff --git a/segmentation/clitkExtractLymphStationsFilter.txx b/segmentation/clitkExtractLymphStationsFilter.txx index 98768b2..64455a8 100644 --- a/segmentation/clitkExtractLymphStationsFilter.txx +++ b/segmentation/clitkExtractLymphStationsFilter.txx @@ -85,6 +85,9 @@ GenerateOutputInformation() { m_Input = dynamic_cast(itk::ProcessObject::GetInput(0)); m_Mediastinum = this->GetAFDB()->template GetImage ("Mediastinum"); + // DD(this->GetVerboseMemoryFlag()); + // clitk::PrintMemory(this->GetVerboseMemoryFlag(), "Start"); + // Clean some computer landmarks to force the recomputation // FIXME -> to put elsewhere ? this->GetAFDB()->RemoveTag("AntPostVesselsSeparation"); diff --git a/segmentation/clitkRelativePositionList.txx b/segmentation/clitkRelativePositionList.txx index 254fa4c..e0258d5 100644 --- a/segmentation/clitkRelativePositionList.txx +++ b/segmentation/clitkRelativePositionList.txx @@ -146,6 +146,7 @@ GenerateOutputInformation() { // Loop on RelativePositionList of operations std::string s = GetInputName(); for(uint i=0; iUpdate(); m_working_input = relPosFilter->GetOutput(); StopCurrentStep(m_working_input); + // clitk::PrintMemory(true, "End"); } } //-------------------------------------------------------------------- diff --git a/vv/qt_ui/vvToolStructureSetManager.ui b/vv/qt_ui/vvToolStructureSetManager.ui index 6ceae4e..ea15504 100644 --- a/vv/qt_ui/vvToolStructureSetManager.ui +++ b/vv/qt_ui/vvToolStructureSetManager.ui @@ -6,8 +6,8 @@ 0 0 - 301 - 480 + 411 + 534 @@ -186,8 +186,14 @@ 0 + + QAbstractItemView::AllEditTriggers + + + true + - false + true QAbstractItemView::SingleSelection @@ -216,6 +222,11 @@ Color + + + Depth + + 10 @@ -226,6 +237,9 @@ Red + + + @@ -241,12 +255,6 @@ Selected ROI - - 1 - - - 1 - @@ -308,13 +316,20 @@ + + 100 + Qt::Horizontal - + + + 100 + + @@ -364,7 +379,7 @@ 1 - 5 + 10 @@ -373,17 +388,57 @@ - - - - 0 - 0 - - - - Name : Lung - - + + + + + + 0 + 0 + + + + Name : Lung + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + Depth + + + + + + + 1 + + + 999999 + + + + @@ -458,12 +513,12 @@ setValue(int) - 344 - 381 + 219 + 385 - 426 - 381 + 376 + 376 @@ -474,12 +529,12 @@ setValue(int) - 432 - 386 + 376 + 367 - 351 - 386 + 222 + 373 diff --git a/vv/vvBinaryImageOverlayActor.cxx b/vv/vvBinaryImageOverlayActor.cxx index d4b9617..612d9c0 100644 --- a/vv/vvBinaryImageOverlayActor.cxx +++ b/vv/vvBinaryImageOverlayActor.cxx @@ -42,6 +42,7 @@ vvBinaryImageOverlayActor::vvBinaryImageOverlayActor() mForegroundValue = 1; mBackgroundValue = 0; m_modeBG = true; + mDepth = 1.0; } //------------------------------------------------------------------------------ @@ -233,14 +234,15 @@ void vvBinaryImageOverlayActor::UpdateColor() //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ -void vvBinaryImageOverlayActor::UpdateSlice(int slicer, int slice) +void vvBinaryImageOverlayActor::UpdateSlice(int slicer, int slice, bool force) { if (!mSlicer) return; - if (mPreviousSlice == mSlicer->GetSlice()) { - if (mPreviousTSlice == mSlicer->GetTSlice()) { - //DD("=========== NOTHING"); - return; // Nothing to do + if (!force) { + if (mPreviousSlice == mSlicer->GetSlice()) { + if (mPreviousTSlice == mSlicer->GetTSlice()) { + return; // Nothing to do + } } } @@ -253,14 +255,9 @@ void vvBinaryImageOverlayActor::UpdateSlice(int slicer, int slice) int orientation = mSlicer->GetOrientation(); int maskExtent[6]; ComputeExtent(orientation, mSlice, imageExtent, maskExtent); - //ComputeExtent(imageExtent, maskExtent, mSlicer->GetImage()->GetFirstVTKImageData(), mImage->GetFirstVTKImageData()); ComputeExtent(maskExtent, maskExtent, mSlicer->GetImage()->GetFirstVTKImageData(), mImage->GetFirstVTKImageData()); - // std::cout << "maskExtent = " << maskExtent[0] << " " << maskExtent[1] << " " << maskExtent[2] << " " - // << maskExtent[3] << " " << maskExtent[4] << " " << maskExtent[5] << std::endl; mSlicer->ClipDisplayedExtent(maskExtent, mMapperList[mTSlice]->GetInput()->GetWholeExtent()); - // std::cout << "maskExtent = " << maskExtent[0] << " " << maskExtent[1] << " " << maskExtent[2] << " " - // << maskExtent[3] << " " << maskExtent[4] << " " << maskExtent[5] << std::endl; - SetDisplayExtentAndCameraPosition(orientation, mSlice, maskExtent, mImageActorList[mTSlice], 0.0); + SetDisplayExtentAndCameraPosition(orientation, mSlice, maskExtent, mImageActorList[mTSlice], mDepth); // set previous slice mPreviousTSlice = mSlicer->GetTSlice(); @@ -297,18 +294,12 @@ void vvBinaryImageOverlayActor::ComputeExtent(int orientation, //---------------------------------------------------------------------------- void vvBinaryImageOverlayActor::ComputeExtent(int * inExtent, int * outExtent, vtkImageData * image, vtkImageData * overlay) { - outExtent[0] = (( image->GetOrigin()[0] + inExtent[0]*image->GetSpacing()[0] ) - overlay->GetOrigin()[0]) / - overlay->GetSpacing()[0]; - outExtent[1] = (( image->GetOrigin()[0] + inExtent[1]*image->GetSpacing()[0] ) - overlay->GetOrigin()[0]) / - overlay->GetSpacing()[0]; - outExtent[2] = (( image->GetOrigin()[1] + inExtent[2]*image->GetSpacing()[1] ) - overlay->GetOrigin()[1]) / - overlay->GetSpacing()[1]; - outExtent[3] = (( image->GetOrigin()[1] + inExtent[3]*image->GetSpacing()[1] ) - overlay->GetOrigin()[1]) / - overlay->GetSpacing()[1]; - outExtent[4] = (( image->GetOrigin()[2] + inExtent[4]*image->GetSpacing()[2] ) - overlay->GetOrigin()[2]) / - overlay->GetSpacing()[2]; - outExtent[5] = (( image->GetOrigin()[2] + inExtent[5]*image->GetSpacing()[2] ) - overlay->GetOrigin()[2]) / - overlay->GetSpacing()[2]; + outExtent[0] = (int)lrint(((image->GetOrigin()[0] + inExtent[0]*image->GetSpacing()[0]) - overlay->GetOrigin()[0]) / overlay->GetSpacing()[0]); + outExtent[1] = (int)lrint(((image->GetOrigin()[0] + inExtent[1]*image->GetSpacing()[0]) - overlay->GetOrigin()[0]) / overlay->GetSpacing()[0]); + outExtent[2] = (int)lrint(((image->GetOrigin()[1] + inExtent[2]*image->GetSpacing()[1]) - overlay->GetOrigin()[1]) / overlay->GetSpacing()[1]); + outExtent[3] = (int)lrint(((image->GetOrigin()[1] + inExtent[3]*image->GetSpacing()[1]) - overlay->GetOrigin()[1]) / overlay->GetSpacing()[1]); + outExtent[4] = (int)lrint(((image->GetOrigin()[2] + inExtent[4]*image->GetSpacing()[2]) - overlay->GetOrigin()[2]) / overlay->GetSpacing()[2]); + outExtent[5] = (int)lrint(((image->GetOrigin()[2] + inExtent[5]*image->GetSpacing()[2]) - overlay->GetOrigin()[2]) / overlay->GetSpacing()[2]); } //---------------------------------------------------------------------------- @@ -320,23 +311,27 @@ void vvBinaryImageOverlayActor::SetDisplayExtentAndCameraPosition(int orientatio vtkImageActor * actor, double position) { + /* FIXME + Error according to camera orientation + */ + // Set position if (orientation == vtkImageViewer2::SLICE_ORIENTATION_XY) { - if (mSlicer->GetRenderer()->GetActiveCamera()->GetPosition()[2] > slice) - actor->SetPosition(0,0, position); - else + //if (mSlicer->GetRenderer()->GetActiveCamera()->GetPosition()[2] > slice) actor->SetPosition(0,0, -position); + //else + //actor->SetPosition(0,0, position); } if (orientation == vtkImageViewer2::SLICE_ORIENTATION_XZ) { - if (mSlicer->GetRenderer()->GetActiveCamera()->GetPosition()[1] > slice) - actor->SetPosition(0,position,0); - else + //if (mSlicer->GetRenderer()->GetActiveCamera()->GetPosition()[1] > slice) + // actor->SetPosition(0,position,0); + //else actor->SetPosition(0,-position,0); } if (orientation == vtkImageViewer2::SLICE_ORIENTATION_YZ) { - if (mSlicer->GetRenderer()->GetActiveCamera()->GetPosition()[0] > slice) - actor->SetPosition(position,0, 0); - else + //if (mSlicer->GetRenderer()->GetActiveCamera()->GetPosition()[0] > slice) + // actor->SetPosition(position,0, 0); + //else actor->SetPosition(-position,0, 0); } actor->SetDisplayExtent(extent); diff --git a/vv/vvBinaryImageOverlayActor.h b/vv/vvBinaryImageOverlayActor.h index dfa3109..0b02c62 100644 --- a/vv/vvBinaryImageOverlayActor.h +++ b/vv/vvBinaryImageOverlayActor.h @@ -41,9 +41,10 @@ class vvBinaryImageOverlayActor : public itk::LightObject void SetColor(double r, double g, double b); void SetOpacity(double d); void SetImage(vvImage * image, double bg, bool modeBG=true); + void SetDepth(double d) { mDepth = d; } void Initialize(bool IsVisible=true); void UpdateColor(); - void UpdateSlice(int slicer, int slice); + void UpdateSlice(int slicer, int slice, bool force=false); void HideActors(); void ShowActors(); @@ -60,6 +61,7 @@ class vvBinaryImageOverlayActor : public itk::LightObject double mForegroundValue; bool m_modeBG; vtkSmartPointer mColorLUT; + double mDepth; std::vector > mMapperList; std::vector > mImageActorList; diff --git a/vv/vvImageContour.cxx b/vv/vvImageContour.cxx index 9412903..173bde0 100644 --- a/vv/vvImageContour.cxx +++ b/vv/vvImageContour.cxx @@ -36,6 +36,7 @@ vvImageContour::vvImageContour() mDisplayModeIsPreserveMemory = true; SetPreserveMemoryModeEnabled(true); mPreviousOrientation = -1; + mDepth = 1.0; } //------------------------------------------------------------------------------ @@ -291,8 +292,7 @@ void vvImageContour::UpdateActor(vtkActor * actor, vtkMarchingSquares * squares, vtkImageClip * clipper, double threshold, int orientation, int slice) { - - // Set parameter for the MarchigSquare + // Set parameter for the MarchigSquare squares->SetValue(0, threshold); // Get image extent @@ -312,15 +312,16 @@ void vvImageContour::UpdateActor(vtkActor * actor, s = s-mHiddenImage->GetFirstVTKImageData()->GetOrigin()[orientation]; // from corner second image s = s/mHiddenImage->GetFirstVTKImageData()->GetSpacing()[orientation]; // in voxel - if (s == floor(s)) { - extent2[orientation*2] = extent2[orientation*2+1] = (int)floor(s); - } else { - extent2[orientation*2] = (int)floor(s); - extent2[orientation*2+1] = extent2[orientation*2]; - } + // Rint to the closest slice + extent2[orientation*2+1] = extent2[orientation*2] = (int)lrint(s); // Do not display a contour if there is no contour on this slice - if (extent2[orientation*2+1] > extent3[orientation*2+1]) { + // DD(extent2[orientation*2+1]); + // DD(extent3[orientation*2+1]); + // DD(extent2[orientation*2]); + // DD(extent3[orientation*2]); + if ((extent2[orientation*2+1] > extent3[orientation*2+1]) || + (extent2[orientation*2] < extent3[orientation*2])) { actor->VisibilityOff(); return; } @@ -338,7 +339,7 @@ void vvImageContour::UpdateActor(vtkActor * actor, // Move the actor to be visible double position[3] = {0, 0, 0}; - position[orientation] = -1; + position[orientation] = -mDepth; actor->SetPosition(position); mapper->Update(); diff --git a/vv/vvImageContour.h b/vv/vvImageContour.h index d2be512..2c92abb 100644 --- a/vv/vvImageContour.h +++ b/vv/vvImageContour.h @@ -43,6 +43,7 @@ public: void SetLineWidth(double w); void SetImage(vvImage * image); void SetPreserveMemoryModeEnabled(bool b); + void SetDepth(double d) { mDepth = d; } protected: vvSlicer * mSlicer; @@ -54,6 +55,7 @@ protected: bool mHiddenImageIsUsed; vvImage * mHiddenImage; bool mDisplayModeIsPreserveMemory; + double mDepth; // For preserveMemory mode std::vector > mSquaresActorList; diff --git a/vv/vvMeshActor.cxx b/vv/vvMeshActor.cxx index 3c50b84..bfc5343 100644 --- a/vv/vvMeshActor.cxx +++ b/vv/vvMeshActor.cxx @@ -67,6 +67,8 @@ void vvMeshActor::Init(vvMesh::Pointer mesh,int time_slice,vvImage::Pointer vf) void vvMeshActor::SetCutSlice(double slice) { + DD("SetCutSlice"); + DD(slice); mCutSlice=slice; vtkImageData* mask; if (static_cast(mTimeSlice)GetNumberOfMasks()) diff --git a/vv/vvROIActor.cxx b/vv/vvROIActor.cxx index f4abf28..b46ae0a 100644 --- a/vv/vvROIActor.cxx +++ b/vv/vvROIActor.cxx @@ -40,6 +40,7 @@ vvROIActor::vvROIActor() mContourWidth = 1; mContourColor.resize(3); m_modeBG = true; + mDepth = 1.0; } //------------------------------------------------------------------------------ @@ -78,7 +79,7 @@ void vvROIActor::UpdateImage() { mOverlayActors.clear(); mImageContour.clear(); - Initialize(mIsVisible); + Initialize(mDepth, mIsVisible); Update(); // No Render } //------------------------------------------------------------------------------ @@ -133,10 +134,11 @@ bool vvROIActor::IsContourVisible() { //------------------------------------------------------------------------------ -void vvROIActor::Initialize(bool IsVisible) { +void vvROIActor::Initialize(double depth, bool IsVisible) { if (mROI->GetImage()) { mImageContour.clear(); mOverlayActors.clear(); + mDepth = depth; for(int i=0; iGetNumberOfSlicers(); i++) { mImageContour.push_back(vvImageContour::New()); @@ -148,6 +150,7 @@ void vvROIActor::Initialize(bool IsVisible) { mImageContour[i]->SetColor(mContourColor[0], mContourColor[1], mContourColor[2]); mImageContour[i]->SetLineWidth(mContourWidth); mImageContour[i]->SetPreserveMemoryModeEnabled(true); + mImageContour[i]->SetDepth(mDepth); //mImageContour[i]->SetPreserveMemoryModeEnabled(false); // SEG FAULT !!! mImageContour[i]->SetSlicer(mSlicerManager->GetSlicer(i)); mImageContour[i]->HideActors(); @@ -168,7 +171,8 @@ void vvROIActor::Initialize(bool IsVisible) { mROI->GetDisplayColor()[2]); mOverlayActors[i]->SetOpacity(mOpacity); mOverlayActors[i]->SetSlicer(mSlicerManager->GetSlicer(i)); - mOverlayActors[i]->Initialize(IsVisible); + mOverlayActors[i]->Initialize(IsVisible); + mOverlayActors[i]->SetDepth(mDepth); } connect(mSlicerManager,SIGNAL(UpdateSlice(int,int)),this,SLOT(UpdateSlice(int, int))); @@ -180,17 +184,30 @@ void vvROIActor::Initialize(bool IsVisible) { //------------------------------------------------------------------------------ -void vvROIActor::Update() +void vvROIActor::SetDepth(double d) +{ + mDepth = d; + for(int i=0; iGetNumberOfSlicers(); i++) { + mOverlayActors[i]->SetDepth(d); + mImageContour[i]->SetDepth(d); + } + Update(true); +} +//------------------------------------------------------------------------------ + + +//------------------------------------------------------------------------------ +void vvROIActor::Update(bool force) { for(int i=0; iGetNumberOfSlicers(); i++) { - UpdateSlice(i, mSlicerManager->GetSlicer(i)->GetSlice()); + UpdateSlice(i, mSlicerManager->GetSlicer(i)->GetSlice(), force); } } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ -void vvROIActor::UpdateSlice(int slicer, int slices) +void vvROIActor::UpdateSlice(int slicer, int slices, bool force) { if (!mROI->GetImage()) return; if ((!mIsVisible) && (!mIsContourVisible)) return; @@ -204,7 +221,7 @@ void vvROIActor::UpdateSlice(int slicer, int slices) } // Refresh overlays - mOverlayActors[slicer]->UpdateSlice(slicer, slices); + mOverlayActors[slicer]->UpdateSlice(slicer, slices, force); } //------------------------------------------------------------------------------ diff --git a/vv/vvROIActor.h b/vv/vvROIActor.h index fb85658..42182cb 100644 --- a/vv/vvROIActor.h +++ b/vv/vvROIActor.h @@ -37,8 +37,8 @@ class vvROIActor: public QObject { void SetROI(clitk::DicomRT_ROI * r); clitk::DicomRT_ROI * GetROI() { return mROI; } void SetSlicerManager(vvSlicerManager * s); - void Update(); - void Initialize(bool IsVisible=true); + void Update(bool force=false); + void Initialize(double d=1.0, bool IsVisible=true); void SetVisible(bool b); void SetContourVisible(bool b); bool IsVisible(); @@ -51,9 +51,11 @@ class vvROIActor: public QObject { void SetContourColor(double r, double v, double b); std::vector & GetContourColor(); void SetBGMode(bool b) { m_modeBG = b; } + void SetDepth(double d); + double GetDepth() { return mDepth; } public slots: - void UpdateSlice(int slicer, int slices); + void UpdateSlice(int slicer, int slices, bool force=false); void UpdateColor(); void UpdateImage(); @@ -70,6 +72,7 @@ public slots: int mContourWidth; std::vector mContourColor; bool m_modeBG; + double mDepth; }; // end class vvROIActor //------------------------------------------------------------------------------ diff --git a/vv/vvStructureSetActor.cxx b/vv/vvStructureSetActor.cxx index 7fcfb01..b7860d3 100644 --- a/vv/vvStructureSetActor.cxx +++ b/vv/vvStructureSetActor.cxx @@ -103,7 +103,7 @@ void vvStructureSetActor::CreateNewROIActor(int n, bool modeBG) actor->SetBGMode(modeBG); actor->SetROI(roi); actor->SetSlicerManager(mSlicerManager); - actor->Initialize(); + actor->Initialize(n+1); // depth is n+1 to start at 1 mMapROIIndex[n] = mROIActors.size()-1; } //------------------------------------------------------------------------------ diff --git a/vv/vvToolStructureSetManager.cxx b/vv/vvToolStructureSetManager.cxx index f625e4c..097f500 100644 --- a/vv/vvToolStructureSetManager.cxx +++ b/vv/vvToolStructureSetManager.cxx @@ -159,6 +159,7 @@ void vvToolStructureSetManager::InputIsSelected(vvSlicerManager *m) connect(mContourCheckBoxShow, SIGNAL(toggled(bool)), this, SLOT(VisibleContourROIToggled(bool))); connect(mChangeContourColorButton, SIGNAL(clicked()), this, SLOT(ChangeContourColor())); connect(mContourWidthSpinBox, SIGNAL(valueChanged(int)), this, SLOT(ChangeContourWidth(int))); + connect(mDepthSpinBox, SIGNAL(valueChanged(int)), this, SLOT(ChangeDepth(int))); connect(mReloadButton, SIGNAL(clicked()), this, SLOT(ReloadCurrentROI())); connect(mCheckBoxShowAll, SIGNAL(stateChanged(int)), this, SLOT(AllVisibleROIToggled(int))); connect(mContourCheckBoxShowAll, SIGNAL(toggled(bool)), this, SLOT(AllVisibleContourROIToggled(bool))); @@ -188,6 +189,8 @@ void vvToolStructureSetManager::AddRoiInTreeWidget(clitk::DicomRT_ROI * roi, QTr QTreeWidgetItem * w = mTreeWidgetList.back().data(); w->setText(0, QString("%1").arg(roi->GetROINumber())); w->setText(1, QString("%1").arg(roi->GetName().c_str())); + vvROIActor * actor = mStructureSetActorsList[0]->GetROIActor(roi->GetROINumber()); + w->setText(3, QString("%1").arg(actor->GetDepth())); QBrush brush(QColor(roi->GetDisplayColor()[0]*255, roi->GetDisplayColor()[1]*255, roi->GetDisplayColor()[2]*255)); brush.setStyle(Qt::SolidPattern); w->setBackground(2, brush); @@ -441,24 +444,40 @@ void vvToolStructureSetManager::SelectedItemChangedInTree() { mCurrentROI = roi; mCurrentROIActor = actor; + // Warning -> avoid unuseful Render here by disconnect slider // Update GUI + disconnect(mTree, SIGNAL(itemSelectionChanged()), this, SLOT(SelectedItemChangedInTree())); + disconnect(mCheckBoxShow, SIGNAL(toggled(bool)), this, SLOT(VisibleROIToggled(bool))); + disconnect(mOpacitySlider, SIGNAL(valueChanged(int)), this, SLOT(OpacityChanged(int))); + disconnect(mChangeColorButton, SIGNAL(clicked()), this, SLOT(ChangeColor())); + disconnect(mContourCheckBoxShow, SIGNAL(toggled(bool)), this, SLOT(VisibleContourROIToggled(bool))); + disconnect(mChangeContourColorButton, SIGNAL(clicked()), this, SLOT(ChangeContourColor())); + disconnect(mContourWidthSpinBox, SIGNAL(valueChanged(int)), this, SLOT(ChangeContourWidth(int))); + disconnect(mDepthSpinBox, SIGNAL(valueChanged(int)), this, SLOT(ChangeDepth(int))); + mGroupBoxROI->setEnabled(true); mROInameLabel->setText(roi->GetName().c_str()); mCheckBoxShow->setChecked(actor->IsVisible()); mContourCheckBoxShow->setChecked(actor->IsContourVisible()); mContourWidthSpinBox->setValue(actor->GetContourWidth()); - - // Warning -> avoir unuseful Render here by disconnect slider - disconnect(mOpacitySlider, SIGNAL(valueChanged(int)), - this, SLOT(OpacityChanged(int))); + mDepthSpinBox->setValue(actor->GetDepth()); + w->setText(3, QString("%1").arg(actor->GetDepth())); mOpacitySlider->setValue((int)lrint(actor->GetOpacity()*100)); mOpacitySpinBox->setValue((int)lrint(actor->GetOpacity()*100)); - connect(mOpacitySlider, SIGNAL(valueChanged(int)), - this, SLOT(OpacityChanged(int))); - actor->Update(); + connect(mTree, SIGNAL(itemSelectionChanged()), this, SLOT(SelectedItemChangedInTree())); + connect(mCheckBoxShow, SIGNAL(toggled(bool)), this, SLOT(VisibleROIToggled(bool))); + connect(mOpacitySlider, SIGNAL(valueChanged(int)), this, SLOT(OpacityChanged(int))); + connect(mChangeColorButton, SIGNAL(clicked()), this, SLOT(ChangeColor())); + connect(mContourCheckBoxShow, SIGNAL(toggled(bool)), this, SLOT(VisibleContourROIToggled(bool))); + connect(mChangeContourColorButton, SIGNAL(clicked()), this, SLOT(ChangeContourColor())); + connect(mContourWidthSpinBox, SIGNAL(valueChanged(int)), this, SLOT(ChangeContourWidth(int))); + connect(mDepthSpinBox, SIGNAL(valueChanged(int)), this, SLOT(ChangeDepth(int))); + + // is this needed ? + // actor->Update(); // Final rendering - mCurrentSlicerManager->Render(); + // mCurrentSlicerManager->Render(); } //------------------------------------------------------------------------------ @@ -597,6 +616,18 @@ void vvToolStructureSetManager::ChangeContourWidth(int n) { //------------------------------------------------------------------------------ +//------------------------------------------------------------------------------ +void vvToolStructureSetManager::ChangeDepth(int n) { + mCurrentROIActor->SetDepth(n); + mCurrentROIActor->UpdateImage(); + mCurrentSlicerManager->Render(); + QList l = mTree->selectedItems(); + QTreeWidgetItem * w = l[0]; + w->setText(3, QString("%1").arg(mCurrentROIActor->GetDepth())); +} +//------------------------------------------------------------------------------ + + //------------------------------------------------------------------------------ void vvToolStructureSetManager::ReloadCurrentROI() { // Reload image diff --git a/vv/vvToolStructureSetManager.h b/vv/vvToolStructureSetManager.h index 4fd4d8e..0f5ffec 100644 --- a/vv/vvToolStructureSetManager.h +++ b/vv/vvToolStructureSetManager.h @@ -63,6 +63,7 @@ public slots: void ChangeColor(); void ChangeContourColor(); void ChangeContourWidth(int n); + void ChangeDepth(int n); void AllVisibleROIToggled(int b); void AllVisibleContourROIToggled(bool b); void ReloadCurrentROI();