On Wed, Nov 3, 2021 at 11:57 PM Tom Vercauteren <tom.vercaute...@gmail.com> wrote:
> Hello, > > Apologies for cross-posting a question I initially posted on stackoverflow > ( > https://stackoverflow.com/q/69739665/17261462) but having had no response > there I thought this mailing list may be a better place for it. > > I am trying to encode 10 bit images losslessly in a video format. The > images are stored as 16 bit png files (but only use 10 bit - currently the > least significant ones) and I have been working with ffmpeg to create and > read back the video files. > > My best attempt so far is based on > https://stackoverflow.com/a/66180140/17261462 but as mentioned there, I > get > some pixel intensity differences which may be due to rounding when > converting between 10 and 16 bit representation. I tried a few different > means (bit shifting, left bit replication, floating point based scaling) > but haven't yet figured out how to get a trully lossless reconstruction. > > Below is a small piece of python code to replicate my issue. I probably am > doing something wrong there so feedback would be appreciated. > > Upload input png somewhere? I guess that png files use only first 10bits from least significant bit. > ```python > > import subprocessimport numpy as npimport matplotlib.pyplot as > pltimport tempfileimport imageio > # Create simple image > bitdepth = 10 > hbd = int(bitdepth/2) > im0 = np.zeros((1<<hbd,1<<hbd),dtype=np.uint16) > im0[:] = > np.arange(0,1<<bitdepth).reshape(im0.shape)print('im0',np.min(im0),np.max(im0),im0.shape,im0.dtype)# > tile it to be at least 64 pix > im0 = np.tile(im0, (2, > 2))print('im0',np.min(im0),np.max(im0),im0.shape,im0.dtype) > im0ref = im0# bitshift it or rescale intensities#im0 = (im0<<6)#im0 = > (im0<<6) + (im0>>4) > im0 = np.uint16(np.round(im0 * > > np.float64((1<<16)-1)/np.float64((1<<10)-1)))print('im0',np.min(im0),np.max(im0),im0.shape,im0.dtype) > # Save it as png > tmp0 = tempfile.NamedTemporaryFile(suffix='.png', > delete=False)print(f'Using tmp file: {tmp0.name}') > imageio.imwrite(tmp0.name,im0) > # Encode with ffmpeg > tmp1 = tempfile.NamedTemporaryFile(suffix='.mkv', delete=False)# note > that adding the following doesn't seem to impact the results # + ' > -bsf:v hevc_metadata=video_full_range_flag=1' \ > mycmd = f'ffmpeg -y -i {tmp0.name}' \ > + ' -c:v libx265 -x265-params lossless=1' \ > + ' -pix_fmt gray10be' \ > + f' {tmp1.name}'print(mycmd) > p = subprocess.run(mycmd.split(), capture_output=True)print( > 'stdout:', p.stdout.decode() )print( 'stderr:', p.stderr.decode() ) > > tmp2 = tempfile.NamedTemporaryFile(suffix='.png', delete=False) > mycmd = f'ffmpeg -y -i {tmp1.name}' \ > + ' -pix_fmt gray16be' \ > + f' {tmp2.name}'print(mycmd) > p = subprocess.run(mycmd.split(), capture_output=True)print( > 'stdout:', p.stdout.decode() )print( 'stderr:', p.stderr.decode() ) > # Read back with ffmpeg > im1 = imageio.imread(tmp2.name > )print('im1',np.min(im1),np.max(im1),im1.shape,im1.dtype) > # Bitshift or scale back > im1pre = im1#im1 = (im1>>6) > im1 = np.uint16(np.round(im1 * > np.float64((1<<10)-1)/np.float64((1<<16)-1))) > # check the result > plt.figure() > plt.imshow(im0ref) > plt.colorbar() > > plt.figure() > plt.imshow(im1) > plt.colorbar() > > plt.figure() > plt.imshow(np.int32(im1)-np.int32(im0ref)) > plt.colorbar() > print('err: ',np.linalg.norm((np.float32(im1)-np.float32(im0ref)).ravel())) > > plt.show() > ``` > > Many thanks, > > Tom > _______________________________________________ > ffmpeg-user mailing list > ffmpeg-user@ffmpeg.org > https://ffmpeg.org/mailman/listinfo/ffmpeg-user > > To unsubscribe, visit link above, or email > ffmpeg-user-requ...@ffmpeg.org with subject "unsubscribe". > _______________________________________________ ffmpeg-user mailing list ffmpeg-user@ffmpeg.org https://ffmpeg.org/mailman/listinfo/ffmpeg-user To unsubscribe, visit link above, or email ffmpeg-user-requ...@ffmpeg.org with subject "unsubscribe".