🧚
OpenCV: 空のMatのclone/copyToではtypeが不一致
環境
- OpenCV 4.5.3
cv::Mat::clone
以下のような例を考えます。Mat::clone()
の挙動をみています。
入力するMatについては以下のようにします。
- 行数・列数ともに0
- depthが
CV_8U
以外 - channelsが2以上
#include <iostream>
#include <opencv2/opencv.hpp>
int main()
{
cv::Mat src(0, 0, CV_32SC2);
auto dst = src.clone();
std::cout << "src: depth=" << src.depth() << ", channels=" << src.channels() << std::endl
<< "dst: depth=" << dst.depth() << ", channels=" << dst.channels() << std::endl;
return 0;
}
結果は以下のようになり、depthが0 (=CV_8U), channelsが1になってしまいます。
src: depth=4, channels=2
dst: depth=0, channels=1
cv::Mat_<T>::clone
ちなみに、要素型がテンプレートな Mat_<T>
の方だと問題ありません。
cv::Mat_<cv::Vec2i> src(0, 0);
auto dst = src.clone();
std::cout << "src: depth=" << src.depth() << ", channels=" << src.channels() << std::endl
<< "dst: depth=" << dst.depth() << ", channels=" << dst.channels() << std::endl;
src: depth=4, channels=2
dst: depth=4, channels=2
たぶん原因
さて、最初に挙げたテンプレートではない方の挙動を追ってみます。
Mat::clone()
の中身は単に Mat::copyTo()
をしているだけなので、copyToの中を確認します。
Mat::copyTo()
の以下の箇所が多分原因に思われます。
テンプレートな Mat_<T>
の方だと問題ない(ように見える)理由は、要素型からtype, depth, channels等を直接求めているから、ということで説明が付きそうです。
言い換えれば、
Mat_<T>
の中身すなわちflags
のフィールド値はやはり同じ問題を抱えているということになります。
回避策
そもそも空のMatをcloneする必要に迫られることはあまりなさそうですし、空のMatのdepth/channelsが狂ったところで困ることも少なそうですが、例えば以下のような独自clone関数を作る手は考えられます。
void myClone(const cv::Mat &src, cv::Mat &dst)
{
if (src.empty())
{
dst.create(src.size(), src.type());
}
else
{
src.copyTo(dst);
}
}
cv::Mat src(0, 0, CV_32SC2);
cv::Mat dst;
myClone(src, dst);
std::cout << "depth=" << dst.depth() << ", channels=" << dst.channels() << std::endl;
// depth=4, channels=2
Discussion