I have an animated gif much like this one, where the cyclic nature of the animation causes some frames to be repeated twice within one full loop of the animation.
(From here)
I am currently storing each frame separately in the gif. Is it possible to only store each repeated frame once, to effectively halve the storage space required?
I am creating my gif in MATLAB using the movie2gif converter, but would be happy with an alternative method for gif creation or a post-processing tool.
EDIT
What I mean by the frame repetition is best explained in the context of this example image. There is a frame shown just as the left-hand ball leaves the row of balls. That exact frame is repeated a few frames later, when the left-hand ball is now on its way back to hit the row of balls again. Because of the ordering of frames, it is currently needed to store this
frame twice.
To clarify what I am looking for: I want a way of saving the gif (or post-processing the gif) such that I can keep the full animation sequence (e.g. of 30 frames), but frames which repeat are soft-linked back to the first showing of them, thus removing the need to store them twice.
Judging from the description of movie2gif and its input arguements, it does not appear to be possible. Furthermore, when reading how gifs work (and LZW) compression I can imagine that it is not even possible to reduce the size of a gif like this.
If you want to save only the images that are minimally required and don't mind building the image before you can see it, then you can just store each image and an indexing vector.
In your case it may be possible to find a way to just save half of the image, and then play it in a cycle: forward-backward-forward ... but I don't know whether this is possible.
Related
An HTMLVideoElement can be resampled in order to get different frames into a texture over time.
For example, as shown at https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/Tutorial/Animating_textures_in_WebGL
However- when loading an animated gif into a HTMLImageElement, resampling does not show the updated texture. This is true even if the image is mounted on the dom and the different frames show on that copy.
Is there a standard way to display an animated gif in webgl, or must it be somehow rewritten into a spritesheet (or series of textures) at runtime?
GIFs aren't automatically animated with WebGL (or regular canvas for that matter) and there is no standard way of doing this.
Contrary to video elements GIF images will only draw the first frame via drawImage() while drawing video elements will draw current frame. This is in part because we don't really have access to any of the image's frames via API (this also applies to animated PNG files, aka APNG) and animated images will be handled only as an internal process conducted at the discretion of the browser and only when in DOM.
With video elements though we do have access to "frames", that is, time via currentTime so it's sort of implies that we want to deal with what we see or what exist at the current time.
You have to manually animate a GIF image though. This means you have to extract each frames as separate images/buffers first then show them at the rate you chose. The browser won't help you a bit here, but you can do this by parsing the file format manually.
Of course, this can be a bit tedious, but luckily there are people out there that has done all the lifting and hard work. For example gifuct (I have not tested it myself but there are others out there as well) will allow you to extract each frame from a GIF
Then render each frame you got from that into the frame buffer and upload to the GPU at the frame rate you choose.
Or:
pre-process the GIF into a spritesheet as you mention
or load it as an image sequence instead
or convert the GIF to a video (this may even reduce the total size)
And as a shameless plug if you should consider APNG instead: I have made apng-parser which does the same for APNG files.
My recommendation though is to convert the GIF/APNG to a video file which gives the animation capabilities for free, potentially smaller files, can be buffered and streamed for long animations, less code to include and typically a single file to deal with (you may have to provide different video formats for older browsers). Free software such as FFMpeg can help you with the conversion.
I'm trying to want to know the P-frame at mpeg.
I have a query about reference image.
Why not we use original image instead decoded image to make P-frame?
I-frame, B-frame and P-frame allows to compress the video.
Indeed, in a video you have a lot of redundant information.
Think about a car moving across the screen: all the pixels in the background do not change from a picture to another, only those around the car are "moving". With the I-B-P frame truck, you give the code of the background and then, you just signalling slight changes (the car moving) through vectors.
This way you have to carry less information than if you have to repeat the entire picture each time.
See also:
Video compression
https://stackoverflow.com/a/24084121/3194340
If I have a gif89a which has multiple image blocks that are identical (and small, say 40x40 or 1600 pixels in size), should these continue to increase the final size of the gif file (assuming a sane encoder)?
I'm trying to understand how the LZW compression works. According to the W3C spec, I thought the entire data stream itself (consisting of multiple image blocks) should be be compressed, and thus repeating the same image frame multiple times would incur very little overhead (just the size of the symbol for the the repeated image block). This does not seem to be the case, and I've tested with several encoders (Gimp, Photoshop).
Is this to be expected with all encoders, or are these two just doing it poorly?
With gimp, my test gif was 23k in size when it had 240 identical image blocks, and 58k in size with 500 image blocks, which seems less impressive than my intuition is telling me (my intuition's pretty dumb, so I won't be shocked if/when someone tells me it's incredibly wrong).
[edit]
I need to expand on what it is I'm getting at, I think, to receive a proper answer. I am wanting to handcraft a gif image (and possibly write an encoder if I'm up to it) that will take advantage of some quirks to compress it better than would happen otherwise.
I would like to include multiple sub-images in the gif that are used repeatedly in a tiling fashion. If the image is large (in this case, 1700x2200), gif can't compress the tiles well because it doesn't see them as tiles, it rasters from the top left to the bottom right, and at most a 30 pixel horizontal slice of any given tile will be given a symbol and compressed, and not the 30x35 tile itself.
The tiles themselves are just the alphabet and some punctuation in this case, from a scan of a magazine. Of course in the original scan, each "a" is slightly different than every other, which doesn't help for compression, and there's plenty of noise in the scan too, and that can't help.
As each tile will be repeated somewhere in the image anywhere from dozens to hundreds of times, and each is 30 or 40 times as large as any given slice of a tile, it looks like there are some gains to be had (supposing the gif file format can be bent towards my goals).
I've hand-created another gif in gimp, that uses 25 sub-images repeatedly (about 700 times, but I lost count). It is 90k in size unzipped, but zipping it drops it back down to 11k. This is true even though each sub-image has a different top/left coordinate (but that's only what, 4 bytes up in the header of the sub-image).
In comparison, a visually identical image with a single frame is 75k. This image gains nothing from being zipped.
There are other problems I've yet to figure out with the file (it's gif89a, and treats this as an animation even though I've set each frame to be 0ms in length, so you can't see it all immediately). I can't even begin to think how you might construct an encoder to do this... it would have to select the best-looking (or at least one of the better-looking) versions of any glyph, and then figure out the best x,y to overlay it even though it doesn't always line up very well.
It's primary use (I believe) would be for magazines scanned in as cbr/cbz ebooks.
I'm also going to embed my hand-crafted gif, it's easier to see what I'm getting at than to read my writing as I stumble over the explanation:
LZW (and GIF) compression is one-dimensional. An image is treated as a stream of symbols where any area-to-area (blocks in your terminology) symmetry is not used. An animated GIF image is just a series of images that are compressed independently and can be applied to the "main" image with various merging options. Animated GIF was more like a hack than a standard and it wasn't well thought out for efficiency in image size.
There is a good explanation for why you see smaller files after ZIP'ing your GIF with repeated blocks. ZIP files utilize several techniques which include a "repeated block" type of compression which could do well with small (<32K) blocks (or small distances separating) identical LZW data.
GIF-generating software can't overcome the basic limitation of how GIF images are compressed without writing a new standard. A slightly better approach is used by PNG which uses simple 2-dimensional filters to take advantage of horizontal and vertical symmetries and then compresses the result with FLATE compression. It sounds like what you're looking for is a more fractal or video approach which can have the concept of a set of compressed primitives that can be repeated at different positions in the final image. GIF and PNG cannot accomplish this.
GIF compression is stream-based. That means to maximize compression, you need to maximize the repeatability of the stream. Rather than square tiles, I'd use narrow strips to minimize the amount of data that passes before it starts repeating then keep the repeats within the same stream.
The LZW code size is capped at 12 bits, which means the compression table fills up relatively quickly. A typical encoder will output a clear code when this happens so that the compression can start over, giving good adaptability to fresh content. If you do your own custom encoder you can skip the clear code and keep reusing the existing table for higher compression results.
The GIF spec does not specify the behavior when a delay time of 0 is given, so you're at the mercy of the decoder implementation. For consistent results you should use a delay of 1 and accept that the entire image won't show up immediately.
Problem
I want to convert a long movie into a series on animated GIFs.
Each GIF needs to be <5MB.
Is there any way to determine how large a GIF will be while it is being encoded?
Progress So Far
I can split the movie into individual frames:
ffmpeg -i movie.ogv -r 25 frameTemp.%05d.gif
I can then use convert from ImageMagick to create GIFs. However, I can't find a way to determine the likely file size before running the command.
Alternatively, I can split the movie into chunks:
ffmpeg -i movie.ogv -vcodec copy -ss 00:00:00 -t 00:20:00 output1.ogv
But I've no way of knowing if, when I convert the file to a GIF it will be under 5MB.
A 10 second scene with a lot of action may be over 5MB (bad!) and a static scene could be under 5MB (not a problem, but not very efficient).
Ideas
I think that what I want to do is convert the entire movie into a GIF, then find a way to split it by file size.
Looking at ImageMagick, I can split a GIF into frames, but I don't see a way to split it into animated GIFs of a certain size / length.
So, is this possible?
There currently is no "Stop at this filesize" option in avconv that i'm aware of. It can, of course, be hacked together quite quickly, but currently libav project doesn't do quick hacks, so it'll likely appear in ffmpeg first.
In addition to this you are facing a problem of animated gif being a very old format, and thus doing some rather strange things. Let me explain the way it normally works:
You create a series of frames from first to last and put them on top of one another.
You make all the "future" frames invisible, and set to appear at the specific time.
In order to make the size of the file smaller, you look "below" the new frames, and if the previous pixel is the same, you set that particular pixel as opaque.
That third step is the only time compression that is done in the animated gif, without it the file size will be much larger (since every pixel must be saved again and again).
However, if you are unsure when was the last break, you cannot determine if the pixel is the same as the previous "frames". After all, this particular frame can be the very first one in the image.
If the limit of 5MiB is soft enough to allow going a little over it, you probably can put something together that just keeps adding frame after frame, and calculating the final file size right away. As soon as one goes over the limit, just stop and use the next frame as the starting point for the next file.
I'm trying to split a video by detecting the presence of a marker (an image) in the frames. I've gone over the documentation and I see removelogo but not detectlogo.
Does anyone know how this could be achieved? I know what the logo is and the region it will be on.
I'm thinking I can extract all frames to png's and then analyse them one by one (or n by n) but it might be a lengthy process...
Any pointers?
ffmpeg doesn't have any such ability natively. The delogo filter simply works by taking a rectangular region in its parameters and interpolating that region based on its surroundings. It doesn't care what the region contained previously; it'll fill in the region regardless of what it previously contained.
If you need to detect the presence of a logo, that's a totally different task. You'll need to create it yourself; if you're serious about this, I'd recommend that you start familiarizing yourself with the ffmpeg filter API and get ready to get your hands dirty. If the logo has a distinctive color, that might be a good way to detect it.
Since what you're after is probably going to just be outputting information on which frames contain (or don't contain) the logo, one filter to look at as a model will be the blackframe filter (which searches for all-black frames).
You can write a detect-logo module, Decode the video(YUV 420P FORMAT), feed the raw frame to this module, Do a SAD(Sum of Absolute Difference) on the region where you expect a logo,if SAD is negligible its a match, record the frame number. You can split the videos at these frames.
SAD is done only on Y(luma) frames. To save processing you can scale the video to a lower resolution before decoding it.
I have successfully detect logo using a rpi and coral ai accelerator in conjunction with ffmeg to to extract the jpegs. Crop the image to just the logo then apply to your trained model. Even then you will need to sample a minute or so of video to determine the actual logos identity.