pibooth icon indicating copy to clipboard operation
pibooth copied to clipboard

Implement "choose effect" after capture, through a state, or a plugin

Open gilou opened this issue 1 year ago • 5 comments

I would like to add a choice once the capture is done to select a filter, and I'll start with Black&White for this use-case. For now, it's done mostly in the camera code, which may or may not be very sustainable (maybe the picamera effects are better than what can be done in PIL, I honestly don't know).

I'll try to describe the use-case.

  1. Effect per capture Once the capture is done, display it as a preview and allow to choose an effect: color or black & white, if an effect is chosen, apply it on that capture (or store the info for later processing).
  2. Effect on the whole picture Once the whole capture is done, allow to choose an effect to apply on all captures: color/black&white, apply, process, and back to the normal flow

My first thought was to make a plugin for it, but it seems the hurdles I'll go through might actually require a new dedicated state there, could be compounding processing, or simply add a new one.

Anyway, to implement it, it'd be nice to be able to start with show_choice, and make it so that it can do more than the x capture selection. However, I can't customize win.show_choice easily, so I'm diving through ChooseBackground that would be great.. but it hardcodes a call to get_pygame_image("layoutxx.png"…). So what to do?

  • do I contain it in a plugin, trying to implement all the logic in say, the processing state, or do I add a state and attack the core?
  • should I bother trying to reuse the choose state / logic (which may require modifying the core as well), or just go standalone?

This is mostly me venting a bit, I'll try to do a simple version to see if there are obvious answers there ;)

Regards, Gilou

gilou avatar Apr 10 '23 12:04 gilou

OK, for the picture processing, it's "easy enough" to intercept the call using the setup_picture_factory, but it's rather unclean, as it will require access to factory._images (which is documented as is in the docs though ;))

import pibooth
from pibooth.pictures.factory import OpenCvPictureFactory
from pibooth.pictures import get_picture_factory

def bw_filter(image):
    """Dumb cv2 grey filter"""
    return image.convert('L')

@pibooth.hookimpl
def pibooth_setup_picture_factory(cfg, factory):
    """Replace the picture factory using our own, that will filter images"""
    # Not so brilliant, as captures are already there, we need to read _images
    # which should be considered private.
    filtered_images = [ bw_filter(image) for image in factory._images ]
    return get_picture_factory(filtered_images, cfg.get('PICTURE', 'orientation'))

Now, on to the choice interface…

gilou avatar Apr 10 '23 15:04 gilou

Hi @gilou

maybe the picamera effects are better than what can be done in PIL

Yes indeed, we implemented the effect part first for picamera as there were some cool effects (like cartoon or oilpaint) and then we found some limited ones on other camera so we added them but I don't think anyone used the mas we fixed a bug in 2.0.7 about it. This is quite blocking for your plugin as for the picamera the effect is given to the command that take the photo, so we don't have the "clean" image and then the "effect" one, So we cannot have this as a generic plugin.

do I contain it in a plugin, trying to implement all the logic in say, the processing state, or do I add a state and attack the core?

Starting v3 you should be able to add custom state, and I think this would be the best way to do it (between capture and processing).

should I bother trying to reuse the choose state / logic (which may require modifying the core as well), or just go standalone?

I would say go standalone, but if you have to rework parts that we could have in the core feel free to open a pull request.

Bon courage

werdeil avatar Apr 10 '23 20:04 werdeil

Yup, that states hook will make it a lot easier, rather than tapping in the limbo on processing_exit. Heading on to v3, and I see there is specific doc as well, that is awesome, amazing job @anxuae, I'll try to bring some feedback if need be.

I'll keep this open for now, I have a feeling this plugin (or addition) might make more than me happy ;)

I'll just "ignore" the camera effects, assuming it's not up to me to combine them if that makes sense, and make it configurable. My goal is now to add a state on v3, and make it easy to choose a single "post prod" effect. Then we'll see ;)

gilou avatar Apr 10 '23 20:04 gilou

I started coding there: https://gitlab.com/wolface/wolfoto-project/pibooth-select-effect The new state hook is indeed a blessing, however, I'm wondering what would be the elegant way to achieve a few things.

  • influence PictureFactory: I have to act before processing, after capture if I want my setup_factory to be useful, I guess that's intended.
  • use of factory._images: maybe that should belong to a "public" interface, or could be integrated in a more pleasant way for plugins to work with the actual captures, or maybe I should work that out inside a PictureFactory-inherited class, I may have been too lazy, but didn't want to go deeper there.
  • state binding… I used cfg.ugly_selected_filter because cfg was passed around, I'm guessing there is a way to do that in pibooth without using a wild attribute ;)

Also, I was able to use ChooseScene somehow (too bad self.text is hardcoded in resize() ;)), but we will build our own for it, so we can have a selector, an a preview, or something like that, maybe using that nice slider, maybe not…

gilou avatar Apr 11 '23 10:04 gilou

Hi @gilou

Thanks for your nice plugin, seems to be a great add-on

influence PictureFactory: I have to act before processing, after capture if I want my setup_factory to be useful, I guess that's intended.

yes this is the correct way

use of factory._images: maybe that should belong to a "public" interface, or could be integrated in a more pleasant way for plugins to work with the actual captures, or maybe I should work that out inside a PictureFactory-inherited class, I may have been too lazy, but didn't want to go deeper there.

Both are working. But that right _images is private but after reflexion, it could be public. I will change it. Of course it will break compatibility with some plugins, but this a major release, it will probably break several compatibilities

state binding… I used cfg.ugly_selected_filter because cfg was passed around, I'm guessing there is a way to do that in pibooth without using a wild attribute ;)

This is the way to do. The dynamically set variables are generally attached to the app object which gather several variables shared with plugins. You can also save the values as global variables of your plugin. But than mean if an other plugin want to base its behavior on your plugin, it can't because your plugin's global variables are not shared between pibooth hooks

anxuae avatar Apr 27 '23 18:04 anxuae