#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.empty()) 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);
}
実行結果:
サポートフォーマットでも,さまざまなバリエーションを持つものがあります. 画像読み込みは,大半が外部ライブラリ依存ですが,例えばLinux環境では,jp2(stream),ras(RLE),bmp/dib(MS Windows 3.X packed Device-Independent Bitmap)などは読み込むことができません.
#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;
}
}
pbm, pgm, ppm のフォーマットは,いずれの拡張子でも pnm 方式としてまとめられ,カラー画像はカラー画像のまま保存されます.
#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.empty()) 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
#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.empty()) 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);
}
入力画像:
実行結果(jpg, 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
#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;
}
}
}
FOURCCについて書く.
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
int
main(int argc, char *argv[])
{
cv::VideoCapture cap(0);
// 様々な設定...
cv::Size cap_size(640, 480);
cap.set(CV_CAP_PROP_FRAME_WIDTH, cap_size.width);
cap.set(CV_CAP_PROP_FRAME_HEIGHT, cap_size.height);
// カメラがオープンできたかの確認
if(!cap.isOpened()) return -1;
// ビデオライタ
int fps = 15;
cv::VideoWriter writer("capture.avi", CV_FOURCC('X','V','I','D'), fps, cap_size);
cv::namedWindow("Capture", CV_WINDOW_AUTOSIZE|CV_WINDOW_FREERATIO);
cv::Mat frame;
while(1) {
cap >> frame; // キャプチャ
// 様々な処理
// ...
writer << frame;
cv::imshow("Capture", frame);
if(cv::waitKey(30) >= 0) break;
}
}
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
int
main(int argc, char *argv[])
{
cv::VideoCapture cap("capture.avi");
// ファイルがオープンできたかの確認
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) break;
}
}
画像のエンコードで指定できる拡張子やパラメータは, imwrite() で指定できるものと同じです.
#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.empty()) 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);
}
入力画像:
実行結果:
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]
YAMLの場合,シーケンス(名前なしリスト)やマップ(名前付きリスト)に対して,BlockとFlowという2種類のスタイルが存在します. 例えばすべての要素がスカラである場合リストなどは,よりコンパクトなFlowスタイルで保存する方が良いでしょう.
(例)Block スタイルのシーケンス:
- Mark McGwire
- Sammy Sosa
- Ken Griffey
(例)Flow スタイルのシーケンス:
[Mark McGwire, Sammy Sosa, Ken Griffey]
(例)Block スタイルのマップ:
hr: 65
avg: 0.278
rbi: 147
(例)Flow スタイルのマップ:
{hr: 65, avg: 0.278, rbi: 147}
OpenCVのFileStorageに書き込む際は, [ ] がBlockスタイルのシーケンス, [: ] がFlowスタイルのシーケンス, { } がBlockスタイルのマップ, {: } がFlowスタイルのマップ,を意味します.
#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 ]
#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
XMLはYAMLと異なり,各ノードに Block や Flow といった種別はありません.
#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>
#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
OpenCVのhighguiで作成されたウィンドウ上の通常のキーイベントは,waitKey() メソッドで取得できますが,(CTRLやSIFTなどの)修飾キーやマウスのイベントは,コールバック関数を設定して取得します. このコールバック関数を設定するには, setMouseCallback を利用します.
#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#define OPENCV_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
#define OPENCV_VERSION_CODE OPENCV_VERSION(CV_MAJOR_VERSION, CV_MINOR_VERSION, CV_SUBMINOR_VERSION)
#if OPENCV_VERSION_CODE < OPENCV_VERSION(2,3,1)
namespace cv
{
enum {
EVENT_MOUSEMOVE =CV_EVENT_MOUSEMOVE,
EVENT_LBUTTONDOWN =CV_EVENT_LBUTTONDOWN,
EVENT_RBUTTONDOWN =CV_EVENT_RBUTTONDOWN,
EVENT_MBUTTONDOWN =CV_EVENT_MBUTTONDOWN,
EVENT_LBUTTONUP =CV_EVENT_LBUTTONUP,
EVENT_RBUTTONUP =CV_EVENT_RBUTTONUP,
EVENT_MBUTTONUP =CV_EVENT_MBUTTONUP,
EVENT_LBUTTONDBLCLK =CV_EVENT_LBUTTONDBLCLK,
EVENT_RBUTTONDBLCLK =CV_EVENT_RBUTTONDBLCLK,
EVENT_MBUTTONDBLCLK =CV_EVENT_MBUTTONDBLCLK
};
enum {
EVENT_FLAG_LBUTTON =CV_EVENT_FLAG_LBUTTON,
EVENT_FLAG_RBUTTON =CV_EVENT_FLAG_RBUTTON,
EVENT_FLAG_MBUTTON =CV_EVENT_FLAG_MBUTTON,
EVENT_FLAG_CTRLKEY =CV_EVENT_FLAG_CTRLKEY,
EVENT_FLAG_SHIFTKEY =CV_EVENT_FLAG_SHIFTKEY,
EVENT_FLAG_ALTKEY =CV_EVENT_FLAG_ALTKEY
};
}
#endif
void onMouse( int event, int x, int y, int flag, void* )
{
std::string desc;
// マウスイベントを取得
switch(event) {
case cv::EVENT_MOUSEMOVE:
desc += "MOUSE_MOVE";
break;
case cv::EVENT_LBUTTONDOWN:
desc += "LBUTTON_DOWN";
break;
case cv::EVENT_RBUTTONDOWN:
desc += "RBUTTON_DOWN";
break;
case cv::EVENT_MBUTTONDOWN:
desc += "MBUTTON_DOWN";
break;
case cv::EVENT_LBUTTONUP:
desc += "LBUTTON_UP";
break;
case cv::EVENT_RBUTTONUP:
desc += "RBUTTON_UP";
break;
case cv::EVENT_MBUTTONUP:
desc += "MBUTTON_UP";
break;
case cv::EVENT_LBUTTONDBLCLK:
desc += "LBUTTON_DBLCLK";
break;
case cv::EVENT_RBUTTONDBLCLK:
desc += "RBUTTON_DBLCLK";
break;
case cv::EVENT_MBUTTONDBLCLK:
desc += "MBUTTON_DBLCLK";
break;
}
// マウスボタン,及び修飾キーを取得
if(flag & cv::EVENT_FLAG_LBUTTON)
desc += " + LBUTTON";
if(flag & cv::EVENT_FLAG_RBUTTON)
desc += " + RBUTTON";
if(flag & cv::EVENT_FLAG_MBUTTON)
desc += " + MBUTTON";
if(flag & cv::EVENT_FLAG_CTRLKEY)
desc += " + CTRL";
if(flag & cv::EVENT_FLAG_SHIFTKEY)
desc += " + SHIFT";
if(flag & cv::EVENT_FLAG_ALTKEY)
desc += " + ALT";
std::cout << desc << " (" << x << ", " << y << ")" << std::endl;
}
int
main(int argc, char *argv[])
{
// 画像を初期化
cv::Mat black_img = cv::Mat::zeros(cv::Size(800, 500), CV_8UC3);
cv::namedWindow("mouse event demo", 0 );
// マウスイベントに対するコールバック関数を登録
cv::setMouseCallback("mouse event demo", onMouse, 0);
imshow("mouse event demo", black_img);
int key;
while(1) {
key = cv::waitKey(0);
// 'Esc'が押された場合に終了
if(key==27) break;
}
}
実行結果:
MOUVE_MOVE + ALT (5, 58)
MOUVE_MOVE + ALT (8, 55)
MOUVE_MOVE + ALT (10, 55)
LBUTTON_DOWN + ALT (10, 55)
LBUTTON_UP + LBUTTON + ALT (10, 55)
LBUTTON_DOWN + ALT (10, 55)
LBUTTON_UP + LBUTTON + ALT (10, 55)
LBUTTON_DOWN + ALT (10, 55)
LBUTTON_DBLCLK + ALT (10, 55)
LBUTTON_UP + LBUTTON + ALT (10, 55)
また,Windowの作成にQtを利用している場合,右クリックがメニューに割り当てられるために,通常は該当するイベントの取得ができません.
トラックバーをウィンドウに追加し,同時にそれに対するコールバックイベントを設定することで,トラックバーの変化に応じた処理を行うことができます. 以下の例では,トラックバーで 0 - 100 [%] の画像混合比アルファを設定し,2枚の画像をブレンディングします.
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
class AlphaBlend
{
private:
cv::Mat src1, src2, dst;
public:
AlphaBlend():alpha_slider(0),alpha_slider_max(100) {};
int alpha_slider;
const int alpha_slider_max;
bool loadSourceImages(std::string s1, std::string s2);
void onTrackbar_impl(int val);
static void onTrackbar(int val, void* data);
};
/// トラックバーイベント
void AlphaBlend::onTrackbar_impl(int val)
{
double alpha = cv::saturate_cast<double>(val)/alpha_slider_max;
double beta = (1.0 - alpha);
cv::addWeighted(src1, alpha, src2, beta, 0.0, dst);
cv::imshow( "Linear Blend", dst);
}
void AlphaBlend::onTrackbar(int val, void* data)
{
AlphaBlend *ab = reinterpret_cast<AlphaBlend*>(data);
ab->onTrackbar_impl(val);
}
/// 画像読み込み
bool AlphaBlend::loadSourceImages(std::string s1, std::string s2)
{
src1 = cv::imread(s1);
src2 = cv::imread(s2);
if(src1.empty() || src2.empty()) return false;
return true;
}
int main( int argc, char** argv )
{
AlphaBlend ab;
// 画像の読み込み
ab.loadSourceImages("../../image/lenna.png", "../../image/mandrill.png");
// ウィンドウの作成
cv::namedWindow("Linear Blend", 1);
// トラックバーの作成
std::stringstream TrackbarName;
TrackbarName << "alpha x " << ab.alpha_slider_max;
// テキスト,追加するウィンドウ名,値を格納する変数へのポインタ,最大値,コールバック関数,データポインタ
cv::createTrackbar(TrackbarName.str(), "Linear Blend", &ab.alpha_slider, ab.alpha_slider_max, AlphaBlend::onTrackbar, &ab);
// 最初の表示
AlphaBlend::onTrackbar(0, &ab);
cv::waitKey(0);
}
実行結果(20%,50%,80%):