Qstairs

起業に向けた活動、およびAndroid・画像認識(人工知能、Deep Learning等)の技術を紹介します

広告

【画像認識】「Caffe」とUSBカメラで数字認識!実装方法編

f:id:qstairs:20160607230240j:plain:h300

はじめに

前にディープラーニングフレームワーク「Caffe」を使って
USBカメラで数字を認識するデモ動画を紹介しました。

qstairs.hatenablog.com

そこで、今回はその処理のソースを紹介します。

改良

Caffeソリューションに「classification」プロジェクトがあります。
#Caffeの環境構築の方法はコチラ

USBカメラで数字を認識するためには、
「classification」プロジェクトの「classification.cpp」を修正するだけです。

もともと「classification」は引数で与えた画像の識別結果を返す
という処理になります。
そこで、今回は、引数で指定した画像を使うのではなく、
USBカメラで撮影した画像を識別に使うように改良します。

改良内容は、
「classification.cpp」のmain関数を以下のように変えるだけです。
#不要処理を削ればもっとスマートになると思います。手抜きです(^_^;

int main(int argc, char** argv) {
  if (argc != 6) {
    std::cerr << "Usage: " << argv[0]
              << " deploy.prototxt network.caffemodel"
              << " mean.binaryproto labels.txt img.jpg" << std::endl;
    return 1;
  }

  ::google::InitGoogleLogging(argv[0]);

  string model_file   = argv[1];  // 学習処理のモデル
  string trained_file = argv[2];  // 学習モデル
  string mean_file    = argv[3];
  string label_file   = argv[4];
  Classifier classifier(model_file, trained_file, mean_file, label_file);

  string file = argv[5];

  std::cout << "---------- Prediction for "
            << file << " ----------" << std::endl;

  cv::Mat img = cv::imread(file, -1);
  CHECK(!img.empty()) << "Unable to decode image " << file;
  std::vector<Prediction> predictions = classifier.Classify(img);

  /* Print the top N predictions. */
  for (size_t i = 0; i < predictions.size(); ++i) {
    Prediction p = predictions[i];
    std::cout << std::fixed << std::setprecision(4) << p.second << " - \""
              << p.first << "\"" << std::endl;
  }

  //******************************
  //   USBカメラによる識別
  //******************************
  // カメラデバイスをオープンする
  cv::VideoCapture cap(0);

  // カメラデバイスが正常にオープンしたか確認する
  if (!cap.isOpened()) {
    return -1;
  }

  cv::Mat tmp;
  cap >> tmp;

  int size = 100;
  int sx = tmp.cols / 2 - size / 2;
  int sy = tmp.rows / 2 - size / 2;
  cv::Rect targetRect(sx, sy, size, size);
  

  // (1)動画ファイルを書き出すの準備を行う
  cv::VideoWriter writer("videofile.avi", CV_FOURCC_MACRO('X', 'V', 'I', 'D'), 30.0, cv::Size(640, 480), true);

  // (2)動画ファイル書き出しの準備に成功したかチェックする(失敗していればエラー終了する)
  if (!writer.isOpened()){
    return -1;
  }

  bool reverseFlag = true;  // ネガポジ反転
  // 無限ループ
  while (1) {
    cv::Mat frame;
    cap >> frame;

    
    cv::Mat target(frame, targetRect);
    // グレースケールに変換する
    //cv::cvtColor(target, target, CV_RGB2GRAY);
    if (reverseFlag){
      target = ~target;
    }
    
    // 識別処理
    std::vector<Prediction> predictions = classifier.Classify(target);

    // 識別結果表示
    Prediction p = predictions[0];
    std::stringstream ss;
    ss << std::fixed << std::setprecision(4) << p.second << " - \"" << p.first << "\"";
    cv::putText(frame, ss.str(), cv::Point(sx-20, sy-10), 1, 1.5, cv::Scalar(0, 0, 255), 2);

    cv::rectangle(frame, targetRect, cv::Scalar(0, 255, 0), 3);

    // 画像を表示する
    cv::imshow("window", frame);

    // 動画書き込み
    writer << frame;

    // キー入力を取得する
    int key = cv::waitKey(1);
    
    // qを押すと終了する
    if (key == 113) {
      break;
    }else if (key == 115) {
      //sを押すと画像を保存する
      cv::imwrite("img.png", frame);
    }
    else if (key == 114){
      if (reverseFlag){
        reverseFlag = false;
      }
      else{
        reverseFlag = true;
      }
    }
  }

  cv::destroyAllWindows();
}

実行

classification.cppを改良後、ビルドします。
そして、生成された「classification.exe」を使い、
以下のバッチ処理を実行するとUSBカメラが起動し、
映像の中心にある矩形内の数字を識別します。
※ちなみにカレントディレクトリは「caffe-master\Build\x64\Release\bat」です。

SET ROOT_DIR=..\

cd %ROOT_DIR%

classification.exe .\examples\mnist\lenet.prototxt .\examples\mnist\lenet_iter_10000.caffemodel .\binaryproto\meanfile.binaryproto .\examples\mnist\test_leveldb\labels.txt .\testimg\one\one.bmp

pause
広告