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 }