Mercurial > hg > orthanc-stone
comparison Applications/StoneWebViewer/WebAssembly/StoneWebViewer.cpp @ 1952:a1e0aae9c17f deep-learning
support interruption of deep learning
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Tue, 16 Aug 2022 13:49:52 +0200 |
parents | 060d61913e39 |
children | 0661115af939 |
comparison
equal
deleted
inserted
replaced
1951:060d61913e39 | 1952:a1e0aae9c17f |
---|---|
3666 | 3666 |
3667 | 3667 |
3668 #include <emscripten/fetch.h> | 3668 #include <emscripten/fetch.h> |
3669 #include "deep-learning/WebAssembly/Worker.pb.h" | 3669 #include "deep-learning/WebAssembly/Worker.pb.h" |
3670 | 3670 |
3671 static void SendRequestToWebWorker(const OrthancStone::Messages::Request& request); | 3671 enum DeepLearningState |
3672 | 3672 { |
3673 DeepLearningState_Waiting, | |
3674 DeepLearningState_Pending, | |
3675 DeepLearningState_Running | |
3676 }; | |
3677 | |
3678 static DeepLearningState deepLearningState_ = DeepLearningState_Waiting; | |
3679 static worker_handle deepLearningWorker_; | |
3680 static std::string deepLearningPendingSopInstanceUid_; | |
3681 static unsigned int deepLearningPendingFrameNumber_; | |
3682 | |
3683 // Forward declaration | |
3673 static void DeepLearningCallback(char* data, | 3684 static void DeepLearningCallback(char* data, |
3674 int size, | 3685 int size, |
3675 void* payload) | 3686 void* payload); |
3676 { | |
3677 OrthancStone::Messages::Response response; | |
3678 if (response.ParseFromArray(data, size)) | |
3679 { | |
3680 switch (response.type()) | |
3681 { | |
3682 case OrthancStone::Messages::ResponseType::INITIALIZED: | |
3683 DISPATCH_JAVASCRIPT_EVENT("DeepLearningInitialized"); | |
3684 break; | |
3685 | |
3686 case OrthancStone::Messages::ResponseType::PARSED_MODEL: | |
3687 LOG(WARNING) << "Number of steps in the model: " << response.parse_model().number_of_steps(); | |
3688 DISPATCH_JAVASCRIPT_EVENT("DeepLearningModelReady"); | |
3689 break; | |
3690 | |
3691 case OrthancStone::Messages::ResponseType::LOADED_IMAGE: | |
3692 { | |
3693 OrthancStone::Messages::Request request; | |
3694 request.set_type(OrthancStone::Messages::RequestType::EXECUTE_STEP); | |
3695 SendRequestToWebWorker(request); | |
3696 break; | |
3697 } | |
3698 | |
3699 case OrthancStone::Messages::ResponseType::STEP_DONE: | |
3700 { | |
3701 EM_ASM({ | |
3702 const customEvent = document.createEvent("CustomEvent"); | |
3703 customEvent.initCustomEvent("DeepLearningStep", false, false, | |
3704 { "progress" : $0 }); | |
3705 window.dispatchEvent(customEvent); | |
3706 }, | |
3707 response.step().progress() | |
3708 ); | |
3709 | |
3710 if (response.step().done()) | |
3711 { | |
3712 LOG(WARNING) << "SUCCESS! Mask: " << response.step().output().width() << "x" | |
3713 << response.step().output().height() << " for frame " | |
3714 << response.step().output().sop_instance_uid() << " / " | |
3715 << response.step().output().frame_number(); | |
3716 } | |
3717 else | |
3718 { | |
3719 OrthancStone::Messages::Request request; | |
3720 request.set_type(OrthancStone::Messages::RequestType::EXECUTE_STEP); | |
3721 SendRequestToWebWorker(request); | |
3722 } | |
3723 | |
3724 break; | |
3725 } | |
3726 | |
3727 default: | |
3728 LOG(ERROR) << "Unsupported response type from the deep learning worker"; | |
3729 } | |
3730 } | |
3731 else | |
3732 { | |
3733 LOG(ERROR) << "Bad response received from the deep learning worker"; | |
3734 } | |
3735 } | |
3736 | |
3737 static worker_handle deepLearningWorker_; | |
3738 | 3687 |
3739 static void SendRequestToWebWorker(const OrthancStone::Messages::Request& request) | 3688 static void SendRequestToWebWorker(const OrthancStone::Messages::Request& request) |
3740 { | 3689 { |
3741 std::string s; | 3690 std::string s; |
3742 if (request.SerializeToString(&s) && | 3691 if (request.SerializeToString(&s) && |
3747 else | 3696 else |
3748 { | 3697 { |
3749 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError, | 3698 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError, |
3750 "Cannot send command to the Web worker"); | 3699 "Cannot send command to the Web worker"); |
3751 } | 3700 } |
3701 } | |
3702 | |
3703 static void DeepLearningSchedule(const std::string& sopInstanceUid, | |
3704 unsigned int frameNumber) | |
3705 { | |
3706 if (deepLearningState_ == DeepLearningState_Waiting) | |
3707 { | |
3708 LOG(WARNING) << "Starting deep learning on: " << sopInstanceUid << " / " << frameNumber; | |
3709 | |
3710 FramesCache::Accessor accessor(*framesCache_, sopInstanceUid, frameNumber); | |
3711 if (accessor.IsValid() && | |
3712 accessor.GetImage().GetFormat() == Orthanc::PixelFormat_Float32) | |
3713 { | |
3714 const Orthanc::ImageAccessor& image = accessor.GetImage(); | |
3715 | |
3716 OrthancStone::Messages::Request request; | |
3717 request.set_type(OrthancStone::Messages::RequestType::LOAD_IMAGE); | |
3718 request.mutable_load_image()->set_sop_instance_uid(sopInstanceUid); | |
3719 request.mutable_load_image()->set_frame_number(frameNumber); | |
3720 request.mutable_load_image()->set_width(image.GetWidth()); | |
3721 request.mutable_load_image()->set_height(image.GetHeight()); | |
3722 | |
3723 const unsigned int height = image.GetHeight(); | |
3724 const unsigned int width = image.GetWidth(); | |
3725 for (unsigned int y = 0; y < height; y++) | |
3726 { | |
3727 const float* p = reinterpret_cast<const float*>(image.GetConstRow(y)); | |
3728 for (unsigned int x = 0; x < width; x++, p++) | |
3729 { | |
3730 request.mutable_load_image()->mutable_values()->Add(*p); | |
3731 } | |
3732 } | |
3733 | |
3734 deepLearningState_ = DeepLearningState_Running; | |
3735 SendRequestToWebWorker(request); | |
3736 } | |
3737 else | |
3738 { | |
3739 LOG(ERROR) << "Cannot access the frame content, maybe a color image?"; | |
3740 | |
3741 EM_ASM({ | |
3742 const customEvent = document.createEvent("CustomEvent"); | |
3743 customEvent.initCustomEvent("DeepLearningStep", false, false, | |
3744 { "progress" : "0" }); | |
3745 window.dispatchEvent(customEvent); | |
3746 }); | |
3747 } | |
3748 } | |
3749 else | |
3750 { | |
3751 deepLearningState_ = DeepLearningState_Pending; | |
3752 deepLearningPendingSopInstanceUid_ = sopInstanceUid; | |
3753 deepLearningPendingFrameNumber_ = frameNumber; | |
3754 } | |
3755 } | |
3756 | |
3757 static void DeepLearningNextStep() | |
3758 { | |
3759 switch (deepLearningState_) | |
3760 { | |
3761 case DeepLearningState_Pending: | |
3762 deepLearningState_ = DeepLearningState_Waiting; | |
3763 DeepLearningSchedule(deepLearningPendingSopInstanceUid_, deepLearningPendingFrameNumber_); | |
3764 break; | |
3765 | |
3766 case DeepLearningState_Running: | |
3767 { | |
3768 OrthancStone::Messages::Request request; | |
3769 request.set_type(OrthancStone::Messages::RequestType::EXECUTE_STEP); | |
3770 SendRequestToWebWorker(request); | |
3771 break; | |
3772 } | |
3773 | |
3774 default: | |
3775 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError, "Bad state for deep learning"); | |
3776 } | |
3777 } | |
3778 | |
3779 static void DeepLearningCallback(char* data, | |
3780 int size, | |
3781 void* payload) | |
3782 { | |
3783 try | |
3784 { | |
3785 OrthancStone::Messages::Response response; | |
3786 if (response.ParseFromArray(data, size)) | |
3787 { | |
3788 switch (response.type()) | |
3789 { | |
3790 case OrthancStone::Messages::ResponseType::INITIALIZED: | |
3791 DISPATCH_JAVASCRIPT_EVENT("DeepLearningInitialized"); | |
3792 break; | |
3793 | |
3794 case OrthancStone::Messages::ResponseType::PARSED_MODEL: | |
3795 LOG(WARNING) << "Number of steps in the model: " << response.parse_model().number_of_steps(); | |
3796 DISPATCH_JAVASCRIPT_EVENT("DeepLearningModelReady"); | |
3797 break; | |
3798 | |
3799 case OrthancStone::Messages::ResponseType::LOADED_IMAGE: | |
3800 DeepLearningNextStep(); | |
3801 break; | |
3802 | |
3803 case OrthancStone::Messages::ResponseType::STEP_DONE: | |
3804 { | |
3805 EM_ASM({ | |
3806 const customEvent = document.createEvent("CustomEvent"); | |
3807 customEvent.initCustomEvent("DeepLearningStep", false, false, | |
3808 { "progress" : $0 }); | |
3809 window.dispatchEvent(customEvent); | |
3810 }, | |
3811 response.step().progress() | |
3812 ); | |
3813 | |
3814 if (response.step().done()) | |
3815 { | |
3816 deepLearningState_ = DeepLearningState_Waiting; | |
3817 LOG(WARNING) << "SUCCESS! Mask: " << response.step().output().width() << "x" | |
3818 << response.step().output().height() << " for frame " | |
3819 << response.step().output().sop_instance_uid() << " / " | |
3820 << response.step().output().frame_number(); | |
3821 } | |
3822 else | |
3823 { | |
3824 DeepLearningNextStep(); | |
3825 } | |
3826 | |
3827 break; | |
3828 } | |
3829 | |
3830 default: | |
3831 LOG(ERROR) << "Unsupported response type from the deep learning worker"; | |
3832 } | |
3833 } | |
3834 else | |
3835 { | |
3836 LOG(ERROR) << "Bad response received from the deep learning worker"; | |
3837 } | |
3838 } | |
3839 EXTERN_CATCH_EXCEPTIONS; | |
3752 } | 3840 } |
3753 | 3841 |
3754 static void DeepLearningModelLoaded(emscripten_fetch_t *fetch) | 3842 static void DeepLearningModelLoaded(emscripten_fetch_t *fetch) |
3755 { | 3843 { |
3756 try | 3844 try |
3817 | 3905 |
3818 std::string sopInstanceUid; | 3906 std::string sopInstanceUid; |
3819 unsigned int frameNumber; | 3907 unsigned int frameNumber; |
3820 if (viewport->GetCurrentFrame(sopInstanceUid, frameNumber)) | 3908 if (viewport->GetCurrentFrame(sopInstanceUid, frameNumber)) |
3821 { | 3909 { |
3822 LOG(ERROR) << "OK: " << sopInstanceUid << " / " << frameNumber; | 3910 DeepLearningSchedule(sopInstanceUid, frameNumber); |
3823 | |
3824 FramesCache::Accessor accessor(*framesCache_, sopInstanceUid, frameNumber); | |
3825 if (accessor.IsValid() && | |
3826 accessor.GetImage().GetFormat() == Orthanc::PixelFormat_Float32) | |
3827 { | |
3828 const Orthanc::ImageAccessor& image = accessor.GetImage(); | |
3829 | |
3830 OrthancStone::Messages::Request request; | |
3831 request.set_type(OrthancStone::Messages::RequestType::LOAD_IMAGE); | |
3832 request.mutable_load_image()->set_sop_instance_uid(sopInstanceUid); | |
3833 request.mutable_load_image()->set_frame_number(frameNumber); | |
3834 request.mutable_load_image()->set_width(image.GetWidth()); | |
3835 request.mutable_load_image()->set_height(image.GetHeight()); | |
3836 | |
3837 const unsigned int height = image.GetHeight(); | |
3838 const unsigned int width = image.GetWidth(); | |
3839 for (unsigned int y = 0; y < height; y++) | |
3840 { | |
3841 const float* p = reinterpret_cast<const float*>(image.GetConstRow(y)); | |
3842 for (unsigned int x = 0; x < width; x++, p++) | |
3843 { | |
3844 request.mutable_load_image()->mutable_values()->Add(*p); | |
3845 } | |
3846 } | |
3847 | |
3848 SendRequestToWebWorker(request); | |
3849 } | |
3850 else | |
3851 { | |
3852 LOG(WARNING) << "Cannot access graylevel frame"; | |
3853 } | |
3854 } | 3911 } |
3855 else | 3912 else |
3856 { | 3913 { |
3857 LOG(WARNING) << "No active frame"; | 3914 LOG(WARNING) << "No active frame"; |
3858 } | 3915 } |