shithub: libvpx

Download patch

ref: aec12b097630b9751bcf33306b4f4291c6b98b67
parent: bb01ac96ecee7aa62e4ef1fbf1bdf9518e72e687
author: Jingning Han <jingning@google.com>
date: Fri Mar 15 07:42:39 EDT 2019

Setup AQ mode for perceptual quality

Adapt the quantization to provide higher quality at smooth regions
where the Wiener variance is smaller.

Change-Id: Ibfd594d1de2ba34d2440d0aa7991b0fdac057ea5

--- a/vp9/encoder/vp9_encodeframe.c
+++ b/vp9/encoder/vp9_encodeframe.c
@@ -3594,7 +3594,7 @@
       wiener_variance += cpi->mb_wiener_variance[row * cm->mb_cols + col];
 
   kmeans_data = &cpi->kmeans_data_arr[cpi->kmeans_data_size++];
-  kmeans_data->value = log(1 + wiener_variance);
+  kmeans_data->value = log(1.0 + wiener_variance) / log(2.0);
   kmeans_data->pos = mi_row * cpi->kmeans_data_stride + mi_col;
   if (wiener_variance)
     wiener_variance /=
@@ -5874,17 +5874,23 @@
   }
 
   // Frame segmentation
-  if (cpi->sf.enable_wiener_variance && cm->show_frame) {
-    int mi_row, mi_col;
-    cpi->kmeans_data_size = 0;
-    cpi->kmeans_ctr_num = 5;
+  if (cpi->sf.enable_wiener_variance) {
+    vp9_disable_segmentation(&cm->seg);
+    if (cm->show_frame) {
+      int mi_row, mi_col;
+      cpi->kmeans_data_size = 0;
+      cpi->kmeans_ctr_num = 5;
 
-    for (mi_row = 0; mi_row < cm->mi_rows; mi_row += MI_BLOCK_SIZE)
-      for (mi_col = 0; mi_col < cm->mi_cols; mi_col += MI_BLOCK_SIZE)
-        wiener_var_rdmult(cpi, BLOCK_64X64, mi_row, mi_col, cpi->rd.RDMULT);
+      for (mi_row = 0; mi_row < cm->mi_rows; mi_row += MI_BLOCK_SIZE)
+        for (mi_col = 0; mi_col < cm->mi_cols; mi_col += MI_BLOCK_SIZE)
+          wiener_var_rdmult(cpi, BLOCK_64X64, mi_row, mi_col, cpi->rd.RDMULT);
 
-    vp9_kmeans(cpi->kmeans_ctr_ls, cpi->kmeans_boundary_ls, cpi->kmeans_ctr_num,
-               cpi->kmeans_data_arr, cpi->kmeans_data_size);
+      vp9_kmeans(cpi->kmeans_ctr_ls, cpi->kmeans_boundary_ls,
+                 cpi->kmeans_ctr_num, cpi->kmeans_data_arr,
+                 cpi->kmeans_data_size);
+
+      vp9_perceptual_aq_mode_setup(cpi, &cm->seg);
+    }
   }
 
   {
--- a/vp9/encoder/vp9_segmentation.c
+++ b/vp9/encoder/vp9_segmentation.c
@@ -9,6 +9,7 @@
  */
 
 #include <limits.h>
+#include <math.h>
 
 #include "vpx_mem/vpx_mem.h"
 
@@ -55,6 +56,46 @@
 
   for (i = 0; i < MAX_SEGMENTS; ++i) {
     vp9_set_segdata(seg, i, SEG_LVL_ALT_Q, 2 * (i - (MAX_SEGMENTS / 2)));
+    vp9_enable_segfeature(seg, i, SEG_LVL_ALT_Q);
+  }
+}
+
+void vp9_perceptual_aq_mode_setup(struct VP9_COMP *cpi,
+                                  struct segmentation *seg) {
+  const VP9_COMMON *cm = &cpi->common;
+  const int seg_counts = cpi->kmeans_ctr_num;
+  const int base_qindex = cm->base_qindex;
+  const double base_qstep = vp9_convert_qindex_to_q(base_qindex, cm->bit_depth);
+  const double mid_ctr = cpi->kmeans_ctr_ls[seg_counts / 2];
+  const double var_diff_scale = 8.0;
+  int i;
+
+  assert(seg_counts <= MAX_SEGMENTS);
+
+  vp9_enable_segmentation(seg);
+  vp9_clearall_segfeatures(seg);
+  seg->abs_delta = SEGMENT_DELTADATA;
+
+  for (i = 0; i < seg_counts / 2; ++i) {
+    double wiener_var_diff = mid_ctr - cpi->kmeans_ctr_ls[i];
+    double target_qstep = base_qstep / (1.0 + wiener_var_diff / var_diff_scale);
+    int target_qindex = vp9_convert_q_to_qindex(target_qstep, cm->bit_depth);
+    assert(wiener_var_diff >= 0.0);
+
+    vp9_set_segdata(seg, i, SEG_LVL_ALT_Q, target_qindex - base_qindex);
+    vp9_enable_segfeature(seg, i, SEG_LVL_ALT_Q);
+  }
+
+  vp9_set_segdata(seg, i, SEG_LVL_ALT_Q, 0);
+  vp9_enable_segfeature(seg, i, SEG_LVL_ALT_Q);
+
+  for (; i < seg_counts; ++i) {
+    double wiener_var_diff = cpi->kmeans_ctr_ls[i] - mid_ctr;
+    double target_qstep = base_qstep * (1.0 + wiener_var_diff / var_diff_scale);
+    int target_qindex = vp9_convert_q_to_qindex(target_qstep, cm->bit_depth);
+    assert(wiener_var_diff >= 0.0);
+
+    vp9_set_segdata(seg, i, SEG_LVL_ALT_Q, target_qindex - base_qindex);
     vp9_enable_segfeature(seg, i, SEG_LVL_ALT_Q);
   }
 }
--- a/vp9/encoder/vp9_segmentation.h
+++ b/vp9/encoder/vp9_segmentation.h
@@ -28,6 +28,9 @@
 
 void vp9_psnr_aq_mode_setup(struct segmentation *seg);
 
+void vp9_perceptual_aq_mode_setup(struct VP9_COMP *cpi,
+                                  struct segmentation *seg);
+
 // The values given for each segment can be either deltas (from the default
 // value chosen for the frame) or absolute values.
 //