Mercurial > hg > orthanc-stone
comparison RenderingPlugin/Sources/Plugin.cpp @ 1946:3c68cdfbdcab
rendering plugin: deal with special case of holes in structs
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Thu, 02 Jun 2022 21:22:24 +0200 |
parents | 98952be6fb97 |
children | 3f88c239043a |
comparison
equal
deleted
inserted
replaced
1945:98952be6fb97 | 1946:3c68cdfbdcab |
---|---|
713 image_(Orthanc::PixelFormat_Grayscale8, width, height, false) | 713 image_(Orthanc::PixelFormat_Grayscale8, width, height, false) |
714 { | 714 { |
715 Orthanc::ImageProcessing::Set(image_, 0); | 715 Orthanc::ImageProcessing::Set(image_, 0); |
716 } | 716 } |
717 | 717 |
718 const Orthanc::ImageAccessor& GetImage() const | 718 Orthanc::ImageAccessor& GetImage() |
719 { | 719 { |
720 return image_; | 720 return image_; |
721 } | 721 } |
722 | 722 |
723 virtual void Fill(int y, | 723 virtual void Fill(int y, |
735 uint8_t* p = reinterpret_cast<uint8_t*>(image_.GetRow(y)) + x1; | 735 uint8_t* p = reinterpret_cast<uint8_t*>(image_.GetRow(y)) + x1; |
736 | 736 |
737 for (int i = x1; i <= x2; i++, p++) | 737 for (int i = x1; i <= x2; i++, p++) |
738 { | 738 { |
739 *p = (*p ^ 0xff); | 739 *p = (*p ^ 0xff); |
740 } | 740 } |
741 } | 741 } |
742 } | 742 } |
743 }; | 743 }; |
744 | 744 |
745 | |
746 class HorizontalSegment | |
747 { | |
748 private: | |
749 int y_; | |
750 int x1_; | |
751 int x2_; | |
752 | |
753 public: | |
754 HorizontalSegment(int y, | |
755 int x1, | |
756 int x2) : | |
757 y_(y), | |
758 x1_(std::min(x1, x2)), | |
759 x2_(std::max(x1, x2)) | |
760 { | |
761 } | |
762 | |
763 int GetY() const | |
764 { | |
765 return y_; | |
766 } | |
767 | |
768 int GetX1() const | |
769 { | |
770 return x1_; | |
771 } | |
772 | |
773 int GetX2() const | |
774 { | |
775 return x2_; | |
776 } | |
777 | |
778 void Fill(Orthanc::ImageAccessor& image) const | |
779 { | |
780 assert(x1_ <= x2_); | |
781 | |
782 if (y_ >= 0 && | |
783 y_ < static_cast<int>(image.GetHeight())) | |
784 { | |
785 int a = std::max(x1_, 0); | |
786 int b = std::min(x2_, static_cast<int>(image.GetWidth()) - 1); | |
787 | |
788 uint8_t* p = reinterpret_cast<uint8_t*>(image.GetRow(y_)) + a; | |
789 | |
790 for (int i = a; i <= b; i++, p++) | |
791 { | |
792 *p = 0xff; | |
793 } | |
794 } | |
795 } | |
796 }; | |
797 | |
798 | |
745 DataAugmentationParameters dataAugmentation; | 799 DataAugmentationParameters dataAugmentation; |
746 std::vector<std::string> structureNames; | 800 std::vector<std::string> structureNames; |
747 std::string instanceId; | 801 std::string instanceId; |
748 bool compress = false; | 802 bool compress = false; |
749 | 803 |
812 } | 866 } |
813 | 867 |
814 // We use a "XOR" filler for the polygons in order to deal with holes in the RT-STRUCT | 868 // We use a "XOR" filler for the polygons in order to deal with holes in the RT-STRUCT |
815 XorFiller filler(parameters->GetWidth(), parameters->GetHeight()); | 869 XorFiller filler(parameters->GetWidth(), parameters->GetHeight()); |
816 OrthancStone::AffineTransform2D transform = dataAugmentation.ComputeTransform(parameters->GetWidth(), parameters->GetHeight()); | 870 OrthancStone::AffineTransform2D transform = dataAugmentation.ComputeTransform(parameters->GetWidth(), parameters->GetHeight()); |
871 | |
872 std::list<HorizontalSegment> horizontalSegments; | |
817 | 873 |
818 for (std::list< std::vector<OrthancStone::Vector> >::const_iterator | 874 for (std::list< std::vector<OrthancStone::Vector> >::const_iterator |
819 it = polygons.begin(); it != polygons.end(); ++it) | 875 it = polygons.begin(); it != polygons.end(); ++it) |
820 { | 876 { |
821 std::vector<Orthanc::ImageProcessing::ImagePoint> points; | 877 std::vector<Orthanc::ImageProcessing::ImagePoint> points; |
831 x = x / parameters->GetPixelSpacingX() + 0.5; | 887 x = x / parameters->GetPixelSpacingX() + 0.5; |
832 y = y / parameters->GetPixelSpacingY() + 0.5; | 888 y = y / parameters->GetPixelSpacingY() + 0.5; |
833 | 889 |
834 transform.Apply(x, y); | 890 transform.Apply(x, y); |
835 | 891 |
836 points.push_back(Orthanc::ImageProcessing::ImagePoint(x, y)); | 892 points.push_back(Orthanc::ImageProcessing::ImagePoint(std::floor(x), std::floor(y))); |
837 } | 893 } |
838 | 894 |
839 Orthanc::ImageProcessing::FillPolygon(filler, points); | 895 Orthanc::ImageProcessing::FillPolygon(filler, points); |
840 } | 896 |
841 | 897 for (size_t i = 0; i < points.size(); i++) |
898 { | |
899 size_t next = (i + 1) % points.size(); | |
900 if (points[i].GetY() == points[next].GetY()) | |
901 { | |
902 horizontalSegments.push_back(HorizontalSegment(points[i].GetY(), points[i].GetX(), points[next].GetX())); | |
903 } | |
904 } | |
905 } | |
906 | |
907 /** | |
908 * We repeat the filling of the horizontal segments. This is | |
909 * important to deal with horizontal edges that are seen in one | |
910 * direction, then in the reverse direction within the same polygon, | |
911 * which can typically be seen in RT-STRUCT with holes. If this step | |
912 * is not done, only the starting point and the ending point of the | |
913 * segments are drawn. | |
914 **/ | |
915 for (std::list<HorizontalSegment>::const_iterator it = horizontalSegments.begin(); | |
916 it != horizontalSegments.end(); ++it) | |
917 { | |
918 it->Fill(filler.GetImage()); | |
919 } | |
920 | |
842 AnswerNumpyImage(output, filler.GetImage(), compress); | 921 AnswerNumpyImage(output, filler.GetImage(), compress); |
843 } | 922 } |
844 | 923 |
845 | 924 |
846 | 925 |