Setup AQ mode for perceptual quality
authorJingning Han <jingning@google.com>
Fri, 15 Mar 2019 18:42:39 +0000 (11:42 -0700)
committerJingning Han <jingning@google.com>
Fri, 15 Mar 2019 22:47:59 +0000 (15:47 -0700)
Adapt the quantization to provide higher quality at smooth regions
where the Wiener variance is smaller.

Change-Id: Ibfd594d1de2ba34d2440d0aa7991b0fdac057ea5

vp9/encoder/vp9_encodeframe.c
vp9/encoder/vp9_segmentation.c
vp9/encoder/vp9_segmentation.h

index 0141b48..414551a 100644 (file)
@@ -3594,7 +3594,7 @@ static int wiener_var_rdmult(VP9_COMP *cpi, BLOCK_SIZE bsize, int mi_row,
       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 @@ static void encode_frame_internal(VP9_COMP *cpi) {
   }
 
   // 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);
+    }
   }
 
   {
index 812d3fc..846ee3b 100644 (file)
@@ -9,6 +9,7 @@
  */
 
 #include <limits.h>
+#include <math.h>
 
 #include "vpx_mem/vpx_mem.h"
 
@@ -59,6 +60,46 @@ void vp9_psnr_aq_mode_setup(struct segmentation *seg) {
   }
 }
 
+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);
+  }
+}
+
 // Based on set of segment counts calculate a probability tree
 static void calc_segtree_probs(int *segcounts, vpx_prob *segment_tree_probs) {
   // Work out probabilities of each segment
index aa34dc8..9404c38 100644 (file)
@@ -28,6 +28,9 @@ void vp9_clear_segdata(struct segmentation *seg, int segment_id,
 
 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.
 //