embedded-graphics / embedded-graphics

A no_std graphics library for embedded applications
Apache License 2.0
968 stars 91 forks source link

Iterating over pixels in `RawImage` and `Image` #609

Open jamwaffles opened 3 years ago

jamwaffles commented 3 years ago

Context: starting from this message by @jacobrosenthal:

We have all the sexy new from impls for pixels colors, i was hoping to be able to say greyscale a rgb rawimage or image, either wholesale rawimage.into() or via a pixel iterator image.into_iter().map(|p|Gray8::from(p))).collect() but I cant seem to figure a way, am I missing anything?

Did we miss out adding methods to iterate over the pixels in both a RawImage an Image? I think these could be added pretty easily, and would be useful methods to have.

rfuest commented 3 years ago

The need for providing a pixel iterator was deliberately removed from ImageDrawable, because it isn't possible to efficiently implement a pixel iterator for all image drawables. ImageDrawable could, for example, also be implemented for a vector graphics file.

We had discussed this earlier and decided to add additional traits if these features are required later. One trait could be used to provide an iterator over all pixels and another trait to access individual pixels: fn pixel(Point) -> C.

jacobrosenthal commented 3 years ago

For context I'm basically trying to use(abuse) eg as the image-rs library. Run convolution over images etc.

rfuest commented 3 years ago

I've created PR #612 to add a pixel getter trait and implement it for ImageRaws.

For context I'm basically trying to use(abuse) eg as the image-rs library. Run convolution over images etc.

Interesting. Do you plan to output the result to a DrawTarget or generate another image?

jacobrosenthal commented 3 years ago

I might need an intermediate image to do more work, but that wouldnt be the goal. The end result would be the DrawTarget

On Sun, Jun 27, 2021 at 7:52 PM Ralf Fuest @.***> wrote:

I've created PR #612 https://github.com/embedded-graphics/embedded-graphics/pull/612 to add a pixel getter trait and implement it for ImageRaws.

For context I'm basically trying to use(abuse) eg as the image-rs library. Run convolution over images etc.

Interesting. Do you plan to output the result to a DrawTarget or generate another image?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/embedded-graphics/embedded-graphics/issues/609#issuecomment-869299137, or unsubscribe https://github.com/notifications/unsubscribe-auth/AADPI5EVJYIFKVS3ZR6RACLTU7PW3ANCNFSM47CIBGXA .

LLFourn commented 2 months ago

I was looking for something like Framebuffer::iter_pixels. I was able to produce it with RawDataSlice manually but it was tricky to figure out. It seems like ImageRaw and FrameBuffer would benefit from helper methods.

rfuest commented 2 months ago

GetPixel trait implementations for Framebuffer and ImageRaw have been added since this PR was created. It is now possible to iterate over the pixels in an image by using code like this:

let fb = Framebuffer::<...>::new();
let pixels_iter = fb.bounding_box().points().map(|p| (p, fb.pixel(p));

This method of accessing the pixel data is more flexible because you can also mutate pixel colors or access neighbouring pixels to apply effects.

LLFourn commented 2 months ago

@rfuest This is a more flexible approach. My concern was that it's not quite zero-cost compared to the RawDataSice approach. I didn't actually scientifically measure the difference in performance so it might not exist!

rfuest commented 2 months ago

Yes, there will be some overhead with the solution I suggested. I'm currently working on replacing the code that accesses the raw pixel data in ImageRaw and Framebuffer and I'm planning to do some analysis of the performance when this work is completed.

RawDataSlice will be replaced in the next e-g release. Can you tell me more about your use case to make sure it will still be supported?

LLFourn commented 1 month ago

@rfuest I'm basically pre-rendering some stuff in a framebuffer and then scrolling it based on user touch/drag gestures. So I need to iter the pixels inside some subsection of the buffer. Now that I look at it maybe I can use the sub_image feature to do this more idiomatically. If that works I wouldn't even need to do what I'm doing!

[EDIT] Ah ok no this won't work because my framebuffer is a BinaryColor and and the target is Rgb565. So I can get a nice subimage but then I can't iterate the pixels and map them so I can pass to fill_contiguous. Good to know that I can use the subimage for selecting the right pixels from the framebuffer but I'll have to use the RawDataSlice to do the manual iteration.

[EDIT] Actually that won't work either since I can't make RawDataSlice iterator from a SubImage<'_, RawImage<..>>. Hmm It feels like any Drawable should just have a way to get an iterator of the pixels it would draw if it were asked to draw itself?