A quick PSNR/SSIM analyzer for Linux
by Emanuele Oriani
stands for Quick PSNR (PSNR
definition and SSIM definition).
Update 18 Jul 2020
The main sources of this project have been moved to github; this page won't be updated any longer.
Update 11 Feb 2015
Recompiled main 64 bit package with Ubuntu 14.04, now using libavformat54.
Update 16 Nov 2013
Released version 0.2.5, use now the following libraries: libavformat53,
libswscale2. Fixed some bugs, introduced more options (thanks Paul
Caron for helping with porting)
Update 27 Feb 2010
Fixed one bug related to image saving; version updated to 0.2.1.
Update 21 Feb 2010
Apparently Ubuntu people won't release updated libav* libraries until
10.10. This is a bit sad. Nevertheless, I've released them as well
latest binaries. Just scroll below at known issues.
Update 20 Feb 2010
Finally got confirmed that libav*.so.* in Ubuntu 9.10 (and apparently
even 10.04) are broken (ie. don't support finalized Theora format).
Update 18 Feb 2010
As seen as PSNR is good but another objective measure does exist, I've
added to this tool even the ability to compute SSIM (invoke with -a ssim or -a avg_ssim to compute it)
I wanted to compute PSNR of some movies, to perform test analysis on
codecs; unluckily on Linux I could not find any native tool (eg. tools
usable without emulation/wine). One way to compute PSNR is to use
mplayer, extract all the frames you're interested into a temporary
directory, then invoke some other processes to perform it and finally
write it on a file.
This approach has many issues. The most important are that is slow, it
requires a lot of disk space and involves fiddling around. This is not
good. Another issue is that usually PSNR is computed between two
sources, a reference and a derivative of the reference (usually the
derivative is lossy
compressed). Problem is that I would like to perform the PSNR of a
reference video vs. multiple derivatives (like the derivatives
compressed with same codec but different bitrate/settings) and the
mplayer script approach doesn't really make it.
Then I decided to write (in C++ naturally)
my own tool, relying on libavcodec to get
the frames of video streams; once I wrote the base classes to handle
video frames, I then moved on the next big thing to do: make it extremely quick!
Luckily I reused previously written threading (threads and thread
pools) and synchronization (semaphores) classes.
As seen as those had been already tested it has been very
straightforward to implement few bits and put the togheter.
In order to achieve quick performance and
resposiveness I've developed the following architecture:
Here a brief explanation:
- A thread to read frames from Video Reference is created
- Multiple threads to read frames from all the Video derivatives (Video 1, Video 2, ... Video n) are created
- Analyzer threads (to compute the PSNR os SSIM) are created
Then what happens is the following:
- Video threads (green boxes) extract a frame
- Buffers containing the just extracted video frames are handed over to the analyzer threads
- While analyzer threads do process the buffers, Video threads execute step 1.
- When analyzer threads are done, go to step 2.
This way we don't use any tmpfile and we try to use each available core.
Other cool features are that you can get an average of the PSNR (for
example each 25 frames) and you can compute the PSNR of other
colorspaces, not only RGB.
To see all options just run it with -h (or --help) option.
- Multi threaded (tries to use all available cores/CPUs)
- Relies on libavcodec to decode video (dynamic library) so unless something there is broken (see known issues) you're good to go
- Low memory usage (no temporary files needed)
- Easily extendible
- Compute PSNR or SSIM (SSIM as now is only computed in Y colorspace)
./qpsnr -s 1000 -m 500 -r reference_video.avi video1.avi video2.avi video3.avi
will compute the PSNR from frame 1001 to 1500 between reference_video.avi and video1.avi video2.avi video3.avi
./qpsnr -m 500 -a avg_psnr --aopts fpa=25:colorspace=hsi -r reference_video.avi video1.avi video2.avi video3.avi
will compute the PSNR in HSI
colorspace for the first 500 frames, printing the average of each 25 frames
./qpsnr -I -s 2000 --aopts colorspace=ycbcr -r reference_video.avi video1.avi video2.avi video3.avi
will compute the PSNR in YCbCr
colorspace skipping the first 2000 frames, saving each frame as ppm image (careful, this will use a lot
of disk space!).
./qpsnr -s 100 -m 500 -a avg_ssim -o blocksize=16:fpa=30 -r reference_video.avi video1.avi video2.avi video3.avi
will compute the SSIM with block size 16x16 from frame 101 to 501, printing the average each 30 frames, between reference_video.avi and video1.avi video2.avi video3.avi
Download it (v 0.2.5)!
Ubuntu 14.04 amd64
To compile the sources install libavcodec-dev, libavformat-dev
QPSNR It is released under the Gpl V3.
If you have any issue with this process, please do report them to me.
Please report any bug/issue to me!
Past issues - no more applicable
Notes on SSIM
- The current version of libavcodec installed in Ubuntu 9.10 is not
able to properly decode Theora video streams! Ubuntu bug has already been reaised (a forum thread here). To fix this one has to use a more recent (ie. working) version of these libraries. Apparently this won't be fixed in Ubuntu 9.10/10.04 as well, so I've compiled for both i386 and x86-64 the latest version of ffmpeg libraries (those fully support Theora video streams).
I'd recommend not to install those in system directories (mplayer for example doesn't really like them), but simply
decompress in the same directory where you will run your software and
then do the following: export LD_LIBRARY_PATH=`pwd`:$LD_LIBRARY_PATH so when you'll execute qpsnr
from there you'll load the right libraries. Please bear in mind that
other apps could not work, but in this case, just close and reopen a
terminal; with this method nothing will be compromised.
While the PSNR is computed on the whole image for each color channel,
the SSIM is computed only for Y (as in TCbCr colorspace), only on
macroblocks of the specified size; if for example you specify 8x8 size,
the SSIM between 2 frames will be computed on 8x8 tiled
blocks of the image then an average of each block's SSIM will be taken as final value.
Another example, with 640x480 image size and 16x16 SSIM macroblock
size, we'll have 40 (640/16) * 30 (480/16) = 1200 macroblocks: the
reported SSIM will be the average of the single value of each SSIM.
In case you want to tell me anything feel free to contct me at ema at fastwebnet dot it .