[x265] [PATCH]Fixed the normalization formula to ouput 0 to 1 and considered max chroma histogram SAD in histogram based scene cut detection

Aruna Matheswaran aruna at multicorewareinc.com
Thu Jun 25 13:44:13 CEST 2020


Updated X265_BUILD and pushed the patch into the master branch
<https://bitbucket.org/multicoreware/x265_git/commits/38774073d45138b01a6abd0e2cfcecae01038a72>
.

On Mon, Jun 22, 2020 at 11:38 AM Praveen Kumar Karadugattu <
praveenkumar at multicorewareinc.com> wrote:

> From 44704e10a60ae314ecd13dfb84c0c4f82d6c1a55 Mon Sep 17 00:00:00 2001
> From: Praveen Kumar Karadugattu <praveenkumar at multicorewareinc.com>
> Date: Wed, 17 Jun 2020 19:28:06 +0530
> Subject: [PATCH] Fixed the normalization formula to ouput 0 to 1 and
>  considered max chroma histogram SAD in histogram based scene cut detection
>
> ---
>  doc/reST/cli.rst           |  8 ++---
>  source/common/param.cpp    |  4 +--
>  source/encoder/encoder.cpp | 75
> ++++++++++++++++++++++------------------------
>  source/encoder/encoder.h   |  6 ++--
>  source/x265cli.cpp         |  2 +-
>  5 files changed, 45 insertions(+), 50 deletions(-)
>
> diff --git a/doc/reST/cli.rst b/doc/reST/cli.rst
> index eceec40..c9e288e 100644
> --- a/doc/reST/cli.rst
> +++ b/doc/reST/cli.rst
> @@ -1462,13 +1462,13 @@ Slice decision options
>  .. option:: --hist-scenecut, --no-hist-scenecut
>
>   Indicates that scenecuts need to be detected using luma edge and chroma
> histograms.
> - :option: `--hist-scenecut` enables scenecut detection using the
> histograms and disables the default scene cut algorithm.
> - :option: `--no-hist-scenecut` disables histogram based scenecut
> algorithm.
> + :option:`--hist-scenecut` enables scenecut detection using the
> histograms and disables the default scene cut algorithm.
> + :option:`--no-hist-scenecut` disables histogram based scenecut
> algorithm.
>
> -.. option:: --hist-threshold <0.0..2.0>
> +.. option:: --hist-threshold <0.0..1.0>
>
>   This value represents the threshold for normalized SAD of edge
> histograms used in scenecut detection.
> - This requires :option: `--hist-scenecut` to be enabled. For example, a
> value of 0.2 indicates that a frame with normalized SAD value
> + This requires :option:`--hist-scenecut` to be enabled. For example, a
> value of 0.2 indicates that a frame with normalized SAD value
>   greater than 0.2 against the previous frame as scenecut.
>   Default 0.01.
>
> diff --git a/source/common/param.cpp b/source/common/param.cpp
> index fb7244e..925f0c4 100644
> --- a/source/common/param.cpp
> +++ b/source/common/param.cpp
> @@ -1688,8 +1688,8 @@ int x265_check_params(x265_param* param)
>            "scenecutThreshold must be greater than 0");
>      CHECK(param->scenecutBias < 0 || 100 < param->scenecutBias,
>              "scenecut-bias must be between 0 and 100");
> -    CHECK(param->edgeTransitionThreshold < 0.0 || 2.0 <
> param->edgeTransitionThreshold,
> -            "hist-threshold must be between 0.0 and 2.0");
> +    CHECK(param->edgeTransitionThreshold < 0.0 || 1.0 <
> param->edgeTransitionThreshold,
> +            "hist-threshold must be between 0.0 and 1.0");
>      CHECK(param->radl < 0 || param->radl > param->bframes,
>            "radl must be between 0 and bframes");
>      CHECK(param->rdPenalty < 0 || param->rdPenalty > 2,
> diff --git a/source/encoder/encoder.cpp b/source/encoder/encoder.cpp
> index 752e5b2..f6bc540 100644
> --- a/source/encoder/encoder.cpp
> +++ b/source/encoder/encoder.cpp
> @@ -222,12 +222,9 @@ void Encoder::create()
>          uint32_t pixelbytes = m_param->internalBitDepth > 8 ? 2 : 1;
>          m_edgePic = X265_MALLOC(pixel, m_planeSizes[0] * pixelbytes);
>          m_edgeHistThreshold = m_param->edgeTransitionThreshold;
> -        m_chromaHistThreshold = m_edgeHistThreshold * 10.0;
> -        m_chromaHistThreshold = x265_min(m_chromaHistThreshold,
> MAX_SCENECUT_THRESHOLD);
> -        m_scaledEdgeThreshold = m_edgeHistThreshold *
> SCENECUT_STRENGTH_FACTOR;
> -        m_scaledEdgeThreshold = x265_min(m_scaledEdgeThreshold,
> MAX_SCENECUT_THRESHOLD);
> -        m_scaledChromaThreshold = m_chromaHistThreshold *
> SCENECUT_STRENGTH_FACTOR;
> -        m_scaledChromaThreshold = x265_min(m_scaledChromaThreshold,
> MAX_SCENECUT_THRESHOLD);
> +        m_chromaHistThreshold = x265_min(m_edgeHistThreshold * 10.0,
> MAX_SCENECUT_THRESHOLD);
> +        m_scaledEdgeThreshold = x265_min(m_edgeHistThreshold *
> SCENECUT_STRENGTH_FACTOR, MAX_SCENECUT_THRESHOLD);
> +        m_scaledChromaThreshold = x265_min(m_chromaHistThreshold *
> SCENECUT_STRENGTH_FACTOR, MAX_SCENECUT_THRESHOLD);
>          if (m_param->sourceBitDepth != m_param->internalBitDepth)
>          {
>              int size = m_param->sourceWidth * m_param->sourceHeight;
> @@ -1450,13 +1447,14 @@ bool Encoder::computeHistograms(x265_picture *pic)
>      memset(edgeHist, 0, EDGE_BINS * sizeof(int32_t));
>      for (uint32_t i = 0; i < m_planeSizes[0]; i++)
>      {
> -        if (!m_edgePic[i])
> -           edgeHist[0]++;
> +        if (m_edgePic[i])
> +            edgeHist[1]++;
>          else
> -           edgeHist[1]++;
> +            edgeHist[0]++;
>      }
> +
>      /* Y Histogram Calculation */
> -    int32_t* yHist = m_curYUVHist[0];
> +    int32_t *yHist = m_curYUVHist[0];
>      memset(yHist, 0, HISTOGRAM_BINS * sizeof(int32_t));
>      for (uint32_t i = 0; i < m_planeSizes[0]; i++)
>      {
> @@ -1468,7 +1466,7 @@ bool Encoder::computeHistograms(x265_picture *pic)
>      {
>          /* U Histogram Calculation */
>          int32_t *uHist = m_curYUVHist[1];
> -        memset(uHist, 0, HISTOGRAM_BINS * sizeof(int32_t));
> +        memset(uHist, 0, sizeof(m_curYUVHist[1]));
>          for (uint32_t i = 0; i < m_planeSizes[1]; i++)
>          {
>              pixelVal = planeU[i];
> @@ -1478,52 +1476,56 @@ bool Encoder::computeHistograms(x265_picture *pic)
>          /* V Histogram Calculation */
>          pixelVal = 0;
>          int32_t *vHist = m_curYUVHist[2];
> -        memset(vHist, 0, HISTOGRAM_BINS * sizeof(int32_t));
> +        memset(vHist, 0, sizeof(m_curYUVHist[2]));
>          for (uint32_t i = 0; i < m_planeSizes[2]; i++)
>          {
>              pixelVal = planeV[i];
>              vHist[pixelVal]++;
>          }
> -        for (int i = 0; i < HISTOGRAM_BINS; i++)
> -        {
> -            m_curMaxUVHist[i] = x265_max(uHist[i], vHist[i]);
> -        }
>      }
>      return true;
>  }
>
> -void Encoder::computeHistogramSAD(double *maxUVNormalizedSad, double
> *edgeNormalizedSad, int curPoc)
> +void Encoder::computeHistogramSAD(double *normalizedMaxUVSad, double
> *normalizedEdgeSad, int curPoc)
>  {
>
>      if (curPoc == 0)
>      {   /* first frame is scenecut by default no sad computation for the
> same. */
> -        *maxUVNormalizedSad = 0.0;
> -        *edgeNormalizedSad  = 0.0;
> +        *normalizedMaxUVSad = 0.0;
> +        *normalizedEdgeSad = 0.0;
>      }
>      else
>      {
> -        /* compute sum of absolute difference of normalized histogram
> bins for maxUV and edge histograms. */
> -        int32_t edgefreqDiff = 0;
> -        int32_t maxUVfreqDiff = 0;
> -        double  edgeProbabilityDiff = 0;
> +        /* compute sum of absolute differences of histogram bins of
> chroma and luma edge response between the current and prev pictures. */
> +        int32_t edgeHistSad = 0;
> +        int32_t uHistSad = 0;
> +        int32_t vHistSad = 0;
> +        double normalizedUSad = 0.0;
> +        double normalizedVSad = 0.0;
>
>          for (int j = 0; j < HISTOGRAM_BINS; j++)
>          {
>              if (j < 2)
>              {
> -                edgefreqDiff = abs(m_curEdgeHist[j] - m_prevEdgeHist[j]);
> -                edgeProbabilityDiff = (double) edgefreqDiff /
> m_planeSizes[0];
> -                *edgeNormalizedSad += edgeProbabilityDiff;
> +                edgeHistSad += abs(m_curEdgeHist[j] - m_prevEdgeHist[j]);
>              }
> -            maxUVfreqDiff = abs(m_curMaxUVHist[j] - m_prevMaxUVHist[j]);
> -            *maxUVNormalizedSad += (double)maxUVfreqDiff /
> m_planeSizes[2];
> +            uHistSad += abs(m_curYUVHist[1][j] - m_prevYUVHist[1][j]);
> +            vHistSad += abs(m_curYUVHist[2][j] - m_prevYUVHist[2][j]);
>          }
> +        *normalizedEdgeSad = normalizeRange(edgeHistSad, 0, 2 *
> m_planeSizes[0], 0.0, 1.0);
> +        normalizedUSad = normalizeRange(uHistSad, 0, 2 * m_planeSizes[1],
> 0.0, 1.0);
> +        normalizedVSad = normalizeRange(vHistSad, 0, 2 * m_planeSizes[2],
> 0.0, 1.0);
> +        *normalizedMaxUVSad = x265_max(normalizedUSad, normalizedVSad);
>      }
>
>      /* store histograms of previous frame for reference */
> -    size_t bufsize = HISTOGRAM_BINS * sizeof(int32_t);
> -    memcpy(m_prevMaxUVHist, m_curMaxUVHist, bufsize);
> -    memcpy(m_prevEdgeHist, m_curEdgeHist, 2 * sizeof(int32_t));
> +    memcpy(m_prevEdgeHist, m_curEdgeHist, sizeof(m_curEdgeHist));
> +    memcpy(m_prevYUVHist, m_curYUVHist, sizeof(m_curYUVHist));
> +}
> +
> +double Encoder::normalizeRange(int32_t value, int32_t minValue, int32_t
> maxValue, double rangeStart, double rangeEnd)
> +{
> +    return (double)(value - minValue) * (rangeEnd - rangeStart) /
> (maxValue - minValue) + rangeStart;
>  }
>
>  void Encoder::findSceneCuts(x265_picture *pic, bool& bDup, double
> maxUVSad, double edgeSad)
> @@ -1542,20 +1544,13 @@ void Encoder::findSceneCuts(x265_picture *pic,
> bool& bDup, double maxUVSad, doub
>          {
>              bDup = true;
>          }
> -        else if (edgeSad > m_edgeHistThreshold && maxUVSad >=
> m_chromaHistThreshold)
> -        {
> -            pic->frameData.bScenecut = true;
> -            bDup = false;
> -        }
> -        else if (edgeSad > m_scaledEdgeThreshold || maxUVSad >=
> m_scaledChromaThreshold)
> +        else if (edgeSad > m_scaledEdgeThreshold || maxUVSad >=
> m_scaledChromaThreshold || (edgeSad > m_edgeHistThreshold && maxUVSad >=
> m_chromaHistThreshold))
>          {
>              pic->frameData.bScenecut = true;
>              bDup = false;
> +            x265_log(m_param, X265_LOG_DEBUG, "scene cut at %d \n",
> pic->poc);
>          }
>      }
> -
> -    if (pic->frameData.bScenecut)
> -       x265_log(m_param, X265_LOG_DEBUG, "scene cut at %d \n", pic->poc);
>  }
>
>  /**
> diff --git a/source/encoder/encoder.h b/source/encoder/encoder.h
> index 2c45886..fd6b3e7 100644
> --- a/source/encoder/encoder.h
> +++ b/source/encoder/encoder.h
> @@ -163,7 +163,7 @@ class RateControl;
>  class ThreadPool;
>  class FrameData;
>
> -#define MAX_SCENECUT_THRESHOLD 2.0
> +#define MAX_SCENECUT_THRESHOLD 1.0
>  #define SCENECUT_STRENGTH_FACTOR 2.0
>
>  class Encoder : public x265_encoder
> @@ -257,8 +257,7 @@ public:
>      pixel*             m_edgePic;
>      pixel*             m_inputPic[3];
>      int32_t            m_curYUVHist[3][HISTOGRAM_BINS];
> -    int32_t            m_curMaxUVHist[HISTOGRAM_BINS];
> -    int32_t            m_prevMaxUVHist[HISTOGRAM_BINS];
> +    int32_t            m_prevYUVHist[3][HISTOGRAM_BINS];
>      int32_t            m_curEdgeHist[2];
>      int32_t            m_prevEdgeHist[2];
>      uint32_t           m_planeSizes[3];
> @@ -373,6 +372,7 @@ public:
>
>      bool computeHistograms(x265_picture *pic);
>      void computeHistogramSAD(double *maxUVNormalizedSAD, double
> *edgeNormalizedSAD, int curPoc);
> +    double normalizeRange(int32_t value, int32_t minValue, int32_t
> maxValue, double rangeStart, double rangeEnd);
>      void findSceneCuts(x265_picture *pic, bool& bDup, double
> m_maxUVSADVal, double m_edgeSADVal);
>
>      void initRefIdx();
> diff --git a/source/x265cli.cpp b/source/x265cli.cpp
> index 5b95698..b53dc2b 100644
> --- a/source/x265cli.cpp
> +++ b/source/x265cli.cpp
> @@ -175,7 +175,7 @@ namespace X265_NS {
>          H1("   --scenecut-bias <0..100.0>    Bias for scenecut detection.
> Default %.2f\n", param->scenecutBias);
>          H0("   --hist-scenecut               Enables histogram based
> scene-cut detection using histogram based algorithm.\n");
>          H0("   --no-hist-scenecut            Disables histogram based
> scene-cut detection using histogram based algorithm.\n");
> -        H1("   --hist-threshold <0.0..2.0>   Luma Edge histogram's
> Normalized SAD threshold for histogram based scenecut detection Default
> %.2f\n", param->edgeTransitionThreshold);
> +        H1("   --hist-threshold <0.0..1.0>   Luma Edge histogram's
> Normalized SAD threshold for histogram based scenecut detection Default
> %.2f\n", param->edgeTransitionThreshold);
>          H0("   --[no-]fades                  Enable detection and
> handling of fade-in regions. Default %s\n", OPT(param->bEnableFades));
>          H1("   --[no-]scenecut-aware-qp      Enable increasing QP for
> frames inside the scenecut window after scenecut. Default %s\n",
> OPT(param->bEnableSceneCutAwareQp));
>          H1("   --scenecut-window <0..1000>   QP incremental duration(in
> milliseconds) when scenecut-aware-qp is enabled. Default %d\n",
> param->scenecutWindow);
> --
> 1.8.3.1
>
>

-- 
Regards,
*Aruna Matheswaran,*
Video Codec Engineer,
Media & AI analytics BU,
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.videolan.org/pipermail/x265-devel/attachments/20200625/340f808d/attachment-0001.html>


More information about the x265-devel mailing list