cvCalcHistを用いたエントロピーフィルタ

最近OpenCVを始めて、ふとエントロピーフィルタを書いてみようと思い立った。
ここではROIをずらしながらcvCalcHistでヒストグラムを求めるエントロピーフィルタについて書く。

#include <math.h>
#include "cv.h"
#include "highgui.h"

void EntropyFilter(IplImage *src, IplImage* dst, int w_size);

int main(int argc, char *argv[]){
  IplImage *img, *dst;

  img = cvLoadImage(argv[1], CV_LOAD_IMAGE_GRAYSCALE); /* 画像をグレースケールで読み込む */
  dst = cvCreateImage(cvSize(img->width, img->height), IPL_DEPTH_8U, 1);

  EntropyFilter(img, dst, 3); /* エントロピーフィルタ */

  cvSaveImage("result.jpg", dst, 0); /* 結果画像の保存 */

  /* メモリの解放 */
  cvReleaseImage(&img);
  cvReleaseImage(&dst);

  return 0;
}

/*
  エントロピーフィルタ
  引数:
    src: 入力画像
    dst: 出力先
    w_size: ウィンドウサイズ
*/
void EntropyFilter(IplImage *src, IplImage* dst, int w_size){
  int i, j, k, hist_size = 256;
  double e, f, e_max;
  float range[] = { 0, 256 };
  float *ranges[] = { range };
  CvHistogram *hist;

  hist = cvCreateHist(1, &hist_size, CV_HIST_ARRAY, 0, 1); /* ヒストグラムを生成する */

  f = 1.0 / (w_size*w_size);
  e_max = f * log(f) * w_size * w_size; /* エントロピーの最大値 */

  for(i=0; i<src->height; i++){
    for(j=0; j<src->width; j++){
      cvSetImageROI(src, cvRect(j, i, w_size, w_size)); /* ROIをセット */
      cvCalcHist(&src, hist, 0, NULL); /* ヒストグラムを計算する */
      /* エントロピーの計算 */
      e = 0.0;
      for(k=0; k<256; k++){
        if(f = cvQueryHistValue_1D(hist, k)){
          f /= w_size*w_size;
          e += f * log(f);
        }
      }
      dst->imageData[dst->widthStep * i + j] = e/e_max*255; /* 0〜255で正規化して格納 */
    }
  }

  cvResetImageROI(src); /* ROIの解除 */
  cvReleaseHist(&hist); /* ヒストグラムを解放する */

  return;
}

入力画像

結果