-
Notifications
You must be signed in to change notification settings - Fork 150
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow callers to pass in output buffers #685
Comments
Have you seen the As for processing on data from external sources I think you should be able to construct an |
Those are in place though (at least the ones I found, like |
See #622 where I had similar thoughts. |
What do you think about something like this? You would only have to implement |
I think that could work, but some downsides I can think of might be:
|
On the other hand standardizing image ops into traits does make it possible to do more advanced usage in generic scenarios such as taking any image ops as an input itself like higher kinded programming does with functions: fn apply_op_twice<O>(op : O, image: Image) where O: ImageOp {
Op.call(image);
Op.call(image);
} Maybe we could even do both methods and write a proc macro which would generate our current non-trait free-standing functions which internally then construct the op struct and then call the structs op impl. This way we get the best of both worlds and give the users the flexibility to choose which method they prefer. At the cost of increased beginner difficulty. |
Okay, so since there is some interest I'll try and come up with some possible design ideas that can take into account some of the more complex cases and the points you mentioned.
I think you'd just put the docs for how a filter works on the struct for it, so they appear at the very top and not in the trait docs.
More than ergonomics actually, since |
Ok, I have thought about some of these points and hope to flesh them out in a master's thesis, so I'll have some better insights after that hopefully. The Curious what others here think, because I think basically reimplementing OpenCV in the age of projects like pytorch is a little bit of a wasted effort. Declarative approaches where operations are completely abstracted away from the actual representation in memory such that optimizations like loop blocking, kernel fusion can be applied over the whole pipeline are the future IMO. I definitely understand if this isn't meant to be a research project tho so excuse my ramblings in that case :D |
|
If there is no |
|
Reading and writing to the same memory violates the borrow checker, lets not forget that |
And a function with the |
Vote for custom allocators in the next rust survey, maybe someone will finally stabilize it. |
I'm not sure I understand your last three comments @cospectrum. Reading and writing to the same memory does not violate the borrow checker? From what I gather this issue is about the lack of the third ownership variant on image processing functions in this library:
Interestingly though, 4. is always computationally equivalently reducible to 3.: fn op(image: &Image) -> Image {
let mut output = Image::new(image.width, image.height);
op(image, &mut output);
output
} And similarly 1. is reducible to 2.: fn op(mut image: Image) -> Image {
op(&mut image);
image
} So we only really need to implement 2. and 3. to unlock all four variants (even generate them with macros somehow). Our current naming conventions using
So maybe we just need to offer variants 2. and 3. if we are interested in being flexible regarding parameter ownership. Unfortunately, not all image processing operations only operate on one image at a time so ownership variants exponentially grow with the number of arguments, but we can probably just follow the variant 2. and 3. patterns for those too. |
|
Well if it's about reducing allocations by reusing buffers then variant 2. and 3. are exactly what you'd want as they let you supply your own already allocated re-usable memory buffer.
|
Owned variant is possible only from inplace. |
This is just an example. We already have a convention to implement |
|
Oh I see, yeah I agree it doesn't bring anything to the table, but when I discussed this in #622 theotherphil mentioned that the I wasn't suggesting we should generate them with macros only that we could since they are easily reducible. |
Lets just find functions that have only this kind of the signature |
If you grep for |
Do you want to replace |
It's a question of style. Ask the owner. |
No I think we should replace I also think we should keep |
I also think we should get rid of shallow functions like this: pub fn open(image: &GrayImage, norm: Norm, k: u8) -> GrayImage {
let mut out = image.clone();
open_mut(&mut out, norm, k);
out
} Since they are potentially misleading to users since they could think that it is implemented using a non-inplace algorithm when in reality it is just forwarding it's implementation to the inplace implementation. |
Should we remove |
We should follow |
They have |
|
Introducing new function is not breaking change. |
I would save |
I'm finding myself wanting to scale/blur/whatever images into an
ndarray
Array3
. Butimageproc
functions all allocate their own output, which is suboptimal in many cases, for example when:I'm not sure adding
do_thing_into
functions for every function in the library is the best way to do this and using inout parameters is cumbersome compared to the current default, so some more generic way to make operations (somewhat) agnostic to where they shove their output might be appropriate.I'm willing to put some time into this, but given that this would break literally every API in the crate I wanted to ask for some opinions before maybe investigating how this could be done.
The text was updated successfully, but these errors were encountered: