ヒストグラムを作成する

以下の例では、1ごとの頻度分布を求めています。

//8bit画像のヒストグラム配列を作成する。
void GetHist
(
  BYTE **btaaData,
  int nRow,
  int nCol,
  int naHist,
  UINT uiaHist[256],
  UINT *uiMode
)
{
  int i, j;
  
  *uiMode = 0;

  for ( i = 0; i < 255; i++ )
  {
    uiaHist = 0;
  }

  //ヒストグラムの登録
  for ( i = 0; i < nRow; i++ )
  {
    for ( j = 0; j < nCol; j++ )
    {
      if ( uiaHist[btaaData[i][j]] == UINT_MAX )
      {
        continue;
      }
      else
      {
        uiaHist[ btaaData[i][j] ]++;
      }
      
      //最頻値を計算
      if ( uiaHist[ btaaData[i][j] ] >= *uiMode ) 
      {
        *uiMode = uiaHist[ btaaData[i][j] ];
      }
    }
  }
}

ヒストグラムの画像化

以下の例では、縦=最頻値、横=レベル数の2値マトリックスを作成します。

void ResultInMatrix( UINT uiaHist[255], BOOL **baaHist, int nMode )
{
  int i, j;
  
  //縦=最頻値、横=レベル数の画像を作成
  (*baaHist) = (BYTE *)calloc( nMode * 255sizeof(BYTE) );

  //ヒストグラムの分だけ黒を残して、他を白にする
  //行列の添え字に注意!
  for ( i = 0; i < 255; i++ )
  {
    for ( j = 0; j < (int)(m_mode - uiaHist[i]); j++ )
    {
      (*baaHist)[j*255+i] = true;
    }
  }
}

ヒストグラムから統計量の算出

ヒストグラムが求まっている状態から平均、標準偏差を求めるには以下のようにします。
この例では、ヒストグラム中のnStartLevelnEndLevelまでの平均、標準偏差を求めます。
また、この範囲に入っていない画素の数はnOmitPixelsで与えられているものとします。

void CalcStatics
(
   UINT uiaHist[255],
   int nRow,
   int nCol,
   int nOmitPixels,
   int nStartLevel,
   int nEndLevel, 
   double *dMean,
   double *dStdev
)
{

  *dMean = 0.0;
  for ( i = nStartLevel; i <= nEndLevel; i++ )
  {
    *dMean += i * uiaHist[i-nStartLevel];  //画素値の合計
  }

  //平均
  *dMean /= nRow * nCol - nOmitPixels;

  //標準偏差
  *dStdev = 0.0;
  for ( i = nStartLevel; i <= nEndLevel; i++ )
  {
    //偏差
    dCn = (double)i - *dMean;
    //相対度数
    dFqRel = (double)uiaHist[i-nStartLevel] / ((nRow * nCol) - nOmitPixels);
    //分散
    *dStdev += dCn*dCn * dFqRel; //分散=Σ{偏差^2 × 相対度数}
  }

  //標準偏差
  *dStdev = sqrt( *dStdev );

}

なお、コントラストは上記のnStartlevelnEndLevelを利用して以下のように求めることができます。

  double dCont = ( nEndLEvel - nStartLevel ) / ( nEndLevel + nStartLevel );

参考文献

アーカイブ