Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Handle floating point round-off error when converting to pixels for h264 animations#8253

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged

Conversation

ngoldbaum
Copy link
Contributor

@ngoldbaumngoldbaum commentedMar 10, 2017
edited
Loading

Rather than handling the rescaling in matplotlib, tell ffmpeg to do the rescaling for us. This avoids issues described in#8250 where the rescaling is susceptible to round-off error. It also allows us to delete some code.

EDIT:

Now let's try rounding the output ofadjusted_figsize. In addition I found that to get this to work properly with yt (and I guess in general any other library that callsset_size_inches after matplotlib does) I needed another call to_adjust_frame_size before actually writing each frame. This avoids the crazy corrupted video I saw in the original issue I opened about this.

@ngoldbaum
Copy link
ContributorAuthor

@efiring I believe you originally added the code I'm deleting. Would you mind taking a look?

# The h264 codec requires that frames passed to it must have a
# a width and height that are even numbers of pixels. This tells
# ffmpeg to rescale the frames to the nearest even number of pixels
# see http://stackoverflow.com/a/20848224/1382869
Copy link
Member

Choose a reason for hiding this comment

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

https:

@ngoldbaumngoldbaumforce-pushed thesimplify-figsize-adjust branch 2 times, most recently from6b9dd12 toe0c212bCompareMarch 10, 2017 01:09
@efiring
Copy link
Member

I don't think this is a good approach. If I understand correctly, what happens with this approach is that each image is generated by mpl (using Agg) with, for example, 501x301 pixels, and then ffmpeg does a massive interpolation to a 500x300 grid. This undoes whatever pixel-snapping and other operations mpl/agg did that involved knowing what the pixel grid would be. I think it fundamentally degrades the image, and I don't see any benefit to it. In the approach I used, the figure size is tweaked so that the desired pixel grid is produced from the start, and never modified. If there is a problem with the floating-point math, I suspect that can be corrected in some more direct way, but I haven't looked at your example in#8250.

wo, ho = self.fig.get_size_inches()
w, h = adjusted_figsize(wo, ho, self.dpi, 2)
if not (wo, ho) == (w, h):
self.fig.set_size_inches(w, h, forward=True)
Copy link
Member

Choose a reason for hiding this comment

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

The fix might be to setforward=False here. Some of the backends will feed-back andmostly go to the size you want (which is another set of things we need to fix, but).

@tacaswell
Copy link
Member

I agree with@efiring , we should handle this on our side by outputting the right sized-frame.

@tacaswelltacaswell added this to the2.0.1 (next bug fix release) milestoneMar 10, 2017
@ngoldbaumngoldbaumforce-pushed thesimplify-figsize-adjust branch frome0c212b tof09dd61CompareMarch 10, 2017 21:22
@ngoldbaum
Copy link
ContributorAuthor

@efiring@tacaswell ok, I've rewritten this pull request in what is hopefully a more copacetic way. Let me know if you have additional comments.

@@ -62,8 +63,8 @@


def adjusted_figsize(w, h, dpi, n):
wnew = int(w * dpi / n) * n / dpi
hnew = int(h * dpi / n) * n / dpi
wnew = np.round(int(w * dpi / n) * n / dpi)
Copy link
Member

Choose a reason for hiding this comment

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

This rounds to the nearest inch which is not what we want.

Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

Ugh, good point!

Unfortunately putting the rounding inframe_size produces a corrupted movie:

http://imgur.com/a/CjftT

@tacaswell
Copy link
Member

If we are having trouble getting this to round trip nicely (and this is a perineal request, the ability to specify the pixel size, not the inch size of the png), then we should fall back to just trimming a single row / column off the image before handing it to ffmpeg.

@ngoldbaum
Copy link
ContributorAuthor

fall back to just trimming a single row / column off the image before handing it to ffmpeg

Is there a straightforward way to do this as an argument to e.g.savefig? I think I could do it using pillow but not easily using pure matplotlib.

@ngoldbaum
Copy link
ContributorAuthor

OK, third (fourth?) time's the charm? I think this one is correct. Now we usenp.nextafter to correct the results ofadjusted_figsize if there's any floating point jitter.

In other news, I now am very annoyed with floating point!

dopplershift reacted with laugh emoji

@njsmith
Copy link

It seems like the underlying problem here is that the agg backend (or whatever) converts figsize to pixels by doingint(width * dpi), and the floating point error +int() truncation introduce some nasty jitter. Rather than trying to model this jitter and correct for it like the PR does right now, maybe it would make more sense to fix the backend code so it computes pixels asround(width * dpi)? This should produce more accurate and predictable results in general, as well as avoiding the super-tricky and fragile code here...

@ngoldbaumngoldbaum changed the titleLet ffmpeg handle image rescaling for h264Handle floating point round-off error when converting to pixels for h264 animationsMar 12, 2017
@@ -337,6 +347,7 @@ def grab_frame(self, **savefig_kwargs):
verbose.report('MovieWriter.grab_frame: Grabbing frame.',
level='debug')
try:
self._adjust_frame_size()
Copy link
Member

Choose a reason for hiding this comment

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

Why do we need this?

Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

What if the animation callback function callsset_size_inches? This happens indirectly with any animation using a yt plot when the figure gets updated. yt assumes it can control the figure size, which is a reasonable assumption everywhere else in matplotlib, except for here when it's trying to work around this h264 issue.

Copy link
Member

Choose a reason for hiding this comment

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

This only partially prevents the problem if the callbacks always set the same size. Probably should cache the size (and dpi) in setup and then re-set them here.

ngoldbaum reacted with thumbs up emoji
Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

thanks for the suggestion, makes the intent clearer

@ngoldbaumngoldbaumforce-pushed thesimplify-figsize-adjust branch from2341c61 to3bdea02CompareMarch 13, 2017 16:50
@ngoldbaumngoldbaumforce-pushed thesimplify-figsize-adjust branch from3bdea02 to53865c5CompareMarch 13, 2017 17:01

# Combine FFMpeg options with pipe-based writing
@writers.register('ffmpeg')
class FFMpegWriter(MovieWriter, FFMpegBase):
Copy link
Member

Choose a reason for hiding this comment

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

why change the mro?

Copy link
Member

Choose a reason for hiding this comment

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

nevemind, I see why ❤️ MI.

stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
creationflags=subprocess_creation_flags)
if not cls._handle_subprocess(p):
Copy link
Member

Choose a reason for hiding this comment

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

could this just bereturn cls._handle_subprocess(p)?

@ngoldbaumngoldbaumforce-pushed thesimplify-figsize-adjust branch from53865c5 to926a59fCompareMarch 13, 2017 18:20
@ngoldbaum
Copy link
ContributorAuthor

OK, I think the test I added is finally passing now.

I had to add some extra code to fix an issue that the travis builds on Ubuntu 12.04 ran into. On that version of Ubuntu they shipped anffmpeg compatibility binary that wrapsavconv. This ffmpeg is not fully compatible with the real ffmpeg (for the purposes of this pull request, it doesn't work with theh264 codec), which caused the test I added to fail. The fix for that is to update the logic that searches forffmpeg to ignore anffmpeg that is really a wrapper foravconv.

In principle in the future this code can be removed since Ubuntu brought back the realffmpeg in 16.04 and Ubuntu 12.04 is going EOL very soon.

@QuLogic
Copy link
Member

QuLogic commentedMar 13, 2017
edited
Loading

Hmm, it may soon be time to switch Travis to the trusty builds. Ifmaster is not going to come out for another month at least, then maybe that time is now.

Copy link
Contributor

@dopplershiftdopplershift left a comment

Choose a reason for hiding this comment

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

Generally 👍 on the approach. (There almost seems as much effort here to fix tests on 12.04 as there is fixing the actual bug.)

if int(x*dpi) % n != 0:
if int(np.nextafter(x, np.inf)*dpi) % n == 0:
x = np.nextafter(x, np.inf)
if int(np.nextafter(x, -np.inf)*dpi) % n == 0:
Copy link
Contributor

Choose a reason for hiding this comment

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

Notelif?

@anntzer
Copy link
Contributor

+1 for not supporting more than the oldest, still Canonical-supported Ubuntu LTS (and that's only a lower bound :-)).

@ngoldbaum
Copy link
ContributorAuthor

@dopplershift yeah, moving travis to use a 14.04 image seems like the way to go come April :)

@tacaswelltacaswell added the Release criticalFor bugs that make the library unusable (segfaults, incorrect plots, etc) and major regressions. labelMar 21, 2017
except OSError:
return False

@classmethod
Copy link
Member

Choose a reason for hiding this comment

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

Is there a reason for using@classmethod rather than@staticmethod here, even though the method doesn't use itscls argument?

Copy link
ContributorAuthor

Choose a reason for hiding this comment

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

No particular reason I think I was under the false impression that can't override a staticmethod in a subclass. In any case I think it makes sense to leave it as is just in case anyone needs access to the data incls in the future.

@efiring
Copy link
Member

As a reminder, we still have the open question as to whether consistently rounding rather than truncating (see#8265) would be a good approach instead of, or in addition to, the floating point adjustment done here.

@tacaswelltacaswellforce-pushed thesimplify-figsize-adjust branch froma507300 to5d4f5deCompareApril 3, 2017 19:18
Copy link
Member

@tacaswelltacaswell left a comment

Choose a reason for hiding this comment

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

Contingent on tests passing.

I added a commit rather than asking@ngoldbaum to make some minor changes.

@ngoldbaum
Copy link
ContributorAuthor

Thanks Tom!

@efiringefiring merged commit44fcb87 intomatplotlib:masterApr 3, 2017
tacaswell pushed a commit that referenced this pull requestMay 3, 2017
Handle floating point round-off error when converting to pixels for h264 animationsConflicts:lib/matplotlib/tests/test_animation.py  - conflicts in tests
@tacaswell
Copy link
Member

backported to v2.0.x ascab1abd

Sorry this missed 2.0.1 :(

@QuLogicQuLogic modified the milestones:2.0.2 (next bug fix release),2.0.1 (next bug fix release)May 3, 2017
@tacaswelltacaswell modified the milestones:2.0.3 (next bug fix release),2.0.2 (critical bug fixes from 2.0.1)May 7, 2017
Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment
Reviewers

@efiringefiringefiring left review comments

@dopplershiftdopplershiftdopplershift left review comments

@QuLogicQuLogicQuLogic left review comments

@tacaswelltacaswelltacaswell approved these changes

Assignees
No one assigned
Labels
Release criticalFor bugs that make the library unusable (segfaults, incorrect plots, etc) and major regressions.topic: animation
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants
@ngoldbaum@efiring@tacaswell@njsmith@QuLogic@anntzer@dopplershift

[8]ページ先頭

©2009-2025 Movatter.jp