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