Skip to content
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

Lowpass mean intensity #92

Open
wants to merge 3 commits into
base: feat-preprocess
Choose a base branch
from
Open

Conversation

MarcelMB
Copy link
Contributor

@MarcelMB MarcelMB commented Jan 14, 2025

Correction for fluctuations of the brightness of the entire field of view

  • calculate the mean pixel intensity for every frame
  • apply a butter low pass filter to mean intensity over time
    creates a figure using the interactive start_frame to end_frame config settings, showing raw data and butter filtered data to visually assess if the filter resembles the data or filter setting need to be adjusted in the config
Screenshot 2025-01-14 at 11 23 15 AM

after pressing 'Esc' script continues running

  • scaled images in interactive plot= scaled image by the percentage difference (scaling factor) of raw and butter filtered mean intensity
  • this filter is applied to the already spatial mask-filtered data

similar method used in Daniels notebook from v4 Miniscope
ipynb notebook
he used it to: 'correct the other source of V4 Miniscope noise. This is a fast, ~+3Hz fluctuation of the brightness'

After closing interactive plot the average and maximum difference between the non-scaled and scaled video is displayed:

Average difference per frame freq_filtered vs scaled_images: 2.247828245162964
Maximum difference across all frames freq_filtered vs scaled_images: 10.018150329589844

which seems like it has a rather small effect on frame intensity

choose filter settings here
butter_filter: enable: true order: 3 cutoff_frequency: 3 sampling_rate: 20

I'm not an expert in if I stick to the general best practice coding of mio, but I included a bunch of logging in case of errors and generally tried to tick to the format of video.py


📚 Documentation preview 📚: https://miniscope-io--92.org.readthedocs.build/en/92/

@MarcelMB MarcelMB requested a review from t-sasatani January 14, 2025 19:32
@t-sasatani
Copy link
Collaborator

I sent in @MarcelMB in DM, but I think I will quickly finish getting feat-preprocess in main so that this PR's destination can be changed later to main to be an independent/focused PR.

@sneakers-the-rat
Copy link
Collaborator

either way! it's easy enough for me to read as is. we talked a bit earlier and i was going to use this as a demo case for what i was talking about in the other PR, so either you go first or i do on making some structure for these processing routines :)

@t-sasatani
Copy link
Collaborator

t-sasatani commented Jan 15, 2025

Yeah, as it's not directed to the main, it makes sense to merge instantly, but we don't want the formatting/testing/structuring/discussing/reviewing to accumulate there, so I preferred doing two independent PRs.

That way, the first one will focus on making the base structure, so I was thinking of quickly doing that. I can work on that for a few hours today, but if you have a specific format/preference in mind, I'm happy to let go of it too :-)

Either way works for me.

@sneakers-the-rat
Copy link
Collaborator

sneakers-the-rat commented Jan 15, 2025

i intended to do this today but got caught up on a bunch of other issues that took way longer than i expected. whups. so if you have time and want to go for it then by all means! i'll follow your lead

Basically all I was going to do here was do something like

class FrameProcessor(ABC):
    @abstractmethod
    def process(self, frame: np.ndarray) -> np.ndarray: ...

    def plot(self, fig: Optional[plt.Figure] = None, ax: Optional[plt.Axes] = None) -> tuple[plt.Figure, plt.Axes]:
        """Optionally plot the results of this processing node"""
        return fig, ax

class ButterFilter(FrameProcessor):
    def __init__(self, config: ButterFilterConfig):
        self.config = config
        # init the rest of the list storing data and stuff
    
    def process(...):
        # move all the processing code here.
        # (well not literally all into one method, probably organize it in some other methods, but expose it in this one method)
        
    def plot(...):
        # move all the plotting stuff here, either taking an existing figure/axes pair or making a new one if not passed. 
        # remove any blocking plot calls so that the calling method can handle the display of plots from multiple processing nodes

as we have done elsewhere. i figure that's probably close to what you had in mind, so yno something in that ballpark is what i was thinking but i'm not that picky about it in this case

@t-sasatani
Copy link
Collaborator

Yeah, something along that. I was wondering a bit about some variations in input/output formats when making everything subclass, so if I don't figure it out a nice way, I'll ask or hand it over (or maybe just Unions).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants