I am using python (scikit-image) and octave to generate 200 images as follows
Python3
import numpy as np
from skimage.io import imsave
images = [255*np.ones((100,100), dtype=np.uint8), # white
np.zeros((100,100), dtype=np.uint8)] # black
for i in range(200): # save alternating black and white images
imsave('%04d.png'%(i+1), images[i%2])
Octave
pkg load image;
im1 = 255*ones(100,100); # white
im2 = zeros(100,100); # black
for i=1:200
name = sprintf('%04d.png', i);
if mod(i,2) == 0
imwrite(im1, name);
else
imwrite(im2, name);
end
end
Next, I use ffmpeg to generate two videos (alternating white and black frames) from these two sets of images using the following command
ffmpeg -r 10 -loglevel quiet \
-i ./%04d.png -c:v libx264 \
-preset ultrafast -crf 0 ./out.mkv
Why do we have this apparently very strange behavior?
EDIT
Since it was suggested that the behavior might be due to octave and python using different bit-depths to store the images, I changed the octave code to use 8 bit numbers
im1 = uint8(255*ones(100,100)); # white
im2 = uint8(zeros(100,100)); # black
and now the image file sizes are nearly the same
but the problem is still the same for video files, octave: 60K, python: 116K
scikit-image (using PIL underneath the hood) saves the PNGs in 8-bit format, while octave uses 16-bit (as mentioned by @carandraug below, this happens because floating point data is provided in Octave, which PNG does not support directly, so the data is converted to uint16 instead). This alone would explain the difference in sizes (although their may be other subtle differences in the ways their encoders work).
scikit-image:
$ identify 000*.png
0001.png PNG 100x100 100x100+0+0 8-bit RGB 256c 120B 0.000u 0:00.000
0002.png[1] PNG 100x100 100x100+0+0 8-bit RGB 256c 90B 0.000u 0:00.000
0003.png[2] PNG 100x100 100x100+0+0 8-bit RGB 256c 120B 0.000u 0:00.000
0004.png[3] PNG 100x100 100x100+0+0 8-bit RGB 256c 90B 0.000u 0:00.000
0005.png[4] PNG 100x100 100x100+0+0 8-bit RGB 256c 120B 0.000u 0:00.000
0006.png[5] PNG 100x100 100x100+0+0 8-bit RGB 256c 90B 0.000u 0:00.000
0007.png[6] PNG 100x100 100x100+0+0 8-bit RGB 256c 120B 0.000u 0:00.000
0008.png[7] PNG 100x100 100x100+0+0 8-bit RGB 256c 90B 0.000u 0:00.000
0009.png[8] PNG 100x100 100x100+0+0 8-bit RGB 256c 120B 0.000u 0:00.000
Octave:
$ identify 000*.png
0001.png PNG 100x100 100x100+0+0 16-bit RGB 98B 0.000u 0:00.000
0002.png[1] PNG 100x100 100x100+0+0 16-bit RGB 192B 0.000u 0:00.000
0003.png[2] PNG 100x100 100x100+0+0 16-bit RGB 98B 0.000u 0:00.000
0004.png[3] PNG 100x100 100x100+0+0 16-bit RGB 192B 0.000u 0:00.000
0005.png[4] PNG 100x100 100x100+0+0 16-bit RGB 98B 0.000u 0:00.000
0006.png[5] PNG 100x100 100x100+0+0 16-bit RGB 192B 0.000u 0:00.000
0007.png[6] PNG 100x100 100x100+0+0 16-bit RGB 98B 0.000u 0:00.000
0008.png[7] PNG 100x100 100x100+0+0 16-bit RGB 192B 0.000u 0:00.000
0009.png[8] PNG 100x100 100x100+0+0 16-bit RGB 98B 0.000u 0:00.000
On my machine (ffmpeg 2.8.11-0ubuntu0.16.04.1), both videos end up being 116KB.