■ TL;DR
- (x,y) デカルト座標系、
cv::Point,cv::Rect,cv::Size全部共通 - [y,x] メモリアクセス、
cv::at -
Mat(cols, rows)が分かりにくいなら、Mat(Size(width, height))でエンバグ回避!
■ はじめに
とても悲しいバグがあったのです...
Animation GIFで、元の背景画像を書き戻すときに何も起きない、というバグでした。こちらはパッチを出していただいたのですが・・・
- restore = Mat(width, height, CV_8UC4, background);
+ restore = Mat(height, width, CV_8UC4, background);
原因は、幅・高さ指定を間違えたために、その後の処理でOpenCVさんが「コピー元とコピー先でサイズが違うん?よっしゃー、じゃ、新しいメモリ用意したるわー」って張り切って、それで悲しい事が起きたのです。
こういう悲劇が二度と繰り返されないように、copyAt()関数が追加されました。
さて、それでは今一度、OpenCV Libraryにおける「XとY」の指定方法をまとめておきます。
■ デカルト座標系を使うとき = OpenCVのクラスで使うなら (x,y)
imgprocmoduleのdrawing functionなどでデカルト座標系を使う時は、代数幾何学と同様に(x,y)の順番になります。
例1)cv::Point
例2)cv::Rect
例3)cv::Size
■ 直接メモリアクセスするときは (y,x)
直接メモリアクセスしたい場合(=デカルト座標系が関わらない場合)は、(y,x)の順番になります
例)cv::Mat::Mat()
例2) cv::Mat::at()
■ cols? rows? 分からなくなっちゃう → Size()でwrapping
とはいえ、colsとかrowsとか言われても、どっちがどっちか分からなくなりますよね!その気持ち痛いほどよく分かります!!でもご安心ください! cv::Size()があります!
例えばの、サンプルコードは以下になります。 cv::Sizeやcv::Pointを使う事で、x,y座標表現になるので、ずいぶん人間にとっては読みやすくなりますね!
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <iostream>
int main(void)
{
// cols/rows表現は馴れないが・・・
cv::Mat srcA(5, 3, CV_8UC1, cv::Scalar(0,0,0));
srcA.at<uchar>(2, 1) = 1;
std::cout << "srcA(5, 3) " << srcA.size() << std::endl;
std::cout << srcA << std::endl;
// Size/Point使って(x,y)表現は分かりやすい!
cv::Mat srcB(cv::Size(3, 5), CV_8UC1, cv::Scalar(0,0,0));
srcB.at<uchar>(cv::Point(1, 2)) = 1;
std::cout << "srcB(Size(3, 5))" << srcB.size() << std::endl;
std::cout << srcB << std::endl;
return 0;
}
kmtr@kmtr-VMware-Virtual-Platform:~/work/temp/a$ ./a.out
srcA(5, 3) [3 x 5]
[ 0, 0, 0;
0, 0, 0;
0, 1, 0;
0, 0, 0;
0, 0, 0]
srcB(Size(3, 5))[3 x 5]
[ 0, 0, 0;
0, 0, 0;
0, 1, 0;
0, 0, 0;
0, 0, 0]
つまり、cv::Point cv::Rect cv::Sizeを使うときは、(x,y)の並びになる、という法則だけ覚えておけば万事解決オールオッケーです!!
この書き方の何がうれしいかというと、Mat::Matするときの引数の順番が、cv::Point(x,y)なんかと表現方法を全く同じにできる点ですね!これなら間違えない!!![]()
■ まとめ
- (x,y) デカルト座標系、
cv::Point,cv::Rect,cv::Size全部共通 - [y,x] メモリアクセス、
cv::at -
Mat(cols, rows)が分かりにくいなら、Mat(Size(width, height))でエンバグ回避!
以上です、ありがとうございました!