scicloj / wolframite

An interface between Clojure and Wolfram Language (the language of Mathematica)
https://scicloj.github.io/wolframite/
Mozilla Public License 2.0
56 stars 2 forks source link

Why is VideoTrim / VideoFrameList this so slow? #116

Open light-matters opened 2 months ago

light-matters commented 2 months ago
(def path--attention-test
  "resources/attention-test--higher-res.webm")

(def frames
  (-> path--attention-test
      w/Video
      (w/VideoTrim [12 24])
      (w/VideoFrameList 20)
      wl/eval))

I feel like all of the work should be on the Wolfram side so why does it take so long (ten minutes so far)? Is it because it's passing all of the image pixels back over to Clojure in a very inefficient way?

holyjak commented 2 months ago

Could be. What if you prevent returning the data by e.g.

  (-> path--attention-test
      w/Video
      (w/VideoTrim [12 24])
      (w/VideoFrameList 20)
      (w/= 'frames)
      (do "done")
      wl/eval))

?

light-matters commented 2 months ago

Good point. I'm not sure that (w/= 'frames) will do what you want with a thread-first macro, but a very good idea. My current solution was to write the frames to file, but this seems more elegant. I should try it later.

light-matters commented 2 months ago

I checked this

(defn make-frames!
  "Like `export-frames!`, but where the frames are kept on the Wolfram side and not passed to the Clojure REPL."
  [path--video]
  (-> path--video
      w/Video
      (w/VideoTrim [12 24])
      (w/VideoFrameList 50)
      (->> (w/= 'frames))
      (do (println "=== frames made ==="))
      wl/eval))

...
(make-frames! ...)
...

(-> (w/Part 'frames 1)
      ((fn [frame]
             (as-> frame f
                  (w/SetAlphaChannel f
                                     (w/ColorDetect f
                                                    (w/ColorsNear
                                                     (w/RGBColor color--ball)
                                                     0.001))))))
             (->> (w/Export  "resources/test.png"))
             wl/eval)

and storing the result internally works much better. This seems sort of obvious in hindsight, but I hadn't really thought of using Wolfram in this way. We should still do something to avoid passing huge data (inefficiently) across the link by accident, but I'm wondering now if we should have some sort of handy API call that makes suppressing the return of data a natural command?

light-matters commented 2 months ago

The way this is done in Wolfram is by using ; (CompoundExpression). This seems to work:

(-> <big thing...>
(->> (w/= 'thing))
      (w/CompoundExpression "=== Not returned ===")
)

Maybe we can make this nicer by putting this under something like

   (->> <big thing...>
      (w/=; 'thing)
   )
holyjak commented 1 month ago

@light-matters What should we do about this one? I'd say close it, since there is no problem with the software itself (only user trying to transfer too large data...)

light-matters commented 1 month ago

I'd close it after we have an eval-quietly or similarly named function in the API.

light-matters commented 1 month ago

@holyjak What do you think of something like

(defn ssh! [x]
    (! `(do ~x  nil)))

added to the API ns?

Edit: or quiet!