Adding SSIM and PSNR videoFrame based functions

Review URL: https://webrtc-codereview.appspot.com/867005

git-svn-id: http://webrtc.googlecode.com/svn/trunk@2871 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
mikhal@webrtc.org 2012-10-04 17:22:32 +00:00
parent f9a0713866
commit 3f9a721da5
3 changed files with 78 additions and 13 deletions

View File

@ -139,10 +139,18 @@ int MirrorI420UpDown(const VideoFrame* src_frame,
VideoFrame* dst_frame);
// Compute PSNR for an I420 frame (all planes).
double I420PSNR(const VideoFrame* ref_frame,
const VideoFrame* test_frame);
// Compute SSIM for an I420 frame (all planes).
double I420SSIM(const VideoFrame* ref_frame,
const VideoFrame* test_frame);
// TODO(mikhal): Remove these functions and keep only the above functionality.
// Compute PSNR for an I420 buffer (all planes).
double I420PSNR(const uint8_t* ref_frame,
const uint8_t* test_frame,
int width, int height);
// Compute SSIM for an I420 frame (all planes).
// Compute SSIM for an I420 buffer (all planes).
double I420SSIM(const uint8_t* ref_frame,
const uint8_t* test_frame,
int width, int height);

View File

@ -158,8 +158,7 @@ TEST_F(TestLibYuv, ConvertTest) {
output_file) != static_cast<unsigned int>(frame_length_)) {
return;
}
psnr = I420PSNR(orig_frame.Buffer(), res_i420_frame.Buffer(),
width_, height_);
psnr = I420PSNR(&orig_frame, &res_i420_frame);
// Optimization Speed- quality trade-off => 45 dB only (platform dependant).
EXPECT_GT(ceil(psnr), 44);
j++;
@ -171,8 +170,7 @@ TEST_F(TestLibYuv, ConvertTest) {
kUYVY, 0, out_uyvy_buffer));
EXPECT_EQ(0, ConvertToI420(kUYVY, out_uyvy_buffer, 0, 0, width_, height_,
0, kRotateNone, &res_i420_frame));
psnr = I420PSNR(orig_frame.Buffer(), res_i420_frame.Buffer(),
width_, height_);
psnr = I420PSNR(&orig_frame, &res_i420_frame);
EXPECT_EQ(48.0, psnr);
if (fwrite(res_i420_frame.Buffer(), 1, frame_length_,
output_file) != static_cast<unsigned int>(frame_length_)) {
@ -211,8 +209,7 @@ TEST_F(TestLibYuv, ConvertTest) {
return;
}
psnr = I420PSNR(orig_frame.Buffer(), res_i420_frame.Buffer(),
width_, height_);
psnr = I420PSNR(&orig_frame, &res_i420_frame);
EXPECT_EQ(48.0, psnr);
j++;
delete [] outYV120Buffer;
@ -229,8 +226,7 @@ TEST_F(TestLibYuv, ConvertTest) {
output_file) != static_cast<unsigned int>(frame_length_)) {
return;
}
psnr = I420PSNR(orig_frame.Buffer(), res_i420_frame.Buffer(),
width_, height_);
psnr = I420PSNR(&orig_frame, &res_i420_frame);
EXPECT_EQ(48.0, psnr);
// printf("\nConvert #%d I420 <-> RGB565\n", j);
@ -245,8 +241,7 @@ TEST_F(TestLibYuv, ConvertTest) {
output_file) != static_cast<unsigned int>(frame_length_)) {
return;
}
psnr = I420PSNR(orig_frame.Buffer(), res_i420_frame.Buffer(),
width_, height_);
psnr = I420PSNR(&orig_frame, &res_i420_frame);
// TODO(leozwang) Investigate the right psnr should be set for I420ToRGB565,
// Another example is I420ToRGB24, the psnr is 44
EXPECT_GT(ceil(psnr), 40);
@ -263,8 +258,7 @@ TEST_F(TestLibYuv, ConvertTest) {
output_file) != static_cast<unsigned int>(frame_length_)) {
return;
}
psnr = I420PSNR(orig_frame.Buffer(), res_i420_frame.Buffer(),
width_, height_);
psnr = I420PSNR(&orig_frame, &res_i420_frame);
// TODO(leozwang) Investigate the right psnr should be set for I420ToARGB8888,
EXPECT_GT(ceil(psnr), 42);

View File

@ -284,6 +284,69 @@ int MirrorI420UpDown(const VideoFrame* src_frame,
width, -height);
}
// Compute PSNR for an I420 frame (all planes)
double I420PSNR(const VideoFrame* ref_frame,
const VideoFrame* test_frame) {
if (!ref_frame || !test_frame)
return -1;
else if ((ref_frame->Width() != test_frame->Width()) ||
(ref_frame->Height() != test_frame->Height()))
return -1;
else if (ref_frame->Width() == 0u || ref_frame->Height() == 0u)
return -1;
int height = ref_frame->Height() ;
int width = ref_frame->Width();
int half_width = (width + 1) >> 1;
int half_height = (height + 1) >> 1;
const uint8_t* src_y_a = ref_frame->Buffer();
const uint8_t* src_u_a = src_y_a + width * height;
const uint8_t* src_v_a = src_u_a + half_width * half_height;
const uint8_t* src_y_b = test_frame->Buffer();
const uint8_t* src_u_b = src_y_b + width * height;
const uint8_t* src_v_b = src_u_b + half_width * half_height;
// In the following: stride is determined by width.
double psnr = libyuv::I420Psnr(src_y_a, width,
src_u_a, half_width,
src_v_a, half_width,
src_y_b, width,
src_u_b, half_width,
src_v_b, half_width,
width, height);
// LibYuv sets the max psnr value to 128, we restrict it to 48.
// In case of 0 mse in one frame, 128 can skew the results significantly.
return (psnr > 48.0) ? 48.0 : psnr;
}
// Compute SSIM for an I420 frame (all planes)
double I420SSIM(const VideoFrame* ref_frame,
const VideoFrame* test_frame) {
if (!ref_frame || !test_frame)
return -1;
else if ((ref_frame->Width() != test_frame->Width()) ||
(ref_frame->Height() != test_frame->Height()))
return -1;
else if (ref_frame->Width() == 0u || ref_frame->Height() == 0u)
return -1;
int height = ref_frame->Height() ;
int width = ref_frame->Width();
int half_width = (width + 1) >> 1;
int half_height = (height + 1) >> 1;
const uint8_t* src_y_a = ref_frame->Buffer();
const uint8_t* src_u_a = src_y_a + width * height;
const uint8_t* src_v_a = src_u_a + half_width * half_height;
const uint8_t* src_y_b = test_frame->Buffer();
const uint8_t* src_u_b = src_y_b + width * height;
const uint8_t* src_v_b = src_u_b + half_width * half_height;
int stride_y = width;
int stride_uv = half_width;
return libyuv::I420Ssim(src_y_a, stride_y,
src_u_a, stride_uv,
src_v_a, stride_uv,
src_y_b, stride_y,
src_u_b, stride_uv,
src_v_b, stride_uv,
width, height);
}
// Compute PSNR for an I420 frame (all planes)
double I420PSNR(const uint8_t* ref_frame,
const uint8_t* test_frame,