5 入出力

5.1 画像を表示する

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>

int
main(int argc, char *argv[])
{
  cv::Mat src_img = cv::imread("../../image/lenna.png", 1);
  if(!src_img.data) return -1;

  /// 画像を表示するウィンドウ
  // ウィンドウの名前,プロパティ
  // CV_WINDOW_AUTOSIZE : ウィンドウサイズを画像サイズに合わせる
  // CV_WINDOW_FREERATIO : ウィンドウのアスペクト比を固定しない
  cv::namedWindow("image1", CV_WINDOW_AUTOSIZE|CV_WINDOW_FREERATIO);
  // ウィンドウ名でウィンドウを指定して,そこに画像を描画
  cv::imshow("image1", src_img);
   
  // デフォルトのプロパティで表示
  cv::imshow("image2", src_img);

  // キー入力を(無限に)待つ
  cv::waitKey(0);
}

実行結果:

_images/lenna.png _images/lenna.png

5.2 ファイルから画像を読み込む

#include <iostream>
#include <opencv2/highgui/highgui.hpp>

int
main(int argc, char *argv[])
{
  const std::string base = "../../image/lenna";
  std::vector<std::string> files;
  files.push_back(base + ".bmp"); // Windows bitmaps (bmp, dib)
  files.push_back(base + ".jpg"); // JPEG files (jpg, jpeg, jpe)
  files.push_back(base + ".jp2"); // JPEG 2000 files (jp2)
  files.push_back(base + ".png"); // Portable Network Graphics (png)
  files.push_back(base + ".pbm"); // Portable image format (pbm:raw)
  files.push_back(base + "_ascii" + ".pbm"); // Portable image format (pbm:ascii)
  files.push_back(base + ".pgm"); // Portable image format (pgm:raw)
  files.push_back(base + "_ascii" + ".pgm"); // Portable image format (pgm:ascii)
  files.push_back(base + ".ppm"); // Portable image format (ppm:raw)
  files.push_back(base + "_ascii" + ".ppm"); // Portable image format (ppm:ascii)
  files.push_back(base + ".ras"); // Sun rasters (ras, sr)
  files.push_back(base + ".tiff"); // TIFF files (tiff, tif)

  cv::namedWindow("image1", CV_WINDOW_AUTOSIZE|CV_WINDOW_FREERATIO);
  cv::namedWindow("image2", CV_WINDOW_AUTOSIZE|CV_WINDOW_FREERATIO);
  cv::namedWindow("image3", CV_WINDOW_AUTOSIZE|CV_WINDOW_FREERATIO);

  std::vector<std::string>::iterator it = files.begin();
  for(;it!=files.end(); ++it) {
    std::cout << *it << std::endl;
    // 3チャンネル,カラー画像として読み込む.
    cv::Mat img1 = cv::imread(*it, 1);
    // グレースケール画像として読み込む.
    cv::Mat img2 = cv::imread(*it, 0);
    // 画像をそのまま読み込む.ただし,アルファチャンネルは無視される.
    cv::Mat img3 = cv::imread(*it, -1);

    cv::imshow("image1", img1);
    cv::imshow("image2", img2);
    cv::imshow("image3", img3);

    if(cv::waitKey(0)==27) break;
  }
}

5.3 ファイルに画像を書き出す

1 デフォルトのパラメータで書き出す

#include <iostream>
#include <opencv2/highgui/highgui.hpp>

int
main(int argc, char *argv[])
{
  const std::string base = "./lenna";
  std::vector<std::string> files;
  files.push_back(base + ".bmp"); // Windows bitmaps (bmp, dib)
  files.push_back(base + ".dib"); // 
  files.push_back(base + ".jpg"); // JPEG files (jpg, jpeg, jpe)
  files.push_back(base + ".jp2"); // JPEG 2000 files (jp2)
  files.push_back(base + ".png"); // Portable Network Graphics (png)
  files.push_back(base + ".pbm"); // Portable any format (pnm)
  files.push_back(base + ".pgm"); // 
  files.push_back(base + ".ppm"); // 
  files.push_back(base + ".ras"); // Sun rasters (ras, sr)
  files.push_back(base + ".tiff"); // TIFF files (tiff, tif)

  cv::Mat src_img = cv::imread("../../image/lenna.png", 1);
  if(!src_img.data) return -1; 

  std::vector<std::string>::iterator it = files.begin();
  for(;it!=files.end(); ++it) {
    if(cv::imwrite(*it, src_img))
      std::cout << "imwrite:" << *it << " ... success" << std::endl;
    else
      std::cout << "imwrite:" << *it << " ... failure" << std::endl;
  }
}

実行結果:

imwrite:./lenna.bmp ... success
imwrite:./lenna.dib ... success
imwrite:./lenna.jpg ... success
imwrite:./lenna.jp2 ... success
imwrite:./lenna.png ... success
imwrite:./lenna.pbm ... success
imwrite:./lenna.pgm ... success
imwrite:./lenna.ppm ... success
imwrite:./lenna.ras ... success
imwrite:./lenna.tiff ... success

2 パラメータを指定して書き出す

#include <iostream>
#include <opencv2/highgui/highgui.hpp>

int
main(int argc, char *argv[])
{
  const std::string base = "./lenna";
  std::vector<std::string> files;
  files.push_back(base + "_q30.jpg"); // JPEG files (jpg, jpeg, jpe)
  files.push_back(base + "_l9.png"); // Portable Network Graphics (png)
  files.push_back(base + "_ascii.ppm"); // Portable any format (pnm)

  cv::Mat src_img = cv::imread("../../image/lenna.png", 1);
  if(!src_img.data) return -1; 
  
  std::vector<int> params(2);
  // jpg
  params[0] = CV_IMWRITE_JPEG_QUALITY;
  params[1] = 10;
  cv::imwrite(base+"_q10.jpg", src_img, params);
  // png
  params[0] = CV_IMWRITE_PNG_COMPRESSION;
  params[1] = 9;
  cv::imwrite(base+"_l9.png", src_img, params);
  // pnm
  params[0] = CV_IMWRITE_PXM_BINARY;
  params[1] = 0;
  cv::imwrite(base+"_ascii.ppm", src_img, params);
}

入力画像:

_images/lenna.png

実行結果(jpg, png):

_images/lenna_q10.jpg _images/lenna_l9.png
$ ls lenna*.jpg
-rw-r--r-- 1 user user 100915 2011-04-01 00:00 lenna.jpg
-rw-r--r-- 1 user user   9001 2011-04-01 00:00 lenna_q10.jpg

$ ls lenna*.png
-rw-r--r-- 1 user user 488272 2011-04-01 00:00 lenna.png
-rw-r--r-- 1 user user 447492 2011-04-01 00:00 lenna_l9.png

$ ls lenna*.ppm
-rw-r--r-- 1 user user  737295 2011-04-19 00:00 lenna.ppm
-rw-r--r-- 1 user user 3441135 2011-04-19 00:00 lenna_ascii.ppm

$ head -n 3 lenna.ppm
P6
512 480
255

$ head -n 3 lenna_ascii.ppm
P3
512 480
255

5.4 カメラ画像をキャプチャする

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>

int
main(int argc, char *argv[])
{
  cv::VideoCapture cap(0);
  // 様々な設定...
  cap.set(CV_CAP_PROP_FRAME_WIDTH, 640);
  cap.set(CV_CAP_PROP_FRAME_HEIGHT, 480);
  // カメラがオープンできたかの確認
  if(!cap.isOpened()) return -1;

  cv::namedWindow("Capture", CV_WINDOW_AUTOSIZE|CV_WINDOW_FREERATIO);
  while(1) {
    cv::Mat frame;
    cap >> frame;  // キャプチャ
    // 様々な処理
    // ...
    cv::imshow("Capture", frame); // 表示
    if(cv::waitKey(30) >= 0) 
       {
	  cv::imwrite("cap.png", frame);
       break;
       }
  }
}

5.5 画像をメモリ上でエンコード/デコードする

#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>

int
main(int argc, char *argv[])
{
  cv::Mat img = cv::imread("../../image/lenna.png", 1);
  if(!img.data) return -1; 
  
  std::vector<uchar> buf;
  std::vector<int> params(2);
  int size = img.rows*img.cols;

  // エンコード(jpg)
  params[0] = CV_IMWRITE_JPEG_QUALITY;
  params[1] = 10;
  cv::imencode(".jpg", img, buf, params);
  std::cout << "jpg" << std::endl;
  std::cout << "Original Data Size: " << (img.isContinuous()? (img.elemSize()*size):0) << " [byte]" << std::endl;
  std::cout << "Encoded Image Size: " << buf.size() << " [byte] (quality=" << params[1] << ")" << std::endl << std::endl;
  
  /// エンコード(png)
  // 拡張子,画像,エンコードバッファ,エンコードパラメータ
  params[0] = CV_IMWRITE_PNG_COMPRESSION;
  params[1] = 9;
  cv::imencode(".png", img, buf, params);
  std::cout << "png" << std::endl;
  std::cout << "Original Data Size: " << (img.isContinuous()? (img.elemSize()*size):0) << " [byte]" << std::endl;
  std::cout << "Encoded Image Size: " << buf.size() << " [byte] (level=" << params[1] << ")" << std::endl << std::endl;

  /// エンコード(pnm:ascii)
  params[0] = CV_IMWRITE_PXM_BINARY;
  params[1] = 0;
  cv::imencode(".pnm", img, buf, params);
  std::cout << "pnm:ascii" << std::endl;
  std::cout << "Original Data Size: " << (img.isContinuous()? (img.elemSize()*size):0) << " [byte]" << std::endl;
  std::cout << "Encoded Image Size: " << buf.size() << " [byte] (binary=" << (params[1]?"true":"false") << ")" << std::endl << std::endl;

  /// エンコード(jpg2000)  
  cv::imencode(".jp2", img, buf, params);
  std::cout << "jpeg2000" << std::endl;
  std::cout << "Original Data Size: " << (img.isContinuous()? (img.elemSize()*size):0) << " [byte]" << std::endl;
  std::cout << "Encoded Image Size: " << buf.size() << " [byte]" << std::endl << std::endl;

  // ...
  // ネットワークにデータを流したりとか...

  // ...
  // ネットワークからデータ受け取ったりとか...

  /// デコード(from jpeg200)
  // バッファ,imreadと同じフラグ
  cv::Mat dst_img = cv::imdecode(cv::Mat(buf), 1);
  
  cv::namedWindow("both flip image", CV_WINDOW_AUTOSIZE|CV_WINDOW_FREERATIO);
  cv::imshow("both flip image", dst_img);
  cv::waitKey(0);
}

入力画像:

_images/lenna.png

実行結果:

jpg
Original Data Size: 737280 [byte]
Encoded Image Size: 9001 [byte] (quality=10)

png
Original Data Size: 737280 [byte]
Encoded Image Size: 447492 [byte] (level=9)

pnm:ascii
Original Data Size: 737280 [byte]
Encoded Image Size: 3441135 [byte] (binary=false)

jpeg2000
Original Data Size: 737280 [byte]
Encoded Image Size: 418611 [byte]

5.6 YAML/XMLを読み込む・書き出す

1 YAMLを書き出す

#include <iostream>
#include <opencv2/core/core.hpp>

int
main(int argc, char *argv[])
{
  // 書き込み用にファイルをオープン
  // ファイルの種類は拡張子で決定
  cv::FileStorage fs("test.yml", cv::FileStorage::WRITE);
  
  // 整数,実数,文字列
  fs << "test_int" << 5 << "test_real" << 3.1 << "test_string" << "ABCDEFGH";
  // Mat
  fs << "test_mat" << cv::Mat::eye(3,3,CV_32F);
  // "[" BLOCK SEQUENCE
  fs << "test_sequence" << "[" << CV_PI << "1+1"
      // "{:" FLOW MAP
     << "{:" << "month" << 12 << "day" << 31 << "year" << 1969 << "}" << "]";
  // "{" BLOCK MAP
  fs << "test_map" << "{" << "x" << 1 << "y" << 2 <<
    // "[:" FLOW SEQUENCE
    "width" << 100 << "height" << 200 << "lbp" << "[:";
  const uchar arr[] = {0, 1, 1, 0, 1, 1, 0, 1};
  fs.writeRaw("u", arr, static_cast<int>(sizeof(arr)/sizeof(arr[0])));
  fs << "]" << "}";
}

実行結果:

%YAML:1.0
test_int: 5
test_real: 3.1000000000000001e+00
test_string: ABCDEFGH
test_mat: !!opencv-matrix
   rows: 3
   cols: 3
   dt: f
   data: [ 1., 0., 0., 0., 1., 0., 0., 0., 1. ]
test_sequence:
   - 3.1415926535897931e+00
   - "1+1"
   - { month:12, day:31, year:1969 }
test_map:
   x: 1
   y: 2
   width: 100
   height: 200
   lbp: [ 0, 1, 1, 0, 1, 1, 0, 1 ]

2 YAMLを読み込む

#include <iostream>
#include <opencv2/core/core.hpp>

int
main(int argc, char *argv[])
{
  // ファイルの種類は,内容から決定
  cv::FileStorage fs("test.yml", cv::FileStorage::READ);
  
  // 整数,実数,文字列,Mat
  int i1 = static_cast<int>(fs["test_int"]); 
  double r1 = static_cast<double>(fs["test_real"]);
  std::string str1 = static_cast<std::string>(fs["test_string"]);
  // スカラ以外(ここではMat)を >> で読み込む
  cv::Mat M; 
  fs["test_mat"] >> M;
  std::cout << i1 << ", " << r1 << ", " << str1 << std::endl;
  std::cout << M << std::endl;

  /// Sequence
  cv::FileNode ts = fs["test_sequence"];
  CV_Assert(ts.type() == cv::FileNode::SEQ && ts.size() == 3);
  double ts0 = static_cast<double>(ts[0]);
  std::string ts1 = static_cast<std::string>(ts[1]);
  int month = static_cast<int>(ts[2]["month"]);
  int day = static_cast<int>(ts[2]["day"]);
  int year = static_cast<int>(ts[2]["year"]);
  std::cout << ts0 << std::endl;
  std::cout << ts1 << std::endl;
  std::cout << "{month:" << month << ", day:" << day << ", year:" << year << "}" << std::endl;
  
  /// Map
  cv::FileNode tm = fs["test_map"];
  CV_Assert(tm.type() == cv::FileNode::MAP && tm.size() == 5);
  cv::Rect r; 
  r.x = static_cast<int>(tm["x"]), r.y = static_cast<int>(tm["y"]);
  r.width = static_cast<int>(tm["width"]), r.height = static_cast<int>(tm["height"]);
  int lbp_val = 0;
  cv::FileNodeIterator it = tm["lbp"].begin();
  // リストをイテレータで読み込む
  for(int k = 0; k < 8; k++, ++it)
    lbp_val |= (static_cast<int>(*it)) << k;
  std::cout << "x:" << r.x << std::endl;
  std::cout << "y:" << r.y << std::endl;
  std::cout << "width:" << r.width << std::endl;
  std::cout << "height:" << r.height << std::endl;
  std::cout << "lbp:" << lbp_val << std::endl;
}

実行結果:

5, 3.1, ABCDEFGH
[1, 0, 0;
  0, 1, 0;
  0, 0, 1]
3.14159
1+1
{month:12, day:31, year:1969}
x:1
y:2
width:100
height:200
lbp:182

3 XMLを書き出す

#include <iostream>
#include <opencv2/core/core.hpp>

int
main(int argc, char *argv[])
{
  // 書き込み用にファイルをオープン
  // ファイルの種類は拡張子で決定
  cv::FileStorage fs("test.xml", cv::FileStorage::WRITE);
  
  // 整数,実数,文字列
  fs << "test_int" << 5 << "test_real" << 3.1 << "test_string" << "ABCDEFGH";
  // Mat
  fs << "test_mat" << cv::Mat::eye(3,3,CV_32F);
  // "[" SEQUENCE
  fs << "test_sequence" << "[" << CV_PI << "1+1"
    // "{" MAP
     << "{" << "month" << 12 << "day" << 31 << "year" << 1969 << "}" << "]";
  // "{" MAP
  fs << "test_map" << "{" << "x" << 1 << "y" << 2 <<
    // "[" SEQUENCE
    "width" << 100 << "height" << 200 << "lbp" << "[";
  const uchar arr[] = {0, 1, 1, 0, 1, 1, 0, 1};
  fs.writeRaw("u", arr, static_cast<int>(sizeof(arr)/sizeof(arr[0])));
  fs << "]" << "}";
}

実行結果:

<?xml version="1.0"?>
<opencv_storage>
<test_int>5</test_int>
<test_real>3.1000000000000001e+00</test_real>
<test_string>ABCDEFGH</test_string>
<test_mat type_id="opencv-matrix">
  <rows>3</rows>
  <cols>3</cols>
  <dt>f</dt>
  <data>
    1. 0. 0. 0. 1. 0. 0. 0. 1.</data></test_mat>
<test_sequence>
  3.1415926535897931e+00 "1+1"
  <_>
    <month>12</month>
    <day>31</day>
    <year>1969</year></_></test_sequence>
<test_map>
  <x>1</x>
  <y>2</y>
  <width>100</width>
  <height>200</height>
  <lbp>
    0 1 1 0 1 1 0 1</lbp></test_map>
</opencv_storage>

4 XMLを読み込む

#include <iostream>
#include <opencv2/core/core.hpp>

int
main(int argc, char *argv[])
{
  // ファイルの種類は,内容から決定
  cv::FileStorage fs("test.xml", cv::FileStorage::READ);
  
  // 整数,実数,文字列,Mat
  int i1 = static_cast<int>(fs["test_int"]); 
  double r1 = static_cast<double>(fs["test_real"]);
  std::string str1 = static_cast<std::string>(fs["test_string"]);
  // スカラ以外(ここではMat)を >> で読み込む
  cv::Mat M; 
  fs["test_mat"] >> M;
  std::cout << i1 << ", " << r1 << ", " << str1 << std::endl;
  std::cout << M << std::endl;

  /// Sequence
  cv::FileNode ts = fs["test_sequence"];
  CV_Assert(ts.type() == cv::FileNode::SEQ && ts.size() == 3);
  double ts0 = static_cast<double>(ts[0]);
  std::string ts1 = static_cast<std::string>(ts[1]);
  int month = static_cast<int>(ts[2]["month"]);
  int day = static_cast<int>(ts[2]["day"]);
  int year = static_cast<int>(ts[2]["year"]);
  std::cout << ts0 << std::endl;
  std::cout << ts1 << std::endl;
  std::cout << "{month:" << month << ", day:" << day << ", year:" << year << "}" << std::endl;
  
  /// Map
  cv::FileNode tm = fs["test_map"];
  CV_Assert(tm.type() == cv::FileNode::MAP && tm.size() == 5);
  cv::Rect r; 
  r.x = static_cast<int>(tm["x"]), r.y = static_cast<int>(tm["y"]);
  r.width = static_cast<int>(tm["width"]), r.height = static_cast<int>(tm["height"]);
  int lbp_val = 0;
  cv::FileNodeIterator it = tm["lbp"].begin();
  // リストをイテレータで読み込む
  for(int k = 0; k < 8; k++, ++it)
    lbp_val |= (static_cast<int>(*it)) << k;
  std::cout << "x:" << r.x << std::endl;
  std::cout << "y:" << r.y << std::endl;
  std::cout << "width:" << r.width << std::endl;
  std::cout << "height:" << r.height << std::endl;
  std::cout << "lbp:" << lbp_val << std::endl;
}

実行結果:

5, 3.1, ABCDEFGH
[1, 0, 0;
  0, 1, 0;
  0, 0, 1]
3.14159
1+1
{month:12, day:31, year:1969}
x:1
y:2
width:100
height:200
lbp:182