2011年7月28日木曜日

OpenCV C++ ヒストグラムクラス

OpenCV2.X向けのヒストグラムクラス。

1Dとカラーのやつは「OpenCV 2 Computer Vision Application Programming Cookbook」に載っているやつ。これを基に、2次元ヒストグラム画像作成など自分なりに手を入れているけれど、まだ中途半端。

#include <opencv2/opencv.hpp>

class Histogram1D {
private:
 int histSize[1];
 float hranges[2];
 const float* ranges[1];
 int channels[1];
public:
 Histogram1D(int hsize = 256) {
  histSize[0] = hsize; //number of bins
  hranges[0] = 0.0;  //min pixel value
  hranges[1] = 255.0;  //max pixel value
  ranges[0] = hranges;
  channels[0] = 0;  //by default, we lookup channel 0
 }

 void setHistSize(int hsize) {
  histSize[0] = hsize;
 }

 void setRanges(float min, float max) {
  hranges[0] = min;
  hranges[1] = max;
  ranges[0] = hranges;
  if(max-min<histSize[0]) {
   histSize[0] = (int)(max-min);
  }
 }

 cv::MatND getHistogram(const cv::Mat &image, int ch = 0) {
  cv::MatND hist;
  channels[0] = ch;
  cv::calcHist(&image, 1, channels, cv::Mat(), hist, 1, histSize, ranges);
  return hist;
 }

 cv::Mat getHistogramImage(const cv::Mat &image, int channel = 0) {
  cv::MatND hist= getHistogram(image, channel);

  double maxVal = 0;
  double minVal = 0;
  cv::minMaxLoc(hist, &minVal, &maxVal, 0, 0);

  cv::Mat histImg(histSize[0], histSize[0], CV_8U, cv::Scalar(255));

  int hpt = static_cast<int>(0.9*histSize[0]);

  for(int h=0; h<histSize[0]; h++) {
   float binVal = hist.at<float>(h);
   int intensity = static_cast<int>(binVal*hpt/maxVal);

   cv::line(histImg, cv::Point(h,histSize[0]), cv::Point(h,histSize[0]-intensity), cv::Scalar::all(0));
  }
  return histImg;
 }
};

class Histogram2D {
private:
 int histSize[2];
 float hranges[2];
 const float* ranges[2];
 int channels[2];
public:
 Histogram2D(int h1size=256, int h2size = 256) {
  histSize[0] = h1size;
  histSize[1] = h2size;
  hranges[0] = 0.0;
  hranges[1] = 255.0;
  ranges[0] = hranges;
  ranges[1] = hranges;
  channels[0] = 0;
  channels[1] = 1;
 }

 cv::MatND getHistogram(const cv::Mat &img1, const cv::Mat &img2) {
  cv::Mat planes[2];
  img1.copyTo(planes[0]);
  img2.copyTo(planes[1]);
  cv::MatND hist;
  cv::calcHist(planes, 2, channels, cv::Mat(), hist, 2, histSize, ranges);
  return hist;
 }

 cv::Mat getHistogramImage(const cv::Mat &img1, const cv::Mat &img2) {
  cv::MatND hist= getHistogram(img1, img2);

  double maxVal = 0;
  double minVal = 0;
  cv::minMaxLoc(hist, &minVal, &maxVal, 0, 0);

  cv::Mat histImg(histSize[0], histSize[1], CV_8U, cv::Scalar(0));

  for(int h=0; h<histSize[0]; h++) {
   for(int i=0; i<histSize[1]; i++) {
    float binVal = hist.at<float>(h,i);
    uchar intensity = static_cast<uchar>(binVal*255/maxVal);
    histImg.at<uchar>(h,i) = intensity;
   }
  }
  return histImg;
 }
};

class ColorHistogram {
private:
 int histSize[3];
 float hranges[2];
 const float* ranges[3];
 int channels[3];
public:
 ColorHistogram(int hSize = 256) {
  histSize[0] = histSize[1] = histSize[2] = hSize;
  hranges[0] = 0.0;
  hranges[1] = 255.0;
  ranges[0] = hranges;
  ranges[1] = hranges;
  ranges[2] = hranges;
  channels[0] = 0;
  channels[1] = 1;
  channels[2] = 2;
 }

 cv::MatND getHistogram(const cv::Mat &image) {
  cv::MatND hist;
  cv::calcHist(&image, 1, channels, cv::Mat(), hist, 3, histSize, ranges);
  return hist;
 }

 cv::SparseMat getSparseHistogram(const cv::Mat &image) {
  cv::SparseMat hist(3, histSize, CV_32F);
  cv::calcHist(&image, 1, channels, cv::Mat(), hist, 3, histSize, ranges);
  return hist;
 }
};

呼び出す側のソース例。
#include <opencv2/opencv.hpp>
#include "histogram.hpp"

#ifdef _DEBUG
#pragma comment(lib,"opencv_core230d.lib") 
#pragma comment(lib,"opencv_highgui230d.lib")
#pragma comment(lib,"opencv_imgproc230d.lib")
#else
#pragma comment(lib,"opencv_core230.lib") 
#pragma comment(lib,"opencv_highgui230d.lib")
#pragma comment(lib,"opencv_imgproc230d.lib")
#endif

using namespace cv;

using std::cout;
using std::endl;

int main()
{
 //モノクロ画像のヒストグラム表示
 Mat gray_img = imread("d:/test1.bmp", 0);
 imshow("gray", gray_img);

 Histogram1D h1(256);
 imshow("Histogram", h1.getHistogramImage(gray_img));

 //カラー画像のチャネル別ヒストグラム画像表示j
 Mat cimg = imread("d:/test2.bmp");
 imshow("color", cimg);

 imshow("B", h1.getHistogramImage(cimg));
 imshow("G", h1.getHistogramImage(cimg, 1));
 imshow("R", h1.getHistogramImage(cimg, 2));

 Mat hsvImg;
 cvtColor(cimg, hsvImg, CV_BGR2HSV_FULL);
 imshow("H", h1.getHistogramImage(hsvImg, 0));
 imshow("S", h1.getHistogramImage(hsvImg, 1));
 imshow("V", h1.getHistogramImage(hsvImg, 2));
 //h1.setRanges(0.0, 180.0);
 //imshow("H", h1.getHistogramImage(hsvImg));

 //2チャンネル2次元ヒストグラム画像表示
 std::vector<cv::Mat> planes;
 cv::split(cimg, planes);
 Histogram2D h2(128,128);
 imshow("2Dhist", h2.getHistogramImage(planes[0], planes[1]));

 //各ヒストグラムを得る。
 MatND hist1 = h1.getHistogram(gray_img);
 MatND hist2 = h2.getHistogram(planes[0], planes[1]);

 //cout << hist2 << endl;
 waitKey();
}

2011年7月15日金曜日

cv::MatのXMLファイルへの入出力

Matの内容をXML形式でファイルに出力 or ファイルから入力する方法のメモ.

2種類のMatを出力するプログラム
#include <opencv2/opencv.hpp>

using namespace cv;

int main()
{
 Mat matA = (cv::Mat_<double>(3,3) << 1, 0, 0, 0, 1, 0, 0, 0, 1);
 Mat matB = cv::Mat::ones(5, 5, CV_8U)*3;

 FileStorage cvfs("D:/test.xml", CV_STORAGE_WRITE);
 write(cvfs,"matA", matA);
 write(cvfs,"matB", matB);
}

出力されたxmlファイルの中身.
<?xml version="1.0"?>
<opencv_storage>
<matA type_id="opencv-matrix">
  <rows>3</rows>
  <cols>3</cols>
  <dt>d</dt>
  <data>
    1. 0. 0. 0. 1. 0. 0. 0. 1.</data></matA>
<matB type_id="opencv-matrix">
  <rows>5</rows>
  <cols>5</cols>
  <dt>u</dt>
  <data>
    3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3</data></matB>
</opencv_storage>

読み込む方のプログラム
int main()
{
    Mat ma, mb;

    FileStorage cvfs("D:/test.xml", CV_STORAGE_READ);
    FileNode node(cvfs.fs, NULL);
    read(node["matB"], mb);
    read(node["matA"], ma);
    std::cout << ma << std::endl;
    std::cout << mb << std::endl;
}

2011年7月14日木曜日

OpenCV2.3向けのVisualStudio2010プロパティシート

VisualStudio2010のプロパティシートで,OpenCV2.3向けの設定.
  • 解凍したwindows用バイナリ(OpenCV-2.3.0-win-superpack.exe)を「C:\OpenCV2.3」に配置
  • プラットフォームが「Win32(x86)」の場合,C:\Users\(ユーザー名)\AppData\Local\Microsoft\MSBuild\v4.0 のMicrosoft.Cpp.Win32.user.props を下記の通り編集.
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
 <PropertyGroup>
  <ExecutablePath>C:\OpenCV2.3\build\bin;C:\OpenCV2.3\build\x86\vc10\bin;$(ExecutablePath)</ExecutablePath>
  <IncludePath>C:\OpenCV2.3\build\include;$(IncludePath)</IncludePath>
  <LibraryPath>C:\OpenCV2.3\build\x86\vc10\lib;$(LibraryPath)</LibraryPath>
 </PropertyGroup>
</Project>
対象プラットフォームがx64の場合には,Microsoft.Cpp.x64.user.propsを編集し,上記x86をx64に置き換えれば良い.

ブログ開設

色々な情報をメモしておいて,共有できるようにブログを使うことにした.

内部公開用のwikiも,そろそろPCが寿命になりそうやし,
メンテナンスしてくれていた学生が卒業して2年以上経ったし.

とりあえず,プログラミング環境の技術メモや,
周辺技術の忘備録として使う予定.