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

Fix min/max String Exception bug #577

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open

Fix min/max String Exception bug #577

wants to merge 4 commits into from

Conversation

gselzer
Copy link
Contributor

@gselzer gselzer commented Sep 12, 2018

When you provide an image of a type that can be negative, the Op can attempt to access the string of valid ascii image characters at a negative index, throwing an error. This PR fixes the bug and adds a test containing the code that threw an error before, as well as making sure that the clamped ascii image is not the same as the unclamped image.

// unclamped String
final String asciiUnclamped = (String) ops.run(DefaultASCII.class, img);

assertTrue(asciiUnclamped != ascii);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When comparing strings, use equals instead of !=. The latter compares reference equality, which is not what you want to test here. Better in this case: use assertEquals(asciiUnclamped, ascii). And if you do want to compare reference equality, you can use assertSame for that.

for (int j = 0; j < width; j++) {
assertTrue(ascii.charAt(i * (width + 1) + j) == CHARS.charAt(i));
}
assertTrue(ascii.charAt(i * (width + 1) + width) == '\n');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use assertEquals here.

final String ascii = (String) ops.run(DefaultASCII.class, img, min, max);
for (int i = 0; i < len; i++) {
for (int j = 0; j < width; j++) {
assertTrue(ascii.charAt(i * (width + 1) + j) == CHARS.charAt(i));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use assertEquals here.

@@ -115,6 +117,8 @@ public String calculate(final IterableInterval<T> input) {
// normalized = (value - min) / (max - min)
tmp.set(cursor.get());
tmp.sub(min);
// NB: if a value is below min we set tmp to zero.
if (tmp.compareTo(zero) < 0) tmp.setZero();
final double normalized = tmp.getRealDouble() / span.getRealDouble();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As long as we are bending over backwards to use the ImgLib2 math APIs... why don't we use tmp.div(span), and only afterward call getRealDouble on the result?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, this will not work if the type does not support decimal values, since we are normalizing the data. I will fix this Wednesday morning.

@@ -115,6 +117,8 @@ public String calculate(final IterableInterval<T> input) {
// normalized = (value - min) / (max - min)
tmp.set(cursor.get());
tmp.sub(min);
// NB: if a value is below min we set tmp to zero.
if (tmp.compareTo(zero) < 0) tmp.setZero();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is inconsistent to protect against <0 normalized values here, but then protect against >=1 normalized values inside the charAt call below. I would prefer to do both checks the same way: by clamping charIndex to [0, charLen). Then you do not need any contortions with a special zero variable etc.

@gselzer
Copy link
Contributor Author

gselzer commented Sep 17, 2018

@ctrueden I reorganized the math within DefaultASCII.java and replaced the assertTrue statements with assertEquals (or assertNotEquals). Let me know if there is anything else that you see. Thanks!

@gselzer
Copy link
Contributor Author

gselzer commented Sep 19, 2018

@ctrueden after pushing the changes that you suggested I got test failures. This is due to the fact that we cannot simply use tmp.div(span) get the normalized value to pull from the ASCII string, since this will cause a rounding error if the RealType of the image is not FloatType or DoubleType. I left double normalization in the code because I did not see a better way of doing it at the time. Let me know if you have any concerns or ideas as to improving this section.

@ctrueden
Copy link
Member

I have a thought. This op is nothing else than a convert/scale/dither to the right destination type, followed by a direct mapping of that type's values to character symbols. We should lean on another op foe the first part, and solve the scaling conversion problem really well across a wide variety of types in that helper op.

@ctrueden ctrueden added the to do label Oct 3, 2018
@gselzer
Copy link
Contributor Author

gselzer commented Jan 14, 2019

@ctrueden I took your advice and leaned on some helper Ops to simplify the code. Note that we convert to DoubleType to prevent rounding errors (correct me if I am wrong, but I think this is necessary) and used image.normalize to scale the data down. From there all that the Op has to do is cast each data value to an int, then use that int to convert to ASCII. The regression tests that we made still pass.

@gselzer
Copy link
Contributor Author

gselzer commented May 18, 2020

@ctrueden I rebased this over master. It seems to me like it is ready to merge. Thoughts?

gselzer added 4 commits May 3, 2023 09:46
When you provide an image of a type that can be negative, the Op can
attempt to access the string of valid ascii image characters at a
negative index, throwing an error. This bug was fixed and a test was
added with the code that threw an error before, as well as making sure
that the clamped ascii image is not the same as the unclamped image.
Note: if the RealType of the image is not a type supporting floating point
numbers, then div(span) on that type would cause a rounding error. This
is the reason that normalized has to call getRealDouble() twice,
although it seems it would be nicer if we used the Imglib2 Type Math.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants