Forum Replies Created
-
AuthorPosts
-
Bruno MarquesBlocked
Hi and sorry for the late reply @btt,
As far as I know SofaCV and ImageProcessing aren’t being used in the Mimesis team, which has a different plugin named OpenCVPlugin for these kinds of tasks.
The SofaCV plugin doesn’t have a huge community of users as of today and I was the main developer working on it. I’ve updated the codebase so that it compiles against the master branch of SOFA, and OpenCV 4.2, with the plugin’s default build options.
If you want extra features, such as the opencv_contrib bindings available through the plugin, you’ll have to do the extra work of fixing the compile issues, although with the basic version compiling, looking at the diff should give you clues on how to fix most issues related to SOFA’s & OpenCV’s evolutions:https://github.com/mimesis-inria/SofaCV/pull/4
https://github.com/mimesis-inria/ImageProcessing/pull/2If you have questions, I’ll try to answer the best I can, although my answers might arrive quite late, as I’m not working on this project anymore.
Best of luck!
– BrunoBruno MarquesBlockedI’ve updated the codebase to match Ubuntu 20.04’s default version, in SofaCV and ImageProcessing.
I only did the essentials (no extra options enabled such as SofaQtQuickGUI widgets, Python3 bindings, OpenCV_Contrib features, etc…) so that the plugins would compile, but hopefully that should put you on track, if you’re willing to go the extra mile.
https://github.com/mimesis-inria/SofaCV/pull/4
https://github.com/mimesis-inria/ImageProcessing/pull/2If you have questions, I’ll try to answer the best I can, although my answers might arrive quite late, as I’m not working on this project anymore.
Best of luck!
– BrunoBruno MarquesBlockedHi @nhnhan, this plug-in is now available on GitHub!
The plug-in has been split into 2 repositories also, SofaCV, which contains mainly interface code, and. ImageProcessing, which contains the code you’re interested in, and depends on SofaCV.
You can check out both plugins at the following link:
https://github.com/mimesis-inria/SofaCV
https://github.com/mimesis-inria/ImageProcessingBruno MarquesBlockedOh, yeah to encourage people to upgrade to 3.7 or 3.8 we have set the minimum python version supported to 3.7
To override that you will have to change it in the main CMakeLists.txt, line 68:# Set the minimum python version to 3.7 set(PYBIND11_PYTHON_VERSION 3.7)
If you change this value to 3.6 the error message should disappear. Tell me if that works for you!
Bruno MarquesBlockedWe do not document the install of an extra python version on a linux distro because it is already relatively well documented on the net. ([see here for instance](https://hackersandslackers.com/multiple-versions-python-ubuntu/)
Usually the trick is to play with update-alternatives (on ubuntu at least) to set additional python versions.When it comes to how to link with the right python libraries and executables when compiling SofaPython3, that should be relatively well documented in the Readme.md of the plugin.
Don’t forget to install python AND the python development packages! 🙂
EDIT:
One more thing, I do not advise you to change the default version of python on your machine (which is possible to do with update-alternatives). It is better to explicitely set the version you want in CMAKE (Python_EXECUTABLE variable), because some system programs might stop working properly if their default python version is overridden)Bruno MarquesBlockedHi @jlorenze,
I believe it it possible to get it to work without much effort. But there will be bugs in error reporting, because of exceptions that can’t be caught in python 3.6-3.7 because of a lack of multithreading support.
We thus chose not to support it (python 3.6 is now 4 years old anyway), and advise our users to install python 3.8+ on their machines (install can easily be done alongside your officially supported version on linux)Have fun with SofaPython3! 🙂
Bruno MarquesBlockedHi @AlbanOdot ,
Here’s the short answer:- how to use writeable():
with self.CFF.forces.writeable() as cff: cff[:] = linear_forces_amplitude * layer
- when should I use which:
in your case
self.CFF.forces.value = linear_force_amplitude * Layer
is as efficient as the writeable versionThe long answer now:
Your first question raises some technical discussions regarding python binding optimizations, I’ll do my best to explain:
When you’re editing a datafield in SOFA, there’s a mechanism that guarantees a thread-safe access by locking / unlocking the access to the data when trying to edit. A call tosetValue()
for instance does 3 things:- lock the data (like a mutex)
- edit the data
- unlock the data to be accessed by other calling points
In the case of the
setValue()
function, this is “invisible” to the user as everything is performed within the function. But when the data is a large vector of values for instance, and that you want to run a set of operations on those values, from the c++ we use beginEdit / endEdit (the locking / unlocking mechanism used within setValue(), that you might have seen in the code of SOFA components already.When it comes to SofaPython3, we want to expose c++ buffers in Python by wrapping it in a numpy array. This is what the
writeable()
function does. But we are still required to use the locking / unlocking mechanism. So if we simply expose the buffer directly using let’s set agetValue()
function returning a writeable buffer, beginEdit() will be called to retreive the value within the getValue() binding function, then the buffer will be returned to python. Now we are inside the python code, with a writeable buffer in our hands, but no clear way on how to “release” the data. We could simply implement anendEdit()
method, but who will think of calling it? This is a huge problem in terms of error management.To circumvent this issue, developers came up with a concept called “RAII” (resource acquisition is initialization). The idea behind RAII is to guarantee that whenever a resource is accessed (here the value of a datafield), its automatic release is guaranteed once were done with it. To do so, the releasing of the resource is attached to the lifetime of the scope in which the resource is being used (which must of course be as short as possible). In the case of SofaPython3, we do this using a ContextManager (with … as xxx:)
The usage of ContextManagers lets the user perform as many operations on your datafield as you want, while only calling beginEdit only once when entering the context (scope), and calling endEdit only once when leaving it.
This is particularily important in python bindings because if you were to call setValue() XXX times to set all the values of a vector datafield for instance, you would ping-pong back and forth between python and c++ through the bindings, each time copying values, which obviously, is very costly and suboptimal.
So in conclusion:
- If you want to perform a single operation on a data : Just use
myData.value = whateverValue
, because anyway, there’s only 1 instruction to execute, so 1 single round-trip through the bindings. - If you’re planning on performing a set of operations on a datafield (for instance running an instruction on each element of a vector field through a for loop…): use a ContextManager: It will significantly limit the number of calls to python bindings and the number of copies of your data, while letting you perform as many operations as you want within the scope of that ContextManager
Here, I hope those explanations are clear enough 😉
Bruno MarquesBlockedHi Zahra,
Sofa does not package numpy with its sources, so your problem, while indeed being an issue with concurrent versions of numpy on your system, is not linked to your install of SOFA. (as far as I know)
I’m no expert in this, but I’d guess that:
– you installed numpy either via your package manager (apt install python-numpy) or via pip (pip install numpy)
– then installed Anaconda, which does, of course, redistributes its own version of python.I *think* that you might be able to fix your issue by uninstalling numpy’s pip (or aptitude) package (using pip uninstall or apt remove).
———————
It seems that you dug a bit in the SofaPython plugin before posting, that’s nice 😉
There’s indeed an example called SofaNumpy in SofaPython, which uses a piece of python code that imports numpy. But this script relies on your system’s install of numpy, so as said before, it should not be the cause of your problem.
That being said, it seems that the SofaNumpy code is supposed to provide shared-memory pointer access to Sofa’s data fields through a numpy array abstraction, which is a must-have feature IMHO. The code does not seem to be functional though, sadly.I actually never realized that there was a SofaNumpy module present in SofaPython, it’s a pretty cool discovery for me. If you have the skills and feel like restoring this code, feel free to do so, we’ll be more than happy to see such a pull request in SOFA!
Meanwhile, we are working on a similar approach in the next gen SofaPython3 plugin whose beta version should be released soon… *teaser*Anyway, I hope this answers your question, and best of luck!
Bruno MarquesBlockedHi and Welcome to Sofa!
Sadly, the runSofa GUI is not meant to allow stepping programmatically.
Luckily, there are some workarounds..:1. SofaPython3 is a plugin in development. It’s purpose is to provide python packages for SOFA, that will let you define your own simulation loop in python by calling SOFA’s animate / step methods manually from python. But I would not encourage you to use it for now as it is still in active development and the API is still likely to change a lot.
2. A (less elegant) alternative is to keep using SofaPython, place a PythonScriptController in your SOFA scene, and hook a socket on its onBeginAnimationStep() method.
This method is called at each step of the simulation, and while you can’t really pause the simulation, you could, through a socket, send a package (in localhost) to a separate process (your learning algorithm) with all the useful stuff from the current simulation step, wait for your other process to send an acknowledgement package before exiting the function.
# something like that (pseudo code) def onBeginAnimationStep(self, dt): sock.send(some_data) ack = sock.recv() return
——————
Concerning your second question, I’m not 100% sure I understood what you mean by “modifying the pythonScriptController” but I assume that your learning algorithm sends you updated data that you need to insert in your simulation (let’s say the young modulus of a FEM ForceField for instance).
Using the approach I suggested, your ACK package could contain the updated values you’d like to apply to your simulation, and your PythonScriptController could take those new values and set them in your scene’s components.
# something like that (pseudo-code) def onBeginAnimationStep(self, dt): sock.send(some_data) ack = sock.recv() y = parse(ack) self.rootNode.myForceField.youngModulus = y self.rootNode.myForceField.reinit() # might be necessary to call reinit() on the component to update the internal values... return
I hope my answer helps, good luck with SOFA, the first time is the worst 😉
Bruno MarquesBlockedHi @Angela_Fifi,
As-is in SOFA, there’s no way of changing the camera’s intrinsic parameters using exisiting components.
There is a plugin, called SofaCV (computer vision) that contains a component called CalibratedCamera, and that can take OpenCV-style camera calibration data in the form of:
– A 3×4 matrix encoding both extrinsic and intrinsic camera parameters
– the K, R, and t parameters as expressed in OpenCV
– A glModelView / glProjection matrix if you’re more comfortable with OpenGL
– A position, up/lookat/ vector, & projection matrix
– …This plugin is hosted at this address: https://gitlab.inria.fr/mimesis/ComputerVision/SofaCV, and while the plugin is Open source, Access is only given upon request I believe.
Otherwise, If you prefer going for your own implementation, I’d suggest to look into the VisualManager class (sofa::core::visual::VisualManager) That let’s you override the OpenGL camera parameters of your scene through the preDrawScene / postDrawScene methods.
If you want to go for the SofaCV plugin, If you want to go for the SofaCV plugin, I believe you would have to create an account on gitlab.inria.fr, and I should then be able to add you to the project’s members 🙂
23 April 2019 at 15:40 in reply to: [SOLVED] How to close the runSofa window/reinitialize it in python? #13426Bruno MarquesBlockedHi @Zahra
This is sadly a recurring issue with SOFA:
As of today, a simulation ran in the runSofa GUI can only be stopped or killed programatically (by usingnode.getRootContext().animate = False
or by for instance callingquit()
in the script to end the program.
There is no way to get from the “paused” state to the “animate” state of the simulation without performing keyboard / mouse interaction.
As I suggested In THIS post, you can hack around by faking mouse or keyboard events.
Although it is quite ugly to do such a thing, the runSofa UI wasn’t designed for this kind of tasks.Whichever way you go, good luck with SOFA!
Bruno MarquesBlockedBonjour Gaetan,
SOFA initialise ses composants en plusieurs étapes.
Tout d’abord, leconstructeur
de la classe est appelé. Les datafields sont initialisées à leurs valeurs par défaut.
Ensuite, la méthodeparse()
est appelée, et cette méthode va (justement) parser ton fichier de scène XML ou python, ou tonBaseObjectDescription
, en fonction de si ta scène est construite depuis le C++, ou depuis un fichier de scène.Enfin, le composant est ‘initialisé’ cà d ses valeurs internes sont mises à jour en fonction des paramètres passés via le mécanisme de DATA.
DONC: tout code dans le constructeur ignorera toujours les valeurs passées à tes data.
Si tu surcharge la méthodeinit()
deBaseObject
, et y déplace le code que tu as actuellement dans le ctor, ca devrait marcher mieux 🙂Bon courage dans tes premiers pas avec SOFA! 🙂
16 February 2019 at 11:03 in reply to: [SOLVED] Problems with Modeler: Can't modify particle property and change componets order #13050Bruno MarquesBlockedSOFA is more a simulation *Framework* as it is a simulation *Software*.
It’s programming language is C++, but (long ago), to simplify scripting, a system has been set in place to describe scenes with XML, and it’s been the main way to create SOFA scenes for a long time.
It’s now much more recommended to create scenes in Python. A Python plugin, present in SOFA’s repository, can be activated with the option PLUGIN_SOFAPYTHON=ON in CMake, and the plugin provides many examples of scenes to give you an idea on how to get started (in applications/plugins/SofaPython)You can also find a (rudimentary) documentation on the plugin here:
It’s in the *optional-features* section, since the plugin is not activated by default, but I would recommend scenes to be created with python all the time, if not in C++ directly.
New developments are being made to improve the GUI user experience, in a separated plugin, but it’s at its premises, so probably not the way to go for you.
Good luck !
15 February 2019 at 09:17 in reply to: [SOLVED] Problems with Modeler: Can't modify particle property and change componets order #13043Bruno MarquesBlockedHi @huntsmanydw,
I personally never used the SOFA modeler so I’m probably not the best suited to answer your question.. But be aware that the modeler, while being present in SOFA’s repository, is not much maintained anymore. While we still apply bugfixes to it, we very rarely add new features to it.
I don’t believe any of the two features you are mentioning are implemented in the modeler, but again, I don’t use the modeler much…Maybe this topic could help you with you out?
Bruno MarquesBlockedHi @Tim,
That’s a good question. To my knowledge there’s no such mechanism.
I looked it up a little bit and it seems that the way the animation works in runSofa is that clicking on the animate button:
– triggers the loop that will call theRealGUI::step()
method.
– This method calls theSimulation::animate()
method that triggers the execution of 1 step of the simulation on the root node for a given dt.
– performs a check on thegetAnimate()
method, and:
– if it returns false, and simulates a click on the animate button, which in turn it stops the loop.
– if it returns true, the next step is called.The thing is, that when the loop is stopped, the program does not enter the loop anymore until the animate button is clicked again, so setting the animate flag to True in python will not actually re-run the loop.
I don’t know if that’s clear…
Anyway, one way to restart the simulation would be to emulate a click on the animate button of the GUI. It’s not really clean, but it could be done by simulating a click on the animate button, or a key press on the spacebar… This is quite a hack, but it would work.
You can simulate keyboard presses usingpyautogui
in python for instance. Your runSofa window must have the focus though.If you go for simulating the keyboard press, there’s still an issue, which is that the spacebar key also toggles the “fly mode” in runSofa’s camera controller, and I have no idea how to prevent that behavior without digging in the code..
The current runSofa gui is quite old, and work is being done to create a new GUI, rare are the bug fixes and new features arriving in runSofa. Sadly, it’s a work in progress and for now we have to bare with runSofa, or develop our own..
Hope this helps… good luck!Bruno MarquesBlockedSorry, I replied a bit too fast the first time:
The results you’re getting means it works:What your code is doing is catching every AnimateEndEvent signals, and stopping the simulation each time.
The AnimateEndEvent’s name is misleading, I admit: it should actually be called “SimulationStepEndEvent”. This signal is sent at the end of each time step.
What you need is defining a condition to stop your simulation (for instance, when the user reaches a target with the surgical tool, or by using a timer.There is no event sent when the simulation is manually stopped by pressing the animate button in the user interface. What I was suggesting was something like this:
void handleEvent(objectmodel::Event* e) { if (simulation::AnimateEndEvent::checkEventType && someInterruptionCondition == true) { this->getContext()->getRootContext()->setAnimate(false); openSomeOtherQApplication(simulationResults) // Open the Widget in a dedicated interface & display the results of the simulation } }
Hope this helps
Bruno MarquesBlockedHi @himanshu,
I’m not a user of windows 10.. but it seems to me that you’re building SOFA without PLUGIN_SOFAPYTHON.– Have you built SOFA by yourself (from sources) or did you download the binaries?
If you built it yourself, you need to enable the SofaPython plugin in your cmake configuration (PLUGIN_SOFAPYTHON=ON)– Are you building the STLIB separately from SOFA, or are you building it as a SOFA_EXTERNAL_DIRECTORY?
– If you are building STLIB with the sources of SOFA, you need to configure it as such (in cmake):
PLUGIN_SOFAPYTHON=ON
SOFA_EXTERNAL_DIRECTORIES=<your STLIB_SOURCE_DIRECTORY>– If you’re building the STLIB as an “out-of-tree build”, you need to pass the path to your SOFA installation directory in CMake:
CMAKE_PREFIX_PATH=<sofa_install_dir>
Bruno MarquesBlocked@rubab123 Your mistake I suppose is that you declared an event pointer in your class declaration.
The prototype of the handleEvent function tells you that it takes a sofa::core::objectmodel::Event pointer as an argument, so that’s the one you have to work with. if you declare an Event* in your class, this one will of course be uninitialized hence unallocated, which means that you’re accessing an undefined space in memory, causing the crash.
Just remove the line you added in your header file, it should work.Bruno MarquesBlocked@rubab123, after reading your last post on the other topic you opened, I’m quite confident that my initial reply answers your problem:
What you want, if I understood correctly, is to wait for a user to execute a simulation in SOFA that would gather some data on the user’s inputs (accuracy, speed…), and, once the simulation is performed, stop the animation and display a plot using the gathered data.
The way I would do it is as follows:
If the scene is made in python (using SofaPython) I would create my scene with a PythonScriptController, and in the onEndAnimationStep method, I would manually stop the scene once the simulation is done (
node.getRootContext().animate = False
), then plot the given data.
If it’s in c++, in a component inheriting BaseObject for instance, I would implement BaseObject’s handleEvent method to check for theAnimateEndEvent
, and if the simulation is complete, stop the simulation (this->getContext()->getRootContext()->animate(false);
), and then plot the graph.I *think* that you want to use SOFA’s simulation loop to handle the interactions with the plot (which would imply keeping the animation running while the plot is being displayed, which would also imply keeping the simulation running…), but that’s not the way to go IMHO.
If instead you keep the SOFA simulation stopped, and handle your plot in a dedicated QApp, you would probably reach the same result with much less troubble.Does this answer your question?
Also, please keep your questions within the same topic on the forum, opening multiple topics for a same question makes things confusing for other users that will be looking for a similar issue.
Bruno MarquesBlockedHi @rubab123,
I’m not sure if I understood correctly, but if what you want is stop / pause the simulation from within a component, you can do this by calling setAnimate(false) on the root context:
this->getContext()->getRootContext()->setAnimate(false);
You can also do this from PythonScriptControllers, if that’s more convenient to you:
node.getRootContext().animate = False
29 January 2019 at 09:02 in reply to: Problem when running SoftRobots python script (SOFA v18.12 on Ubuntu 16.04) #12922Bruno MarquesBlockedHi @nicklj,
Could you tell us more about your build setting?
– Which OS are you on?
– Did you manually activate / deactivate any option in cmake besides PLUGIN_SOFAPYTHON, SOFA_BUILD_METIS?
– Could you dump the whole output of runSofa on the problematic scene?10 August 2018 at 12:18 in reply to: [SOLVED] How to extract the surface of a volumeyric mesh #11649Bruno MarquesBlockedHi Zahra,
You might want to look at the “Tetra2TriangleTopologicalMapping” component.
You can find an example in the scene “examples/Components/topology/Tetra2TriangleTopologicalMapping.scn”Bruno MarquesBlockedAlright!
We ended up finding what was missing.
Whiile my new class type was well declared, it wasn’t registered to the PythonFactory, which handles the lookup of typenames to find out if the BaseData* object provided could be downcasted.In order to get the new type registered, a call to
SP_ADD_CLASS_IN_FACTORY(cvMatData, sofa::Data<sofaor::common::cvMat>)
must be done when initializing the plugin.a function is present in most plugins, called
initExternalModule()
. This function is used for any external modules, such as plugin widgets for the new GUI (runSofa2) or SofaPython’s Factory.Here’s the final implementation of this method in my plugin, as an example:
void initExternalModule() { static bool first = true; if (first) { first = false; #ifdef QT_PLUGIN initResources(); #endif // QT_PLUGIN #ifdef SOFA_HAVE_SOFAPYTHON if (PythonFactory::s_sofaPythonModule) { simulation::PythonEnvironment::gil lock(__func__); // adding new bindings for Data<cvMat> SP_ADD_CLASS_IN_FACTORY(cvMatData, sofa::Data<sofaor::common::cvMat>) } #endif } }
I close the topic!
Bruno MarquesBlockedHi Lionel,
Thanks for your input!
I did that too. There are bindings for AssembledSystem in the compliant plugin, that is slightly different (it has a constructor and destructor, which uses a different SP_* macro.
But fundamentally, the implementation is the same:1. a
SP_DECLARE_TYPE(MyPythonType)
2. multiple static methods for python with the signaturestatic PyObject* MyPythonType_methodName(PyObject*, PyObject*)
3. same for attributes accessors, ctors and dtors if any4.
SP_CLASS_METHODS_BEGIN(MyPythonType) SP_CLASS_METHOD(methodName) [...] SP_CLASS_METHODS_END
5. same for attributes, ctors, dtors etc if any
6.
SP_CLASS_TYPE_BASE_PTR(MyPythonType, MyCppType)
or other variants {ATTRS,NEW_FREE,…}My implementation seems to be respecting this declaration structure, but something is missing, and I can’t find out what… :/
25 September 2017 at 08:46 in reply to: [SOLVED] Retrieve Sofa Scene's OpenGL Viewport from within a component #9991Bruno MarquesBlockedHi @hugo,
Thanks for your reply!
I investigated a bit further and found out a saveScreen() method in helper::gl::Capture.
This function does the screen grab (call to glreadpixels) in runSofa, but will not have the expected behavior in runSofa2.For now, since runSofa2 is not yet fully implemented, I will use runSofa whenever I need this feature, and will maybe try to implement it in a near future.
I also think that it would be interesting to expose this kind of features through SofaPython, but that is a conversation for sofa’s issue tracker more than the forum I guess =)
Thanks anyways! I’ll close this topic
– Bruno -
AuthorPosts