-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Fix ImageMobject 3D rotation/flipping and remove resampling algorithms lanczos (antialias), box and hamming
#4266
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
base: main
Are you sure you want to change the base?
Conversation
7b059ef to
6aea7b6
Compare
|
I fixed the glitch! The transform coefficients for To fix it, I simply skip the rendering of the image if the quadrilateral of the transformed image cannot contain any pixels (when it's perpendicular to the camera, too small, etc). In order to figure it out, I find the longest side of the quadrilateral and calculate the height from that side: if it's less than 0.5 pixels, do not attempt to render the image. Plus, to help prevent situations where an image is not rendered because two corners are mapped to the same pixel or three corners are mapped to collinear pixels (without the whole image being necessarily invisible, such as when we apply a rather extreme perspective), I defined EDIT: a video showing that images can now be properly flipped as well. Example code: class FlipImage(Scene):
def construct(self):
arr = np.zeros((256, 256, 3), dtype=np.uint8)
arr[:128, :128] = BLUE_E.to_int_rgb()
arr[:128, 128:] = BLUE_D.to_int_rgb()
arr[128:, :128] = BLUE_C.to_int_rgb()
arr[128:, 128:] = DARK_BROWN.to_int_rgb()
image = ImageMobject(arr)
self.add(image)
self.play(image.animate.rotate(TAU/2, axis=UP))
self.wait(0.5)FlipImage.mp4 |
1cfe382 to
9f13443
Compare
9f13443 to
230a301
Compare
230a301 to
651d32b
Compare
Fixes #2412
Therefore, also fixes its duplicates #2979, #3131, #3559 and part of #3646.
As I commented in the "Image issues Tracking" issue #3482:
The solution I described, which was also discussed in some of the issues I mentioned before, consists of leveraging
PIL.Image.Image.transform()to rewriteCamera.display_image_mobject(). Figuring out how to usePIL.Image.Image.transform()was the actual challenge, but this StackOverflow discussion shed light on this problem (thank you very much, mmgp ❤️).I'll use the example provided by @hennels on issue #2412 (thanks!). I'm including the generated video after applying these changes.
There are still some issues, though:
Details
There is a brief glitch at the beginning of this video when the image is perpendicular to the camera. Maybe floating point error? I couldn't figure out how to fix it, but this video is in medium quality and the glitch doesn't show up when I render the scene in high quality. Key point: high quality = more pixels = bigger pixel coordinates https://github.com/user-attachments/assets/562ef7e7-772d-44e0-9137-2511266576c7
ImageIn3D.mp4
However, this PR must introduce a...
BREAKING CHANGE 💥
PIL.Image.Image.transform()only supports theNEAREST,BILINEARandBICUBICresampling algorithms. It does not supportBOX,HAMMINGorLANCZOS. That is a big issue, sinceCamera.display_image_mobject()runs for every frame and you can't opt out of using it. Even in 2D scenes where there's no actual need for a perspective transform, one still has to account for possible shears of an image, which seems to require.transform()anyways. There doesn't seem to exist a proper fix to the 3D rotation / flipping / shear issue without usingPIL.Image.Image.transform().If such fix does not exist, then it is not possible to support
BOX,HAMMINGorLANCZOS. Therefore, I removed support for them in this PR by removing the following constants:I also rewrote
tests/test_graphical_units/test_img_and_svg.py::test_ImageInterpolationto remove those now unsupported resampling algorithms and rewroteAbstractImageMobject.set_resampling_algorithm()to better capture invalid values.Reviewer Checklist