Skip to content

Conversation

mgporter
Copy link
Contributor

@mgporter mgporter commented Mar 11, 2024

This update fixes the Binarization Adjust Board issues when opening files from .OMR.

1.) The method Picture.getGrayImage() previously would call adjustImageFormat() after trying to load the gray source. If the source was not available, it would throw an exception. I added a null check here so that this method can return null. This way, Picture.getSource(SourceKey.GRAY) will properly return null if the source is not available (which happens if an OMR is loaded which contains an invalid image file path).

2.) As a result of #1 above, the BinarizationAdjustBoard is now able to check for a gray source using Picture.getSource(SourceKey.GRAY), and if not found, it disables itself with a message to the user.

Screenshot 2024-03-11 160704

3.) Also as a result of #1 above, the original BinarizationBoard no longer causes an exception when it uses Picture.getSource() to check for a gray source.

4.) The BinarizationAdjustBoard also checks to make sure the SheetView is properly loaded before calling .repaint() on the component. Not checking this caused an issue when loading an OMR file (but not when loading directly from an input image).

I also rearranged the binarizationadjustboard methods to be in alphabetical order... sorry for making it harder to read.

Herve - if you think there is anything else I should address please tell me. I was looking at some other things, but wanted to get to this quickly since I would hate to introduce a bug.

…ge AND the original image file cannot be found. Previously, the program would throw an exception in this case because it would be calling Picture.adjustImageFormat() on the unexisting (null) image.
…able. It also checks to make sure the current view is ready before applying a repaint.
@hbitteur hbitteur merged commit 1c97ad1 into Audiveris:development Mar 12, 2024
@hbitteur
Copy link
Contributor

See my comments based on the code of your first PR (especially the use of FilterDescriptor.equals() instead of the non-working "!=")

Regarding this second PR, I think you made the right modifications to cope with no-longer-existing input files.

I'd suggest a few minor code simplifications below.
Since all items in the body of your board are descendants of the LField classs, you can use for example:

adaptiveMeanValue.setVisible(false);

instead of:

        //        adaptiveMeanValue.getLabel().setVisible(false);
        //        adaptiveMeanValue.getField().setVisible(false);

and same thing for the method disableBoard():

        for (Component comp : getBody().getComponents()) {
            comp.setEnabled(false);
        }

instead of:

        //        adaptiveFilterRadioButton.setEnabled(false);
        //        globalFilterRadioButton.setEnabled(false);
        //        adaptiveMeanValue.setEnabled(false);
        //        adaptiveStdDevValue.setEnabled(false);
        //        globalThresholdValue.setEnabled(false);
        //        applyButton.setEnabled(false);
        //        resetButton.setEnabled(false);
        //        applyToBookButton.setEnabled(false);

@mgporter
Copy link
Contributor Author

I'm glad you gave your suggestions! I want to get this right.

While you are at it, the label "Apply to all pages" would be better named "Apply to all sheets".

Done!

Also, I noticed this line in the connect() method of BinarizationAdjustBoard, right after the comment // Re-binarize image if the filter has changed

        if (sheet.getStub().getBinarizationFilter() != previousFilter) {

This is dangerous because it checks if the 2 items share the same address, while we just want to compare their values. And actually, the addresses are different, hence the filter is always re-applied. Bad luck!

Done! Sorry about that, I forgot to check that you had overwritten the equals method. Yours is a better way to do it.

We could even keep the pre-selection of the BinarizationAdjustBoard (the line: baBoard.setSelected(true);) But the user should not press any of the buttons (Apply, Reset, ...). Not very user-friendly! :-)

Perhaps the BinarizationAdjustBoard should be "selectable" (automatically or on demand) only if the input file has been successfully checked for availability beforehand. What do you think of this approach?

Good point. How about the board is added, but only pre-selected if a gray source exists? If the board is not even added to the BoardsPane when a gray source does not exist, the user might think there is a bug, because a UI board they are used to having is suddenly completely missing. If the BinarizationAdjustBoard is at least added, and the user manually selects it, then they will see the reason that it cannot be used, ie, the message "No source image available for binarization" is displayed on the board.

UPDATE: Answering my own question, you are using the callback on connect() to potentially re-launch the binarization. In that case, I'd suggest:

  • To remove the eventClasses item and replace it by null in the constructor
  • To remove the call to super.connect() in connect()
  • To remove the call to super.disconnect() in disconnect()

Perfect, I was just going to ask you your suggestion for this. Unfortunately, I have to keep the empty onEvent method override because this method requires an implementation.

I'd suggest a few minor code simplifications below.

This is great! Those base classes are very convenient!

Sorry for creating two pull requests. Is there a way to add another commit to this pull request? I feel like there should be, let me try it.

@mgporter
Copy link
Contributor Author

Another thing: looking at the Binarization settings in the BookParameters pane in the options menu, I feel like you should keep it. The reason is that the options menu provides fine-grained control over global-scope, book-scope, and sheet-scope variables, so a user with a large book (with many sheets) would probably benefit from that.

By contrast, the BinarizationAdjustBoard provides a quick way to change the current sheet and all sheets, but doesn't provide the sort of control of variable scopes that the BookParameters provides. Although I think this will be useful for most use cases, adding different scopes to this BinarizationAdjustBoard would make it overly complex (with too many apply buttons or options).

So personally, I feel that you can keep both, since they do something similar, but in a different way.

@hbitteur
Copy link
Contributor

We can keep both entry points as you said.

  • From the book parameters, the user can define specifications upfront, with different scopes.
  • From the binary tab, the user can modify and observe the filter "in action"

We must however make sure that the modifications done "on the job" are persisted correctly in the hierarchy of parameters (the same ones used by book parameters dialog)

@mgporter
Copy link
Contributor Author

Ok, I went back and made sure that the BookParameter settings and the BinarizationAdjustBoard settings are in sync. Here are the behaviors of the buttons on the BinarizationAdjustBoard:

apply -> sets a sheet-level scoped filter on this sheet
reset -> now this button properly calls setSpecific(null) on the sheetStub's filterParam to erase the sheet-level scope, and resets the controls back to the book's default.
apply to all sheets -> sets a sheet-level scoped filter on every sheet in this book

This way, the scopes and values work correctly, and are properly reflected in the BookParameters menu.

mgporter added a commit to mgporter/audiveris that referenced this pull request Mar 12, 2024
…er key for apply, the reset button now resets the sheet to book-level scope values, and other issues from PR Audiveris#717
mgporter added a commit to mgporter/audiveris that referenced this pull request Mar 13, 2024
…er key for apply, the reset button now resets the sheet to book-level scope values, and other issues from PR Audiveris#717
@hbitteur
Copy link
Contributor

[Re-phrasing and extending my comments sent by email]

apply -> sets a sheet-level scoped filter on this sheet

OK for a multi-sheet book.
For a single-sheet book, sets the book-level filter

reset -> now this button properly calls setSpecific(null) on the sheetStub's filterParam to erase the sheet-level scope, and resets the controls back to the book's default.

OK for a multi-sheet book.
For a single-sheet book, sets the controls back to global default

apply to all sheets -> sets a sheet-level scoped filter on every sheet in this book

I disagree here.
Rather than setting the filter specifically on every sheet in the book, we should set the filter at book level.
Doing so, unless a given sheet has a specific filter, the book filter is chosen for this sheet.

For consistency, the button "Apply to all sheets" should be in fact named "Apply to whole book"

I just checked the book parameters dialog:

  • For a multi-sheet book, we have at least 4 tabs: Default, Book, Sheet1, Sheet2, ...
  • For a single-sheet book, we have exactly 2 tabs: Default, Book. And the modifications (for book) are stored at book-level not at sheet-level.

Still for consistency, in BinarizationAdjustBoard for a single-sheet book:

  • the button "Apply to whole book" should not exist (or not be visible)
  • the Apply and Reset buttons should impact the book-level, not the sheet-level

@mgporter
Copy link
Contributor Author

Got it, I just finished adding in these details. I hadn't realized that the program treated single-sheet and multi-sheet books a little differently. See my new PR for details, and if you can think of anything else, let me know.

@mgporter
Copy link
Contributor Author

Hi Herve! I used your feedback to make the improvements in PR #719. If you have any suggestions, let me know.

hbitteur pushed a commit that referenced this pull request Apr 1, 2024
…er key for apply, the reset button now resets the sheet to book-level scope values, and other issues from PR #717
IllTemperedMax pushed a commit to IllTemperedMax/audiveris that referenced this pull request Nov 14, 2024
…er key for apply, the reset button now resets the sheet to book-level scope values, and other issues from PR Audiveris#717
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.

2 participants