2012年4月27日金曜日

OpenCV 画像の90度回転

テキストをパースして、複数の画像を1枚にまとめてみる テスト

パース処理にboostのtokenizerを使用

貼り付ける画像が、貼り付け先の画像からはみ出るとエラーになるよ


テキストファイルの例

2                     <-- 貼り付ける画像数
1024 512              <-- 貼り付け先の画像の幅, 高さ
c:/temp/test1.bmp"    <-- 画像の絶対パス
0 0 0 200 200 0       <-- [画像のインデックス] [X座標] [Y座標] [幅] [高さ] [※回転]
c:/temp/test2.bmp"
1 210 0 32 128 1

main.cpp

#include <fstream>
#include <boost/lexical_cast.hpp>
#include <boost/tokenizer.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>

// 貼り付ける画像情報
struct ImageInfo {
  std::string   path;   // ファイルの絶対パス
  int       param[6]; // パラメータ
};

// src_imgをdst_imgのrect領域にコピー
void MatCopyPaste(const cv::Rect& rect, cv::Mat& dst_img, cv::Mat& src_img) {
  cv::Mat d = dst_img(rect);    // 貼り付け先のMatを取得
  src_img.copyTo(d);        // 貼り付け画像をコピーする
}

// 1画像の処理
void ImageProc(cv::Mat& dst_img, const ImageInfo& info) {
  // 貼り付ける画像を読み込む
  cv::Mat src_img = cv::imread(info.path, 1);
  assert(!src_img.empty());

  // 貼り付け先の画像のサイズ
  int imgWidth = info.param[3];
  int imgHeight = info.param[4];
  // 貼り付け位置
  int imgX = info.param[1];
  int imgY = info.param[2];

  // 貼り付け画像
  cv::Mat tmp_img(cv::Size(imgWidth, imgHeight), src_img.type());

  if(info.param[5] == 1) {
    // 画像を回転
    int src_w = src_img.size().width;
    int src_h = src_img.size().height;
    
    cv::Mat rot_img(cv::Size(src_h, src_w), src_img.type(), cv::Scalar(0, 0, 0));
    cv::transpose(src_img, rot_img);  // 転置 左回り 反時計回りに90度回転 
    cv::flip(rot_img, rot_img, 1);    // 左右反転 時計回りに90度回転

    cv::resize(rot_img, tmp_img, tmp_img.size(), cv::INTER_CUBIC);
  } else {
    // サイズ変更
    cv::resize(src_img, tmp_img, tmp_img.size(), cv::INTER_CUBIC);
  }

  // 指定した矩形に画像を貼り付ける
  cv::Rect rect(imgX, imgY, imgWidth, imgHeight); 
  MatCopyPaste(rect, dst_img, tmp_img);
}

int main( int argc, char **argv ) {
  int count = 0;
  std::string str;
  // 貼り付ける画像を記述したテキストファイルを読み込む
  std::ifstream ifs( "./data/ImgList.txt" );

  typedef boost::char_separator char_sep;
  typedef boost::tokenizer tokenizer;
  char_sep sep(" ");    // スペース区切り

  int imgNum, imgWidth, imgHeight;
  std::vector  imgDataArray;
  ImageInfo imgData;

  while(std::getline(ifs, str)) {
    std::vector tokenArray;

    // 読み込んだ文字列をトークンに分割して配列に格納
    tokenizer tok(str, sep);
    for (tokenizer::iterator tok_iter = tok.begin(); tok_iter != tok.end(); ++tok_iter) {
      tokenArray.push_back( *tok_iter );
    }

    switch(count) {
    case 0:  // 画像数
      // int にキャスト
      imgNum = boost::lexical_cast(tokenArray[0]);
      break;
    case 1:  // 画像の幅と高さ
      imgWidth = boost::lexical_cast(tokenArray[0]);
      imgHeight = boost::lexical_cast(tokenArray[1]);
      break;
    default: // 画像のパラメータ
      if(0 == count % 2) {
        // ファイルパス
        imgData.path = tokenArray[0];
      } else {
        // パラメータ
        for(int i = 0; i < 6; i++) {
          imgData.param[i] = boost::lexical_cast(tokenArray[i]);
        }
        imgDataArray.push_back(imgData);
      }
      break;
    }
    count++;
  }

  // 貼り付け先の画像
  cv::Mat dstImg(cv::Size(imgWidth, imgHeight), CV_8UC3, cv::Scalar(0, 0, 0));

  // 画像処理
  for(size_t i = 0; i < imgDataArray.size(); i++) {
    ImageProc(dstImg, imgDataArray[i]);
  }

  // 結果を保存
//  cv::imwrite("./data/result.png", dstImg);

  // 結果を表示
  cv::namedWindow("Result", CV_WINDOW_AUTOSIZE|CV_WINDOW_FREERATIO);
  cv::imshow("Result", dstImg);
  cv::waitKey(0);
  return 0;
}