mirror of
https://github.com/opencv/opencv.git
synced 2026-07-31 08:13:04 +04:00
Merge branch 4.x
This commit is contained in:
@@ -2544,7 +2544,7 @@ void undistortPoints(InputArray src, OutputArray dst,
|
||||
CV_EXPORTS_W
|
||||
void undistortImagePoints(InputArray src, OutputArray dst, InputArray cameraMatrix,
|
||||
InputArray distCoeffs,
|
||||
TermCriteria = TermCriteria(TermCriteria::MAX_ITER + TermCriteria::EPS, 5, 0.01));
|
||||
TermCriteria = TermCriteria(TermCriteria::MAX_ITER, 5, 0.01));
|
||||
|
||||
namespace fisheye {
|
||||
|
||||
|
||||
@@ -437,8 +437,12 @@ static void undistortPointsInternal( const Mat& _src, Mat& _dst, const Mat& _cam
|
||||
y0 = y = invProj * vecUntilt(1);
|
||||
|
||||
double error = std::numeric_limits<double>::max();
|
||||
double prevError = std::numeric_limits<double>::max();
|
||||
// compensate distortion iteratively using fixed-point iteration
|
||||
|
||||
// parameter for damped fixed-point iteration
|
||||
double alpha = 1.;
|
||||
|
||||
for( int j = 0; ; j++ )
|
||||
{
|
||||
if ((criteria.type & TermCriteria::COUNT) && j >= criteria.maxCount)
|
||||
@@ -462,10 +466,11 @@ static void undistortPointsInternal( const Mat& _src, Mat& _dst, const Mat& _cam
|
||||
// [x'', y'']^T = [x' / icdist + deltaX, y' / icdist + deltaY]^T =>
|
||||
// [x', y']^T = [(x'' - deltaX) * icdist, (y'' - deltaY) * icdist]^T =>
|
||||
// x' = f1(x') := (x'' - deltaX) * icdist, y' = f2(y') := (y'' - deltaY) * icdist
|
||||
// Fixed-point iteration:
|
||||
// new_x' = f1(x') = (x'' - deltaX) * icdist, new_y' = f2(y') = (y'' - deltaY) * icdist
|
||||
x = (x0 - deltaX)*icdist;
|
||||
y = (y0 - deltaY)*icdist;
|
||||
// Damped fixed-point iteration:
|
||||
// f1(x') = (x'' - deltaX) * icdist, f2(y') = (y'' - deltaY) * icdist
|
||||
// new_x' = (1 - alpha) * x' + alpha * f1(x'), new_y' = (1 - alpha) * y' + alpha * f2(y')
|
||||
double new_x = (1. - alpha)*x + alpha*(x0 - deltaX)*icdist;
|
||||
double new_y = (1. - alpha)*y + alpha*(y0 - deltaY)*icdist;
|
||||
|
||||
if(criteria.type & TermCriteria::EPS)
|
||||
{
|
||||
@@ -474,20 +479,20 @@ static void undistortPointsInternal( const Mat& _src, Mat& _dst, const Mat& _cam
|
||||
Vec3d vecTilt;
|
||||
|
||||
// r^2 = x'^2 + y'^2
|
||||
r2 = x*x + y*y;
|
||||
r2 = new_x*new_x + new_y*new_y;
|
||||
r4 = r2*r2;
|
||||
r6 = r4*r2;
|
||||
a1 = 2*x*y;
|
||||
a2 = r2 + 2*x*x;
|
||||
a3 = r2 + 2*y*y;
|
||||
a1 = 2*new_x*new_y;
|
||||
a2 = r2 + 2*new_x*new_x;
|
||||
a3 = r2 + 2*new_y*new_y;
|
||||
// cdist := 1 + k1 * r^2 + k2 * r^4 + k3 * r^6
|
||||
cdist = 1 + k[0]*r2 + k[1]*r4 + k[4]*r6;
|
||||
// icdist2 := 1 / (1 + k4 * r^2 + k5 * r^4 + k6 * r^6)
|
||||
icdist2 = 1./(1 + k[5]*r2 + k[6]*r4 + k[7]*r6);
|
||||
// x'' = x' * cdist * icdist2 + 2 * p1 * x' * y' + p2 * (r^2 + 2 * x'^2) + s1 * r^2 + s2 * r^4
|
||||
// y'' = y' * cdist * icdist2 + p1 * (r^2 + 2 * y'^2) + 2 * p2 * x' * y' + s3 * r^2 + s4 * r^4
|
||||
xd0 = x*cdist*icdist2 + k[2]*a1 + k[3]*a2 + k[8]*r2+k[9]*r4;
|
||||
yd0 = y*cdist*icdist2 + k[2]*a3 + k[3]*a1 + k[10]*r2+k[11]*r4;
|
||||
xd0 = new_x*cdist*icdist2 + k[2]*a1 + k[3]*a2 + k[8]*r2+k[9]*r4;
|
||||
yd0 = new_y*cdist*icdist2 + k[2]*a3 + k[3]*a1 + k[10]*r2+k[11]*r4;
|
||||
|
||||
// s * [x''', y''', 1]^T = matTilt * [x'', y'', 1]^T =>
|
||||
// (vecTilt := matTilt * [x'', y'', 1]^T)
|
||||
@@ -505,6 +510,13 @@ static void undistortPointsInternal( const Mat& _src, Mat& _dst, const Mat& _cam
|
||||
|
||||
error = sqrt( pow(x_proj - u, 2) + pow(y_proj - v, 2) );
|
||||
}
|
||||
if (error > prevError) {
|
||||
alpha *= .5;
|
||||
} else {
|
||||
x = new_x;
|
||||
y = new_y;
|
||||
}
|
||||
prevError = error;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ protected:
|
||||
void generateCameraMatrix(Mat& cameraMatrix);
|
||||
void generateDistCoeffs(Mat& distCoeffs, int count);
|
||||
cv::Mat generateRotationVector();
|
||||
std::vector<cv::Point2d> distortPoints(const cv::Mat &cameraMatrix, const cv::Mat &dist, const std::vector<cv::Point2d> &points);
|
||||
|
||||
double thresh = 1.0e-2;
|
||||
};
|
||||
@@ -60,6 +61,34 @@ cv::Mat UndistortPointsTest::generateRotationVector()
|
||||
return rvec;
|
||||
}
|
||||
|
||||
std::vector<cv::Point2d> UndistortPointsTest::distortPoints(const cv::Mat &cameraMatrix, const cv::Mat &dist, const std::vector<cv::Point2d> &points)
|
||||
{
|
||||
CV_Assert(cameraMatrix.rows == 3 && cameraMatrix.cols == 3);
|
||||
CV_Assert(cameraMatrix.type() == CV_64F);
|
||||
CV_Assert(dist.rows * dist.cols == 12);
|
||||
CV_Assert(dist.type() == CV_64F);
|
||||
double *k = reinterpret_cast<double *>(dist.data);
|
||||
double fx = cameraMatrix.at<double>(0, 0);
|
||||
double fy = cameraMatrix.at<double>(1, 1);
|
||||
double cx = cameraMatrix.at<double>(0, 2);
|
||||
double cy = cameraMatrix.at<double>(1, 2);
|
||||
std::vector<cv::Point2d> distortedPoints;
|
||||
distortedPoints.reserve(points.size());
|
||||
|
||||
for (const cv::Point2d p : points) {
|
||||
double x = (p.x - cx) / fx;
|
||||
double y = (p.y - cy) / fy;
|
||||
double r2 = x*x + y*y;
|
||||
double cdist = (1 + ((k[4]*r2 + k[1])*r2 + k[0])*r2)/(1 + ((k[7]*r2 + k[6])*r2 + k[5])*r2);
|
||||
CV_Assert(cdist >= 0);
|
||||
double deltaX = 2*k[2]*x*y + k[3]*(r2 + 2*x*x)+ k[8]*r2+k[9]*r2*r2;
|
||||
double deltaY = k[2]*(r2 + 2*y*y) + 2*k[3]*x*y+ k[10]*r2+k[11]*r2*r2;
|
||||
distortedPoints.push_back(cv::Point2d((x * cdist + deltaX) * fx + cx, (y * cdist + deltaY) * fy + cy));
|
||||
}
|
||||
|
||||
return distortedPoints;
|
||||
}
|
||||
|
||||
TEST_F(UndistortPointsTest, accuracy)
|
||||
{
|
||||
Mat intrinsics, distCoeffs;
|
||||
@@ -196,4 +225,33 @@ TEST_F(UndistortPointsTest, regression_14583)
|
||||
<< "undistort point: " << undistort_pt;
|
||||
}
|
||||
|
||||
TEST_F(UndistortPointsTest, regression_27916)
|
||||
{
|
||||
cv::Mat K = (cv::Mat_<double>(3, 3) <<
|
||||
1570.8956145992222, 0., 744.87337646727406, 0.,
|
||||
1570.3494207432338, 575.55087456337526, 0., 0., 1.);
|
||||
cv::Mat dist = (cv::Mat_<double>(1, 12) <<
|
||||
-2.8247717583453804, -0.80078070764368037,
|
||||
-0.014595359484103326, 0.0018820998949700702, 1.9827795585249783,
|
||||
-2.7306773773930897, -1.217725820479524, 2.4052243546080136,
|
||||
-0.0020670359760441713, 3.4660880793174063e-05,
|
||||
0.014100351510458799, -3.0935329736207612e-05);
|
||||
|
||||
const cv::TermCriteria termCriteria(TermCriteria::MAX_ITER | TermCriteria::EPS, 100, thresh / 2);
|
||||
std::vector<cv::Point2d> distortedPoints, distortedPoints2;
|
||||
std::vector<cv::Point2d> undistortedPoints;
|
||||
|
||||
for (int i = 0; i < 50; i++)
|
||||
{
|
||||
for (int j = 0; j < 50; j++)
|
||||
{
|
||||
distortedPoints.push_back(cv::Point2d(i, j));
|
||||
}
|
||||
}
|
||||
|
||||
cv::undistortPoints(distortedPoints, undistortedPoints, K, dist, cv::noArray(), K, termCriteria);
|
||||
distortedPoints2 = distortPoints(K, dist, undistortedPoints);
|
||||
EXPECT_MAT_NEAR(distortedPoints2, distortedPoints, thresh);
|
||||
}
|
||||
|
||||
}} // namespace
|
||||
|
||||
@@ -201,7 +201,7 @@ cvRound( double value )
|
||||
{
|
||||
#if defined CV_INLINE_ROUND_DBL
|
||||
CV_INLINE_ROUND_DBL(value);
|
||||
#elif defined _MSC_VER && defined _M_ARM64
|
||||
#elif defined(_MSC_VER) && (defined(_M_ARM64) || defined(_M_ARM64EC))
|
||||
float64x1_t v = vdup_n_f64(value);
|
||||
int64x1_t r = vcvtn_s64_f64(v);
|
||||
return static_cast<int>(vget_lane_s64(r, 0));
|
||||
@@ -327,7 +327,7 @@ CV_INLINE int cvRound(float value)
|
||||
{
|
||||
#if defined CV_INLINE_ROUND_FLT
|
||||
CV_INLINE_ROUND_FLT(value);
|
||||
#elif defined _MSC_VER && defined _M_ARM64
|
||||
#elif defined(_MSC_VER) && (defined(_M_ARM64) || defined(_M_ARM64EC))
|
||||
float32x2_t v = vdup_n_f32(value);
|
||||
int32x2_t r = vcvtn_s32_f32(v);
|
||||
return vget_lane_s32(r, 0);
|
||||
|
||||
@@ -59,6 +59,7 @@ namespace ogl
|
||||
namespace cuda
|
||||
{
|
||||
class CV_EXPORTS GpuMat;
|
||||
class CV_EXPORTS GpuMatND;
|
||||
class CV_EXPORTS HostMem;
|
||||
class CV_EXPORTS Stream;
|
||||
class CV_EXPORTS Event;
|
||||
|
||||
@@ -287,7 +287,8 @@ public:
|
||||
STD_VECTOR_UMAT =11 << KIND_SHIFT,
|
||||
STD_BOOL_VECTOR =12 << KIND_SHIFT,
|
||||
STD_VECTOR_CUDA_GPU_MAT = 13 << KIND_SHIFT,
|
||||
STD_ARRAY_MAT =15 << KIND_SHIFT
|
||||
STD_ARRAY_MAT =15 << KIND_SHIFT,
|
||||
CUDA_GPU_MATND =16 << KIND_SHIFT
|
||||
};
|
||||
|
||||
_InputArray();
|
||||
@@ -306,6 +307,7 @@ public:
|
||||
_InputArray(const double& val);
|
||||
_InputArray(const cuda::GpuMat& d_mat);
|
||||
_InputArray(const std::vector<cuda::GpuMat>& d_mat_array);
|
||||
_InputArray(const cuda::GpuMatND& d_mat);
|
||||
_InputArray(const ogl::Buffer& buf);
|
||||
_InputArray(const cuda::HostMem& cuda_mem);
|
||||
template<typename _Tp> _InputArray(const cudev::GpuMat_<_Tp>& m);
|
||||
@@ -325,6 +327,7 @@ public:
|
||||
void getUMatVector(std::vector<UMat>& umv) const;
|
||||
void getGpuMatVector(std::vector<cuda::GpuMat>& gpumv) const;
|
||||
cuda::GpuMat getGpuMat() const;
|
||||
cuda::GpuMatND getGpuMatND() const;
|
||||
ogl::Buffer getOGlBuffer() const;
|
||||
|
||||
int getFlags() const;
|
||||
@@ -360,6 +363,7 @@ public:
|
||||
bool isVector() const;
|
||||
bool isGpuMat() const;
|
||||
bool isGpuMatVector() const;
|
||||
bool isGpuMatND() const;
|
||||
~_InputArray();
|
||||
|
||||
protected:
|
||||
@@ -428,6 +432,7 @@ public:
|
||||
_OutputArray(std::vector<Mat>& vec);
|
||||
_OutputArray(cuda::GpuMat& d_mat);
|
||||
_OutputArray(std::vector<cuda::GpuMat>& d_mat);
|
||||
_OutputArray(cuda::GpuMatND& d_mat);
|
||||
_OutputArray(ogl::Buffer& buf);
|
||||
_OutputArray(cuda::HostMem& cuda_mem);
|
||||
template<typename _Tp> _OutputArray(cudev::GpuMat_<_Tp>& m);
|
||||
@@ -446,6 +451,7 @@ public:
|
||||
_OutputArray(const std::vector<Mat>& vec);
|
||||
_OutputArray(const cuda::GpuMat& d_mat);
|
||||
_OutputArray(const std::vector<cuda::GpuMat>& d_mat);
|
||||
_OutputArray(const cuda::GpuMatND& d_mat);
|
||||
_OutputArray(const ogl::Buffer& buf);
|
||||
_OutputArray(const cuda::HostMem& cuda_mem);
|
||||
template<typename _Tp> _OutputArray(const cudev::GpuMat_<_Tp>& m);
|
||||
@@ -476,6 +482,7 @@ public:
|
||||
std::vector<Mat>& getMatVecRef() const;
|
||||
std::vector<UMat>& getUMatVecRef() const;
|
||||
template<typename _Tp> std::vector<std::vector<_Tp> >& getVecVecRef() const;
|
||||
cuda::GpuMatND& getGpuMatNDRef() const;
|
||||
ogl::Buffer& getOGlBufferRef() const;
|
||||
cuda::HostMem& getHostMemRef() const;
|
||||
|
||||
@@ -516,6 +523,7 @@ public:
|
||||
_InputOutputArray(Mat& m);
|
||||
_InputOutputArray(std::vector<Mat>& vec);
|
||||
_InputOutputArray(cuda::GpuMat& d_mat);
|
||||
_InputOutputArray(cuda::GpuMatND& d_mat);
|
||||
_InputOutputArray(ogl::Buffer& buf);
|
||||
_InputOutputArray(cuda::HostMem& cuda_mem);
|
||||
template<typename _Tp> _InputOutputArray(cudev::GpuMat_<_Tp>& m);
|
||||
@@ -533,6 +541,7 @@ public:
|
||||
_InputOutputArray(const std::vector<Mat>& vec);
|
||||
_InputOutputArray(const cuda::GpuMat& d_mat);
|
||||
_InputOutputArray(const std::vector<cuda::GpuMat>& d_mat);
|
||||
_InputOutputArray(const cuda::GpuMatND& d_mat);
|
||||
_InputOutputArray(const ogl::Buffer& buf);
|
||||
_InputOutputArray(const cuda::HostMem& cuda_mem);
|
||||
template<typename _Tp> _InputOutputArray(const cudev::GpuMat_<_Tp>& m);
|
||||
|
||||
@@ -214,7 +214,10 @@ inline _InputArray::_InputArray(const cuda::GpuMat& d_mat)
|
||||
{ init(+CUDA_GPU_MAT + ACCESS_READ, &d_mat); }
|
||||
|
||||
inline _InputArray::_InputArray(const std::vector<cuda::GpuMat>& d_mat)
|
||||
{ init(+STD_VECTOR_CUDA_GPU_MAT + ACCESS_READ, &d_mat);}
|
||||
{ init(+STD_VECTOR_CUDA_GPU_MAT + ACCESS_READ, &d_mat);}
|
||||
|
||||
inline _InputArray::_InputArray(const cuda::GpuMatND& d_mat)
|
||||
{ init(+CUDA_GPU_MATND + ACCESS_READ, &d_mat); }
|
||||
|
||||
inline _InputArray::_InputArray(const ogl::Buffer& buf)
|
||||
{ init(+OPENGL_BUFFER + ACCESS_READ, &buf); }
|
||||
@@ -261,6 +264,7 @@ inline bool _InputArray::isVector() const { return kind() == _InputArray::STD_VE
|
||||
(kind() == _InputArray::MATX && (sz.width <= 1 || sz.height <= 1)); }
|
||||
inline bool _InputArray::isGpuMat() const { return kind() == _InputArray::CUDA_GPU_MAT; }
|
||||
inline bool _InputArray::isGpuMatVector() const { return kind() == _InputArray::STD_VECTOR_CUDA_GPU_MAT; }
|
||||
inline bool _InputArray::isGpuMatND() const { return kind() == _InputArray::CUDA_GPU_MATND; }
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -339,7 +343,10 @@ inline _OutputArray::_OutputArray(cuda::GpuMat& d_mat)
|
||||
{ init(+CUDA_GPU_MAT + ACCESS_WRITE, &d_mat); }
|
||||
|
||||
inline _OutputArray::_OutputArray(std::vector<cuda::GpuMat>& d_mat)
|
||||
{ init(+STD_VECTOR_CUDA_GPU_MAT + ACCESS_WRITE, &d_mat);}
|
||||
{ init(+STD_VECTOR_CUDA_GPU_MAT + ACCESS_WRITE, &d_mat);}
|
||||
|
||||
inline _OutputArray::_OutputArray(cuda::GpuMatND& d_mat)
|
||||
{ init(+CUDA_GPU_MATND + ACCESS_WRITE, &d_mat); }
|
||||
|
||||
inline _OutputArray::_OutputArray(ogl::Buffer& buf)
|
||||
{ init(+OPENGL_BUFFER + ACCESS_WRITE, &buf); }
|
||||
@@ -362,6 +369,8 @@ inline _OutputArray::_OutputArray(const std::vector<UMat>& vec)
|
||||
inline _OutputArray::_OutputArray(const cuda::GpuMat& d_mat)
|
||||
{ init(FIXED_TYPE + FIXED_SIZE + CUDA_GPU_MAT + ACCESS_WRITE, &d_mat); }
|
||||
|
||||
inline _OutputArray::_OutputArray(const cuda::GpuMatND& d_mat)
|
||||
{ init(+FIXED_TYPE + FIXED_SIZE + CUDA_GPU_MATND + ACCESS_WRITE, &d_mat); }
|
||||
|
||||
inline _OutputArray::_OutputArray(const ogl::Buffer& buf)
|
||||
{ init(FIXED_TYPE + FIXED_SIZE + OPENGL_BUFFER + ACCESS_WRITE, &buf); }
|
||||
@@ -486,6 +495,9 @@ _InputOutputArray::_InputOutputArray(const _Tp* vec, int n)
|
||||
inline _InputOutputArray::_InputOutputArray(cuda::GpuMat& d_mat)
|
||||
{ init(+CUDA_GPU_MAT + ACCESS_RW, &d_mat); }
|
||||
|
||||
inline _InputOutputArray::_InputOutputArray(cuda::GpuMatND& d_mat)
|
||||
{ init(+CUDA_GPU_MATND + ACCESS_RW, &d_mat); }
|
||||
|
||||
inline _InputOutputArray::_InputOutputArray(ogl::Buffer& buf)
|
||||
{ init(+OPENGL_BUFFER + ACCESS_RW, &buf); }
|
||||
|
||||
@@ -513,6 +525,9 @@ inline _InputOutputArray::_InputOutputArray(const std::vector<cuda::GpuMat>& d_m
|
||||
template<> inline _InputOutputArray::_InputOutputArray(std::vector<cuda::GpuMat>& d_mat)
|
||||
{ init(FIXED_TYPE + FIXED_SIZE + STD_VECTOR_CUDA_GPU_MAT + ACCESS_RW, &d_mat);}
|
||||
|
||||
inline _InputOutputArray::_InputOutputArray(const cuda::GpuMatND& d_mat)
|
||||
{ init(+FIXED_TYPE + FIXED_SIZE + CUDA_GPU_MATND + ACCESS_RW, &d_mat); }
|
||||
|
||||
inline _InputOutputArray::_InputOutputArray(const ogl::Buffer& buf)
|
||||
{ init(FIXED_TYPE + FIXED_SIZE + OPENGL_BUFFER + ACCESS_RW, &buf); }
|
||||
|
||||
|
||||
@@ -113,6 +113,12 @@ Mat _InputArray::getMat_(int i) const
|
||||
CV_Error(cv::Error::StsNotImplemented, "You should explicitly call download method for cuda::GpuMat object");
|
||||
}
|
||||
|
||||
if( k == CUDA_GPU_MATND )
|
||||
{
|
||||
CV_Assert( i < 0 );
|
||||
CV_Error(cv::Error::StsNotImplemented, "You should explicitly call download method for cuda::GpuMatND object");
|
||||
}
|
||||
|
||||
if( k == CUDA_HOST_MEM )
|
||||
{
|
||||
CV_Assert( i < 0 );
|
||||
@@ -360,6 +366,22 @@ void _InputArray::getGpuMatVector(std::vector<cuda::GpuMat>& gpumv) const
|
||||
CV_Error(Error::StsNotImplemented, "CUDA support is not enabled in this OpenCV build (missing HAVE_CUDA)");
|
||||
#endif
|
||||
}
|
||||
cuda::GpuMatND _InputArray::getGpuMatND() const
|
||||
{
|
||||
#ifdef HAVE_CUDA
|
||||
_InputArray::KindFlag k = kind();
|
||||
|
||||
if (k == CUDA_GPU_MATND)
|
||||
{
|
||||
const cuda::GpuMatND* d_mat = (const cuda::GpuMatND*)obj;
|
||||
return *d_mat;
|
||||
}
|
||||
|
||||
CV_Error(cv::Error::StsNotImplemented, "getGpuMatND is available only for cuda::GpuMatND");
|
||||
#else
|
||||
CV_Error(Error::StsNotImplemented, "CUDA support is not enabled in this OpenCV build (missing HAVE_CUDA)");
|
||||
#endif
|
||||
}
|
||||
ogl::Buffer _InputArray::getOGlBuffer() const
|
||||
{
|
||||
_InputArray::KindFlag k = kind();
|
||||
@@ -382,11 +404,29 @@ _InputArray::KindFlag _InputArray::kind() const
|
||||
|
||||
int _InputArray::rows(int i) const
|
||||
{
|
||||
#ifdef HAVE_CUDA
|
||||
_InputArray::KindFlag k = kind();
|
||||
if (k == CUDA_GPU_MATND)
|
||||
{
|
||||
const cuda::GpuMatND& _gpuMatND = *(const cuda::GpuMatND*)obj;
|
||||
return (_gpuMatND.dims < 1) ? 0 : _gpuMatND.size[0];
|
||||
}
|
||||
#endif
|
||||
|
||||
return size(i).height;
|
||||
}
|
||||
|
||||
int _InputArray::cols(int i) const
|
||||
{
|
||||
#ifdef HAVE_CUDA
|
||||
_InputArray::KindFlag k = kind();
|
||||
if (k == CUDA_GPU_MATND)
|
||||
{
|
||||
const cuda::GpuMatND& _gpuMatND = *(const cuda::GpuMatND*)obj;
|
||||
return (_gpuMatND.dims < 2) ? 0 : _gpuMatND.size[1];
|
||||
}
|
||||
#endif
|
||||
|
||||
return size(i).width;
|
||||
}
|
||||
|
||||
@@ -655,8 +695,13 @@ bool _InputArray::sameSize(const _InputArray& arr) const
|
||||
return false;
|
||||
sz1 = m->size();
|
||||
}
|
||||
else if ( (k1 == CUDA_GPU_MATND) && (k2 == CUDA_GPU_MATND))
|
||||
{
|
||||
return ((const cuda::GpuMatND*)obj)->size == ((const cuda::GpuMatND*)arr.obj)->size;
|
||||
}
|
||||
else
|
||||
sz1 = size();
|
||||
|
||||
if( arr.dims() > 2 )
|
||||
return false;
|
||||
return sz1 == arr.size();
|
||||
@@ -744,6 +789,12 @@ int _InputArray::dims(int i) const
|
||||
return 2;
|
||||
}
|
||||
|
||||
if( k == CUDA_GPU_MATND )
|
||||
{
|
||||
CV_Assert( i < 0 );
|
||||
return ((const cuda::GpuMatND*)obj)->dims;
|
||||
}
|
||||
|
||||
if( k == CUDA_HOST_MEM )
|
||||
{
|
||||
CV_Assert( i < 0 );
|
||||
@@ -799,6 +850,21 @@ size_t _InputArray::total(int i) const
|
||||
return vv[i].total();
|
||||
}
|
||||
|
||||
if( k == CUDA_GPU_MATND )
|
||||
{
|
||||
CV_Assert( i < 0 );
|
||||
size_t res = 0;
|
||||
const cuda::GpuMatND& _gpuMatND = *((const cuda::GpuMatND*)obj);
|
||||
if (_gpuMatND.dims > 0)
|
||||
{
|
||||
res = 1;
|
||||
for(int d = 0 ; d<_gpuMatND.dims ; ++d)
|
||||
res *= _gpuMatND.size[d];
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return size(i).area();
|
||||
}
|
||||
|
||||
@@ -876,6 +942,9 @@ int _InputArray::type(int i) const
|
||||
if( k == CUDA_GPU_MAT )
|
||||
return ((const cuda::GpuMat*)obj)->type();
|
||||
|
||||
if( k == CUDA_GPU_MATND )
|
||||
return ((const cuda::GpuMatND*)obj)->type();
|
||||
|
||||
if( k == CUDA_HOST_MEM )
|
||||
return ((const cuda::HostMem*)obj)->type();
|
||||
|
||||
@@ -955,6 +1024,9 @@ bool _InputArray::empty() const
|
||||
return vv.empty();
|
||||
}
|
||||
|
||||
if( k == CUDA_GPU_MATND )
|
||||
return ((const cuda::GpuMatND*)obj)->empty();
|
||||
|
||||
if( k == CUDA_HOST_MEM )
|
||||
return ((const cuda::HostMem*)obj)->empty();
|
||||
|
||||
@@ -999,6 +1071,9 @@ bool _InputArray::isContinuous(int i) const
|
||||
if( k == CUDA_GPU_MAT )
|
||||
return i < 0 ? ((const cuda::GpuMat*)obj)->isContinuous() : true;
|
||||
|
||||
if( k == CUDA_GPU_MATND )
|
||||
return i < 0 ? ((const cuda::GpuMatND*)obj)->isContinuous() : true;
|
||||
|
||||
CV_Error(cv::Error::StsNotImplemented, "Unknown/unsupported array type");
|
||||
}
|
||||
|
||||
@@ -1037,6 +1112,11 @@ bool _InputArray::isSubmatrix(int i) const
|
||||
return vv[i].isSubmatrix();
|
||||
}
|
||||
|
||||
if( k == CUDA_GPU_MATND )
|
||||
{
|
||||
return ((const cuda::GpuMatND*)obj)->isSubmatrix();
|
||||
}
|
||||
|
||||
CV_Error(cv::Error::StsNotImplemented, "");
|
||||
}
|
||||
|
||||
@@ -1152,6 +1232,12 @@ size_t _InputArray::step(int i) const
|
||||
CV_Assert(i >= 0 && (size_t)i < vv.size());
|
||||
return vv[i].step;
|
||||
}
|
||||
if( k == CUDA_GPU_MATND )
|
||||
{
|
||||
const cuda::GpuMatND& _gpuMatND = *(const cuda::GpuMatND*)obj;
|
||||
CV_Assert( i >= _gpuMatND.dims );
|
||||
return _gpuMatND.step[i];
|
||||
}
|
||||
|
||||
CV_Error(Error::StsNotImplemented, "");
|
||||
}
|
||||
@@ -1234,6 +1320,18 @@ void _OutputArray::create(Size _sz, int mtype, int i, bool allowTransposed, _Out
|
||||
return;
|
||||
#else
|
||||
CV_Error(Error::StsNotImplemented, "CUDA support is not enabled in this OpenCV build (missing HAVE_CUDA)");
|
||||
#endif
|
||||
}
|
||||
if( k == CUDA_GPU_MATND && i < 0 && !allowTransposed && fixedDepthMask == 0 )
|
||||
{
|
||||
CV_Assert(!fixedSize() || ((((cuda::GpuMatND*)obj)->dims == 2) && (((cuda::GpuMatND*)obj)->size[0] == _sz.height) && (((cuda::GpuMatND*)obj)->size[1] == _sz.width)));
|
||||
CV_Assert(!fixedType() || ((cuda::GpuMatND*)obj)->type() == mtype);
|
||||
#ifdef HAVE_CUDA
|
||||
cuda::GpuMatND::SizeArray sizes = {_sz.height, _sz.width};
|
||||
((cuda::GpuMatND*)obj)->create(sizes, mtype);
|
||||
return;
|
||||
#else
|
||||
CV_Error(Error::StsNotImplemented, "CUDA support is not enabled in this OpenCV build (missing HAVE_CUDA)");
|
||||
#endif
|
||||
}
|
||||
if( k == OPENGL_BUFFER && i < 0 && !allowTransposed && fixedDepthMask == 0 )
|
||||
@@ -1288,6 +1386,18 @@ void _OutputArray::create(int _rows, int _cols, int mtype, int i, bool allowTran
|
||||
return;
|
||||
#else
|
||||
CV_Error(Error::StsNotImplemented, "CUDA support is not enabled in this OpenCV build (missing HAVE_CUDA)");
|
||||
#endif
|
||||
}
|
||||
if( k == CUDA_GPU_MATND && i < 0 && !allowTransposed && fixedDepthMask == 0 )
|
||||
{
|
||||
CV_Assert(!fixedSize() || ((((cuda::GpuMatND*)obj)->dims == 2) && (((cuda::GpuMatND*)obj)->size[0] == _rows) && (((cuda::GpuMatND*)obj)->size[1] == _cols)));
|
||||
CV_Assert(!fixedType() || ((cuda::GpuMatND*)obj)->type() == mtype);
|
||||
#ifdef HAVE_CUDA
|
||||
cuda::GpuMatND::SizeArray sizes = {_rows, _cols};
|
||||
((cuda::GpuMatND*)obj)->create(sizes, mtype);
|
||||
return;
|
||||
#else
|
||||
CV_Error(Error::StsNotImplemented, "CUDA support is not enabled in this OpenCV build (missing HAVE_CUDA)");
|
||||
#endif
|
||||
}
|
||||
if( k == OPENGL_BUFFER && i < 0 && !allowTransposed && fixedDepthMask == 0 )
|
||||
@@ -1705,6 +1815,18 @@ void _OutputArray::create(int d, const int* sizes, int mtype, int i,
|
||||
return;
|
||||
}
|
||||
|
||||
if( k == CUDA_GPU_MATND && d > 0 && i < 0 && !allowTransposed && fixedDepthMask == 0 )
|
||||
{
|
||||
#ifdef HAVE_CUDA
|
||||
cuda::GpuMatND::SizeArray sizeArray = cuda::GpuMatND::SizeArray(sizes, sizes+d);
|
||||
((cuda::GpuMatND*)obj)->create(sizeArray, mtype);
|
||||
return;
|
||||
#else
|
||||
CV_Error(Error::StsNotImplemented, "CUDA support is not enabled in this OpenCV build (missing HAVE_CUDA)");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
CV_Error(Error::StsNotImplemented, "Unknown/unsupported array type");
|
||||
}
|
||||
|
||||
@@ -1840,6 +1962,16 @@ void _OutputArray::release() const
|
||||
#endif
|
||||
}
|
||||
|
||||
if( k == CUDA_GPU_MATND )
|
||||
{
|
||||
#ifdef HAVE_CUDA
|
||||
((cuda::GpuMatND*)obj)->release();
|
||||
return;
|
||||
#else
|
||||
CV_Error(Error::StsNotImplemented, "CUDA support is not enabled in this OpenCV build (missing HAVE_CUDA)");
|
||||
#endif
|
||||
}
|
||||
|
||||
if( k == CUDA_HOST_MEM )
|
||||
{
|
||||
#ifdef HAVE_CUDA
|
||||
@@ -1971,6 +2103,12 @@ std::vector<cuda::GpuMat>& _OutputArray::getGpuMatVecRef() const
|
||||
CV_Assert(k == STD_VECTOR_CUDA_GPU_MAT);
|
||||
return *(std::vector<cuda::GpuMat>*)obj;
|
||||
}
|
||||
cuda::GpuMatND& _OutputArray::getGpuMatNDRef() const
|
||||
{
|
||||
_InputArray::KindFlag k = kind();
|
||||
CV_Assert( k == CUDA_GPU_MATND );
|
||||
return *(cuda::GpuMatND*)obj;
|
||||
}
|
||||
|
||||
ogl::Buffer& _OutputArray::getOGlBufferRef() const
|
||||
{
|
||||
|
||||
@@ -1164,20 +1164,31 @@ String tempfile( const char* suffix )
|
||||
fname = String(aname);
|
||||
}
|
||||
#else
|
||||
// Use GUID-based naming to avoid race condition with GetTempFileNameA
|
||||
// See issue #19648
|
||||
char temp_dir2[MAX_PATH] = { 0 };
|
||||
char temp_file[MAX_PATH] = { 0 };
|
||||
|
||||
if (temp_dir.empty())
|
||||
{
|
||||
::GetTempPathA(sizeof(temp_dir2), temp_dir2);
|
||||
temp_dir = std::string(temp_dir2);
|
||||
}
|
||||
if(0 == ::GetTempFileNameA(temp_dir.c_str(), "ocv", 0, temp_file))
|
||||
|
||||
GUID g;
|
||||
HRESULT hr = CoCreateGuid(&g);
|
||||
if (FAILED(hr))
|
||||
return String();
|
||||
char guidStr[40];
|
||||
const char* mask = "%08x_%04x_%04x_%02x%02x_%02x%02x%02x%02x%02x%02x";
|
||||
snprintf(guidStr, sizeof(guidStr), mask,
|
||||
g.Data1, g.Data2, g.Data3, (unsigned int)g.Data4[0], (unsigned int)g.Data4[1],
|
||||
(unsigned int)g.Data4[2], (unsigned int)g.Data4[3], (unsigned int)g.Data4[4],
|
||||
(unsigned int)g.Data4[5], (unsigned int)g.Data4[6], (unsigned int)g.Data4[7]);
|
||||
|
||||
DeleteFileA(temp_file);
|
||||
|
||||
fname = temp_file;
|
||||
fname = temp_dir;
|
||||
if (!fname.empty() && fname[fname.size()-1] != '\\' && fname[fname.size()-1] != '/')
|
||||
fname += "\\";
|
||||
fname = fname + "ocv" + guidStr;
|
||||
#endif
|
||||
# else
|
||||
# ifdef __ANDROID__
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
|
||||
// Ensure the included flatbuffers.h is the same version as when this file was
|
||||
// generated, otherwise it may not be compatible.
|
||||
static_assert(FLATBUFFERS_VERSION_MAJOR == 23 &&
|
||||
FLATBUFFERS_VERSION_MINOR == 5 &&
|
||||
FLATBUFFERS_VERSION_REVISION == 9,
|
||||
static_assert(FLATBUFFERS_VERSION_MAJOR == 25 &&
|
||||
FLATBUFFERS_VERSION_MINOR == 9 &&
|
||||
FLATBUFFERS_VERSION_REVISION == 23,
|
||||
"Non-compatible flatbuffers version included");
|
||||
|
||||
namespace opencv_tflite {
|
||||
|
||||
@@ -1666,6 +1666,10 @@ CvWindow::CvWindow(QString name, int arg2)
|
||||
show();
|
||||
}
|
||||
|
||||
CvWindow::~CvWindow()
|
||||
{
|
||||
delete myView;
|
||||
}
|
||||
|
||||
void CvWindow::setMouseCallBack(CvMouseCallback callback, void* param)
|
||||
{
|
||||
|
||||
@@ -298,6 +298,7 @@ class CvWindow : public CvWinModel
|
||||
Q_OBJECT
|
||||
public:
|
||||
CvWindow(QString arg2, int flag = cv::WINDOW_NORMAL);
|
||||
~CvWindow();
|
||||
|
||||
void setMouseCallBack(CvMouseCallback m, void* param);
|
||||
|
||||
|
||||
@@ -113,7 +113,7 @@ enum ImwriteFlags {
|
||||
IMWRITE_TIFF_PREDICTOR = 317,//!< For TIFF, use to specify predictor. See cv::ImwriteTiffPredictorFlags. Default is IMWRITE_TIFF_PREDICTOR_HORIZONTAL .
|
||||
IMWRITE_JPEG2000_COMPRESSION_X1000 = 272,//!< For JPEG2000, use to specify the target compression rate (multiplied by 1000). The value can be from 0 to 1000. Default is 1000.
|
||||
IMWRITE_AVIF_QUALITY = 512,//!< For AVIF, it can be a quality between 0 and 100 (the higher the better). Default is 95.
|
||||
IMWRITE_AVIF_DEPTH = 513,//!< For AVIF, it can be 8, 10 or 12. If >8, it is stored/read as CV_32F. Default is 8.
|
||||
IMWRITE_AVIF_DEPTH = 513,//!< For AVIF, it can be 8, 10 or 12. If >8, it is stored/read as CV_16U. Default is 8.
|
||||
IMWRITE_AVIF_SPEED = 514,//!< For AVIF, it is between 0 (slowest) and 10(fastest). Default is 9.
|
||||
IMWRITE_JPEGXL_QUALITY = 640,//!< For JPEG XL, it can be a quality from 0 to 100 (the higher is the better). Default value is 95. If set, distance parameter is re-calicurated from quality level automatically. This parameter request libjxl v0.10 or later.
|
||||
IMWRITE_JPEGXL_EFFORT = 641,//!< For JPEG XL, encoder effort/speed level without affecting decoding speed; it is between 1 (fastest) and 10 (slowest). Default is 7.
|
||||
@@ -539,6 +539,11 @@ can be saved using this function, with these exceptions:
|
||||
To achieve this, create an 8-bit 4-channel (CV_8UC4) BGRA image, ensuring the alpha channel is the last component.
|
||||
Fully transparent pixels should have an alpha value of 0, while fully opaque pixels should have an alpha value of 255.
|
||||
- 8-bit single-channel images (CV_8UC1) are not supported due to GIF's limitation to indexed color formats.
|
||||
- With AVIF encoder, 8-bit unsigned (CV_8U) and 16-bit unsigned (CV_16U) images can be saved.
|
||||
- CV_16U images can be saved as only 10-bit or 12-bit (not 16-bit). See IMWRITE_AVIF_DEPTH.
|
||||
- AVIF images with an alpha channel can be saved using this function.
|
||||
To achieve this, create an 8-bit 4-channel (CV_8UC4) / 16-bit 4-channel (CV_16UC4) BGRA image, ensuring the alpha channel is the last component.
|
||||
Fully transparent pixels should have an alpha value of 0, while fully opaque pixels should have an alpha value of 255 (8-bit) / 1023 (10-bit) / 4095 (12-bit) (see the code sample below).
|
||||
|
||||
If the image format is not supported, the image will be converted to 8-bit unsigned (CV_8U) and saved that way.
|
||||
|
||||
|
||||
@@ -86,15 +86,12 @@ AvifImageUniquePtr ConvertToAvif(const cv::Mat &img, bool lossless, int bit_dept
|
||||
result->yuvFormat = AVIF_PIXEL_FORMAT_YUV400;
|
||||
result->colorPrimaries = AVIF_COLOR_PRIMARIES_UNSPECIFIED;
|
||||
result->transferCharacteristics = AVIF_TRANSFER_CHARACTERISTICS_UNSPECIFIED;
|
||||
result->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_IDENTITY;
|
||||
result->matrixCoefficients = AVIF_MATRIX_COEFFICIENTS_UNSPECIFIED;
|
||||
result->yuvRange = AVIF_RANGE_FULL;
|
||||
result->yuvPlanes[0] = img.data;
|
||||
result->yuvRowBytes[0] = img.step[0];
|
||||
result->imageOwnsYUVPlanes = AVIF_FALSE;
|
||||
return AvifImageUniquePtr(result);
|
||||
}
|
||||
|
||||
if (lossless) {
|
||||
} else if (lossless) {
|
||||
result =
|
||||
avifImageCreate(width, height, bit_depth, AVIF_PIXEL_FORMAT_YUV444);
|
||||
if (result == nullptr) return nullptr;
|
||||
@@ -139,22 +136,24 @@ AvifImageUniquePtr ConvertToAvif(const cv::Mat &img, bool lossless, int bit_dept
|
||||
#endif
|
||||
}
|
||||
|
||||
avifRGBImage rgba;
|
||||
avifRGBImageSetDefaults(&rgba, result);
|
||||
if (img.channels() == 3) {
|
||||
rgba.format = AVIF_RGB_FORMAT_BGR;
|
||||
} else {
|
||||
CV_Assert(img.channels() == 4);
|
||||
rgba.format = AVIF_RGB_FORMAT_BGRA;
|
||||
}
|
||||
rgba.rowBytes = (uint32_t)img.step[0];
|
||||
rgba.depth = bit_depth;
|
||||
rgba.pixels =
|
||||
const_cast<uint8_t *>(reinterpret_cast<const uint8_t *>(img.data));
|
||||
if (img.channels() > 1) {
|
||||
avifRGBImage rgba;
|
||||
avifRGBImageSetDefaults(&rgba, result);
|
||||
if (img.channels() == 3) {
|
||||
rgba.format = AVIF_RGB_FORMAT_BGR;
|
||||
} else {
|
||||
CV_Assert(img.channels() == 4);
|
||||
rgba.format = AVIF_RGB_FORMAT_BGRA;
|
||||
}
|
||||
rgba.rowBytes = (uint32_t)img.step[0];
|
||||
rgba.depth = bit_depth;
|
||||
rgba.pixels =
|
||||
const_cast<uint8_t *>(reinterpret_cast<const uint8_t *>(img.data));
|
||||
|
||||
if (avifImageRGBToYUV(result, &rgba) != AVIF_RESULT_OK) {
|
||||
avifImageDestroy(result);
|
||||
return nullptr;
|
||||
if (avifImageRGBToYUV(result, &rgba) != AVIF_RESULT_OK) {
|
||||
avifImageDestroy(result);
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
return AvifImageUniquePtr(result);
|
||||
}
|
||||
|
||||
@@ -337,7 +337,7 @@ bool BmpDecoder::readData( Mat& img )
|
||||
}
|
||||
else
|
||||
{
|
||||
int x_shift3 = (int)(line_end - data);
|
||||
ptrdiff_t x_shift3 = line_end - data;
|
||||
|
||||
if( code == 2 )
|
||||
{
|
||||
@@ -430,7 +430,7 @@ decode_rle4_bad: ;
|
||||
}
|
||||
else
|
||||
{
|
||||
int x_shift3 = (int)(line_end - data);
|
||||
ptrdiff_t x_shift3 = line_end - data;
|
||||
int y_shift = m_height - y;
|
||||
|
||||
if( code || !line_end_flag || x_shift3 < width3 )
|
||||
@@ -441,7 +441,7 @@ decode_rle4_bad: ;
|
||||
y_shift = m_strm.getByte();
|
||||
}
|
||||
|
||||
x_shift3 += (y_shift * width3) & ((code == 0) - 1);
|
||||
x_shift3 += ((ptrdiff_t)y_shift * width3) & ((code == 0) - 1);
|
||||
|
||||
if( y >= m_height )
|
||||
break;
|
||||
|
||||
@@ -435,7 +435,7 @@ bool IsColorPalette( PaletteEntry* palette, int bpp )
|
||||
uchar* FillUniColor( uchar* data, uchar*& line_end,
|
||||
int step, int width3,
|
||||
int& y, int height,
|
||||
int count3, PaletteEntry clr )
|
||||
ptrdiff_t count3, PaletteEntry clr )
|
||||
{
|
||||
do
|
||||
{
|
||||
@@ -444,7 +444,7 @@ uchar* FillUniColor( uchar* data, uchar*& line_end,
|
||||
if( end > line_end )
|
||||
end = line_end;
|
||||
|
||||
count3 -= (int)(end - data);
|
||||
count3 -= end - data;
|
||||
|
||||
for( ; data < end; data += 3 )
|
||||
{
|
||||
@@ -467,7 +467,7 @@ uchar* FillUniColor( uchar* data, uchar*& line_end,
|
||||
uchar* FillUniGray( uchar* data, uchar*& line_end,
|
||||
int step, int width,
|
||||
int& y, int height,
|
||||
int count, uchar clr )
|
||||
ptrdiff_t count, uchar clr )
|
||||
{
|
||||
do
|
||||
{
|
||||
@@ -476,7 +476,7 @@ uchar* FillUniGray( uchar* data, uchar*& line_end,
|
||||
if( end > line_end )
|
||||
end = line_end;
|
||||
|
||||
count -= (int)(end - data);
|
||||
count -= end - data;
|
||||
|
||||
for( ; data < end; data++ )
|
||||
{
|
||||
|
||||
@@ -124,9 +124,9 @@ void FillGrayPalette( PaletteEntry* palette, int bpp, bool negative = false );
|
||||
bool IsColorPalette( PaletteEntry* palette, int bpp );
|
||||
void CvtPaletteToGray( const PaletteEntry* palette, uchar* grayPalette, int entries );
|
||||
uchar* FillUniColor( uchar* data, uchar*& line_end, int step, int width3,
|
||||
int& y, int height, int count3, PaletteEntry clr );
|
||||
int& y, int height, ptrdiff_t count3, PaletteEntry clr );
|
||||
uchar* FillUniGray( uchar* data, uchar*& line_end, int step, int width3,
|
||||
int& y, int height, int count3, uchar clr );
|
||||
int& y, int height, ptrdiff_t count3, uchar clr );
|
||||
|
||||
uchar* FillColorRow8( uchar* data, uchar* indices, int len, PaletteEntry* palette );
|
||||
uchar* FillGrayRow8( uchar* data, uchar* indices, int len, uchar* palette );
|
||||
|
||||
@@ -296,13 +296,15 @@ INSTANTIATE_TEST_CASE_P(Imgcodecs, Exif,
|
||||
testing::ValuesIn(exif_files));
|
||||
|
||||
#ifdef HAVE_AVIF
|
||||
TEST(Imgcodecs_Avif, ReadWriteWithExif)
|
||||
typedef testing::TestWithParam<int> MatChannels;
|
||||
|
||||
TEST_P(MatChannels, Imgcodecs_Avif_ReadWriteWithExif)
|
||||
{
|
||||
int avif_nbits = 10;
|
||||
int avif_speed = 10;
|
||||
int avif_quality = 85;
|
||||
int imgdepth = avif_nbits > 8 ? CV_16U : CV_8U;
|
||||
int imgtype = CV_MAKETYPE(imgdepth, 3);
|
||||
int imgtype = CV_MAKETYPE(imgdepth, GetParam());
|
||||
const string outputname = cv::tempfile(".avif");
|
||||
Mat img = makeCirclesImage(Size(1280, 720), imgtype, avif_nbits);
|
||||
|
||||
@@ -328,7 +330,7 @@ TEST(Imgcodecs_Avif, ReadWriteWithExif)
|
||||
EXPECT_EQ(img2.rows, img.rows);
|
||||
EXPECT_EQ(img2.type(), imgtype);
|
||||
EXPECT_EQ(read_metadata_types, read_metadata_types2);
|
||||
EXPECT_GE(read_metadata_types.size(), 1u);
|
||||
ASSERT_GE(read_metadata_types.size(), 1u);
|
||||
EXPECT_EQ(read_metadata, read_metadata2);
|
||||
EXPECT_EQ(read_metadata_types[0], IMAGE_METADATA_EXIF);
|
||||
EXPECT_EQ(read_metadata_types.size(), read_metadata.size());
|
||||
@@ -338,6 +340,9 @@ TEST(Imgcodecs_Avif, ReadWriteWithExif)
|
||||
EXPECT_LT(mse, 1500);
|
||||
remove(outputname.c_str());
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(Imgcodecs, MatChannels,
|
||||
testing::Values(1,3,4));
|
||||
#endif // HAVE_AVIF
|
||||
|
||||
#ifdef HAVE_WEBP
|
||||
|
||||
@@ -1344,8 +1344,8 @@ public class ImgprocTest extends OpenCVTestCase {
|
||||
|
||||
RotatedRect rrect = Imgproc.minAreaRect(points);
|
||||
|
||||
assertEquals(new Size(5, 2), rrect.size);
|
||||
assertEquals(0., rrect.angle);
|
||||
assertEquals(new Size(2, 5), rrect.size);
|
||||
assertEquals(-90., rrect.angle);
|
||||
assertEquals(new Point(3.5, 2), rrect.center);
|
||||
}
|
||||
|
||||
|
||||
@@ -76,12 +76,16 @@ static int Sklansky_( Point_<_Tp>** array, int start, int end, int* stack, int n
|
||||
|
||||
if( CV_SIGN( by ) != nsign )
|
||||
{
|
||||
_Tp ax = array[pcur]->x - array[pprev]->x;
|
||||
_Tp bx = array[pnext]->x - array[pcur]->x;
|
||||
_Tp ay = cury - array[pprev]->y;
|
||||
_DotTp convexity = (_DotTp)ay*bx - (_DotTp)ax*by; // if >0 then convex angle
|
||||
Vec<_Tp, 2> a(array[pcur]->x - array[pprev]->x, cury - array[pprev]->y);
|
||||
Vec<_Tp, 2> b(array[pnext]->x - array[pcur]->x, by);
|
||||
if (std::is_floating_point<_Tp>::value)
|
||||
{
|
||||
a = normalize(a);
|
||||
b = normalize(b);
|
||||
}
|
||||
_DotTp convexity = (_DotTp)a[1]*b[0] - (_DotTp)a[0]*b[1]; // if >0 then convex angle
|
||||
|
||||
if( CV_SIGN( convexity ) == sign2 && (ax != 0 || ay != 0) )
|
||||
if( CV_SIGN( convexity ) == sign2 && (a[0] != 0 || a[1] != 0) )
|
||||
{
|
||||
pprev = pcur;
|
||||
pcur = pnext;
|
||||
|
||||
@@ -1174,13 +1174,31 @@ static bool replacementFilter2D(int stype, int dtype, int kernel_type,
|
||||
cvhalFilter2D* ctx;
|
||||
int res = cv_hal_filterInit(&ctx, kernel_data, kernel_step, kernel_type, kernel_width, kernel_height, width, height,
|
||||
stype, dtype, borderType, delta, anchor_x, anchor_y, isSubmatrix, src_data == dst_data);
|
||||
if (res != CV_HAL_ERROR_OK)
|
||||
if (res == CV_HAL_ERROR_NOT_IMPLEMENTED)
|
||||
{
|
||||
return false;
|
||||
} else if (res != CV_HAL_ERROR_OK)
|
||||
{
|
||||
CV_Error_(cv::Error::StsInternal,
|
||||
("HAL implementation filterInit ==> " CVAUX_STR(cv_hal_filterInit) " returned %d (0x%08x)", res, res));
|
||||
}
|
||||
|
||||
res = cv_hal_filter(ctx, src_data, src_step, dst_data, dst_step, width, height, full_width, full_height, offset_x, offset_y);
|
||||
bool success = (res == CV_HAL_ERROR_OK);
|
||||
if (res != CV_HAL_ERROR_OK && res != CV_HAL_ERROR_NOT_IMPLEMENTED )
|
||||
{
|
||||
CV_Error_(cv::Error::StsInternal,
|
||||
("HAL implementation filter ==> " CVAUX_STR(cv_hal_filter) " returned %d (0x%08x)", res, res));
|
||||
}
|
||||
|
||||
res = cv_hal_filterFree(ctx);
|
||||
if (res != CV_HAL_ERROR_OK)
|
||||
return false;
|
||||
success &= (res == CV_HAL_ERROR_OK);
|
||||
if (res != CV_HAL_ERROR_OK && res != CV_HAL_ERROR_NOT_IMPLEMENTED )
|
||||
{
|
||||
CV_Error_(cv::Error::StsInternal,
|
||||
("HAL implementation filterFree ==> " CVAUX_STR(cv_hal_filterFree) " returned %d (0x%08x)", res, res));
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
@@ -1372,13 +1390,31 @@ static bool replacementSepFilter(int stype, int dtype, int ktype,
|
||||
kernelx_data, kernelx_len,
|
||||
kernely_data, kernely_len,
|
||||
anchor_x, anchor_y, delta, borderType);
|
||||
if (res != CV_HAL_ERROR_OK)
|
||||
if (res == CV_HAL_ERROR_NOT_IMPLEMENTED)
|
||||
{
|
||||
return false;
|
||||
} else if (res != CV_HAL_ERROR_OK)
|
||||
{
|
||||
CV_Error_(cv::Error::StsInternal,
|
||||
("HAL implementation sepFilterInit ==> " CVAUX_STR(cv_hal_sepFilterInit) " returned %d (0x%08x)", res, res));
|
||||
}
|
||||
|
||||
res = cv_hal_sepFilter(ctx, src_data, src_step, dst_data, dst_step, width, height, full_width, full_height, offset_x, offset_y);
|
||||
bool success = (res == CV_HAL_ERROR_OK);
|
||||
if (res != CV_HAL_ERROR_OK && res != CV_HAL_ERROR_NOT_IMPLEMENTED )
|
||||
{
|
||||
CV_Error_(cv::Error::StsInternal,
|
||||
("HAL implementation sepFilter ==> " CVAUX_STR(cv_hal_sepFilter) " returned %d (0x%08x)", res, res));
|
||||
}
|
||||
|
||||
res = cv_hal_sepFilterFree(ctx);
|
||||
if (res != CV_HAL_ERROR_OK)
|
||||
return false;
|
||||
success &= (res == CV_HAL_ERROR_OK);
|
||||
if (res != CV_HAL_ERROR_OK && res != CV_HAL_ERROR_NOT_IMPLEMENTED )
|
||||
{
|
||||
CV_Error_(cv::Error::StsInternal,
|
||||
("HAL implementation sepFilterFree ==> " CVAUX_STR(cv_hal_sepFilterFree) " returned %d (0x%08x)", res, res));
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
@@ -218,8 +218,14 @@ static bool halMorph(int op, int src_type, int dst_type,
|
||||
anchor_x, anchor_y,
|
||||
borderType, borderValue,
|
||||
iterations, isSubmatrix, src_data == dst_data);
|
||||
if (res != CV_HAL_ERROR_OK)
|
||||
if (res == CV_HAL_ERROR_NOT_IMPLEMENTED)
|
||||
{
|
||||
return false;
|
||||
} else if (res != CV_HAL_ERROR_OK)
|
||||
{
|
||||
CV_Error_(cv::Error::StsInternal,
|
||||
("HAL implementation morphInit ==> " CVAUX_STR(cv_hal_morphInit) " returned %d (0x%08x)", res, res));
|
||||
}
|
||||
|
||||
res = cv_hal_morph(ctx, src_data, src_step, dst_data, dst_step, width, height,
|
||||
roi_width, roi_height,
|
||||
@@ -227,10 +233,19 @@ static bool halMorph(int op, int src_type, int dst_type,
|
||||
roi_width2, roi_height2,
|
||||
roi_x2, roi_y2);
|
||||
bool success = (res == CV_HAL_ERROR_OK);
|
||||
if (res != CV_HAL_ERROR_OK && res != CV_HAL_ERROR_NOT_IMPLEMENTED )
|
||||
{
|
||||
CV_Error_(cv::Error::StsInternal,
|
||||
("HAL implementation morph ==> " CVAUX_STR(cv_hal_morph) " returned %d (0x%08x)", res, res));
|
||||
}
|
||||
|
||||
res = cv_hal_morphFree(ctx);
|
||||
if (res != CV_HAL_ERROR_OK)
|
||||
return false;
|
||||
success &= (res == CV_HAL_ERROR_OK);
|
||||
if (res != CV_HAL_ERROR_OK && res != CV_HAL_ERROR_NOT_IMPLEMENTED )
|
||||
{
|
||||
CV_Error_(cv::Error::StsInternal,
|
||||
("HAL implementation morphFree ==> " CVAUX_STR(cv_hal_morphFree) " returned %d (0x%08x)", res, res));
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
@@ -64,6 +64,7 @@ enum { CALIPERS_MAXHEIGHT=0, CALIPERS_MINAREARECT=1, CALIPERS_MAXDIST=2 };
|
||||
// Parameters:
|
||||
// points - convex hull vertices ( any orientation )
|
||||
// n - number of vertices
|
||||
// orientation - -1 for clockwise vertices order, 1 for CCW. 0 if unknown.
|
||||
// mode - concrete application of algorithm
|
||||
// can be CV_CALIPERS_MAXDIST or
|
||||
// CV_CALIPERS_MINAREARECT
|
||||
@@ -115,7 +116,7 @@ static bool firstVecIsRight(const cv::Point2f& vec1, const cv::Point2f &vec2)
|
||||
}
|
||||
|
||||
/* we will use usual cartesian coordinates */
|
||||
static void rotatingCalipers( const Point2f* points, int n, int mode, float* out )
|
||||
static void rotatingCalipers( const Point2f* points, int n, float orientation, int mode, float* out )
|
||||
{
|
||||
float minarea = FLT_MAX;
|
||||
float max_dist = 0;
|
||||
@@ -132,7 +133,6 @@ static void rotatingCalipers( const Point2f* points, int n, int mode, float* out
|
||||
(a,b) (-b,a) (-a,-b) (b, -a)
|
||||
*/
|
||||
/* this is a first base vector (a,b) initialized by (1,0) */
|
||||
float orientation = 0;
|
||||
float base_a;
|
||||
float base_b = 0;
|
||||
|
||||
@@ -171,6 +171,7 @@ static void rotatingCalipers( const Point2f* points, int n, int mode, float* out
|
||||
}
|
||||
|
||||
// find convex hull orientation
|
||||
if (orientation == 0.f)
|
||||
{
|
||||
double ax = vect[n-1].x;
|
||||
double ay = vect[n-1].y;
|
||||
@@ -364,8 +365,10 @@ cv::RotatedRect cv::minAreaRect( InputArray _points )
|
||||
Mat hull;
|
||||
Point2f out[3];
|
||||
RotatedRect box;
|
||||
box.angle = -(float)CV_PI / 2; // default angle for box without rotation and single point
|
||||
|
||||
convexHull(_points, hull, false, true);
|
||||
static const bool clockwise = false;
|
||||
convexHull(_points, hull, clockwise, true);
|
||||
|
||||
if( hull.depth() != CV_32F )
|
||||
{
|
||||
@@ -379,22 +382,37 @@ cv::RotatedRect cv::minAreaRect( InputArray _points )
|
||||
|
||||
if( n > 2 )
|
||||
{
|
||||
rotatingCalipers( hpoints, n, CALIPERS_MINAREARECT, (float*)out );
|
||||
rotatingCalipers( hpoints, n, clockwise ? -1.f : 1.f, CALIPERS_MINAREARECT, (float*)out );
|
||||
box.center.x = out[0].x + (out[1].x + out[2].x)*0.5f;
|
||||
box.center.y = out[0].y + (out[1].y + out[2].y)*0.5f;
|
||||
box.size.width = (float)std::sqrt((double)out[1].x*out[1].x + (double)out[1].y*out[1].y);
|
||||
box.size.height = (float)std::sqrt((double)out[2].x*out[2].x + (double)out[2].y*out[2].y);
|
||||
box.angle = (float)atan2( (double)out[1].y, (double)out[1].x );
|
||||
box.size.width = (float)std::sqrt((double)out[2].x*out[2].x + (double)out[2].y*out[2].y);
|
||||
box.size.height = (float)std::sqrt((double)out[1].x*out[1].x + (double)out[1].y*out[1].y);
|
||||
if (out[1].x == 0.f && out[1].y > 0.f)
|
||||
std::swap(box.size.width, box.size.height);
|
||||
else
|
||||
box.angle += (float)atan2( (double)out[1].y, (double)out[1].x );
|
||||
}
|
||||
else if( n == 2 )
|
||||
{
|
||||
box.center.x = (hpoints[0].x + hpoints[1].x)*0.5f;
|
||||
box.center.y = (hpoints[0].y + hpoints[1].y)*0.5f;
|
||||
double dx = hpoints[1].x - hpoints[0].x;
|
||||
double dy = hpoints[1].y - hpoints[0].y;
|
||||
box.size.width = (float)std::sqrt(dx*dx + dy*dy);
|
||||
box.size.height = 0;
|
||||
box.angle = (float)atan2( dy, dx );
|
||||
double dx = hpoints[0].x - hpoints[1].x;
|
||||
double dy = hpoints[0].y - hpoints[1].y;
|
||||
box.size.width = 0;
|
||||
box.size.height = (float)std::sqrt(dx*dx + dy*dy);
|
||||
if (dx == 0)
|
||||
{
|
||||
std::swap(box.size.width, box.size.height);
|
||||
}
|
||||
else if (dy < 0)
|
||||
{
|
||||
box.angle = (float)atan2( dy, dx );
|
||||
std::swap(box.size.width, box.size.height);
|
||||
}
|
||||
else if (dy > 0)
|
||||
{
|
||||
box.angle += (float)atan2( dy, dx );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -403,6 +421,8 @@ cv::RotatedRect cv::minAreaRect( InputArray _points )
|
||||
}
|
||||
|
||||
box.angle = (float)(box.angle*180/CV_PI);
|
||||
CV_DbgCheckGE(box.angle, -90.0f, "");
|
||||
CV_DbgCheckLT(box.angle, 0.0f, "");
|
||||
return box;
|
||||
}
|
||||
|
||||
|
||||
@@ -1232,6 +1232,57 @@ TEST(minEnclosingPolygon, pentagon)
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Imgproc_minAreaRect, reproducer_21482)
|
||||
{
|
||||
const int N = 4;
|
||||
float pts_[N][2] = {
|
||||
{ 188.8991f, 12.400669f },
|
||||
{ 80.64467f, -49.644814f },
|
||||
{ 469.59897f, 173.28242f },
|
||||
{ 690.4597f, 299.86768f },
|
||||
};
|
||||
|
||||
Mat contour(N, 1, CV_32FC2, (void*)pts_);
|
||||
|
||||
RotatedRect rr = cv::minAreaRect(contour);
|
||||
|
||||
EXPECT_TRUE(checkMinAreaRect(rr, contour)) << rr.center << " " << rr.size << " " << rr.angle;
|
||||
EXPECT_NEAR(min(rr.size.width, rr.size.height), 0, 1e-5);
|
||||
EXPECT_GE(max(rr.size.width, rr.size.height), 702);
|
||||
}
|
||||
|
||||
TEST(Imgproc_minAreaRect, reproducer_21482_small_values)
|
||||
{
|
||||
const int N = 4;
|
||||
float pts_[N][2] = { { 0.f, 0.f }, { 1e-4f, 0.f }, { 1e-4f, 1e-4f }, { 0.f, 1e-4f },};
|
||||
|
||||
Mat contour(N, 1, CV_32FC2, (void*)pts_);
|
||||
|
||||
RotatedRect rr = cv::minAreaRect(contour);
|
||||
|
||||
EXPECT_TRUE(checkMinAreaRect(rr, contour)) << rr.center << " " << rr.size << " " << rr.angle;
|
||||
EXPECT_EQ(rr.size.width, 1e-4f);
|
||||
EXPECT_EQ(rr.size.height, 1e-4f);
|
||||
}
|
||||
|
||||
typedef testing::TestWithParam<tuple<Point2f, Point2f, Point2f, Size2f, float>> minAreaRect_of_line;
|
||||
TEST_P(minAreaRect_of_line, accuracy)
|
||||
{
|
||||
Point2f p1 = get<0>(GetParam());
|
||||
Point2f p2 = get<1>(GetParam());
|
||||
RotatedRect out = minAreaRect(std::vector<Point2f>{p1, p2});
|
||||
EXPECT_EQ(out.center, get<2>(GetParam()));
|
||||
EXPECT_EQ(out.size, get<3>(GetParam()));
|
||||
EXPECT_NEAR(out.angle, get<4>(GetParam()), 1e-6);
|
||||
}
|
||||
INSTANTIATE_TEST_CASE_P(Imgproc, minAreaRect_of_line,
|
||||
testing::Values(
|
||||
std::make_tuple(Point2f(10, 15), Point2f(10, 25), Point2f(10, 20), Size2f(10, 0), -90.f),
|
||||
std::make_tuple(Point2f(450, 500), Point2f(508, 500), Point2f(479, 500), Size2f(0, 58), -90.f),
|
||||
std::make_tuple(Point2f(10, 20), Point2f(13, 16), Point2f(11.5, 18), Size2f(5, 0), -53.1301002f),
|
||||
std::make_tuple(Point2f(9, 19), Point2f(4, 7), Point2f(6.5, 13), Size2f(0, 13), -22.6198654f)
|
||||
));
|
||||
|
||||
}} // namespace
|
||||
|
||||
/* End of file. */
|
||||
|
||||
@@ -710,14 +710,14 @@ QUnit.test('test_rotatedRectangleIntersection', function(assert) {
|
||||
assert.deepEqual(intersectionType, cv.INTERSECT_FULL);
|
||||
intersectionPoints.convertTo(intersectionPoints, cv.CV_32S);
|
||||
let intersectionPointsData = intersectionPoints.data32S;
|
||||
assert.deepEqual(intersectionPointsData[0], 30);
|
||||
assert.deepEqual(intersectionPointsData[1], 40);
|
||||
assert.deepEqual(intersectionPointsData[2], 40);
|
||||
assert.deepEqual(intersectionPointsData[3], 30);
|
||||
assert.deepEqual(intersectionPointsData[4], 50);
|
||||
assert.deepEqual(intersectionPointsData[5], 40);
|
||||
assert.deepEqual(intersectionPointsData[6], 40);
|
||||
assert.deepEqual(intersectionPointsData[7], 50);
|
||||
assert.deepEqual(intersectionPointsData[0], 40);
|
||||
assert.deepEqual(intersectionPointsData[1], 50);
|
||||
assert.deepEqual(intersectionPointsData[2], 30);
|
||||
assert.deepEqual(intersectionPointsData[3], 40);
|
||||
assert.deepEqual(intersectionPointsData[4], 40);
|
||||
assert.deepEqual(intersectionPointsData[5], 30);
|
||||
assert.deepEqual(intersectionPointsData[6], 50);
|
||||
assert.deepEqual(intersectionPointsData[7], 40);
|
||||
|
||||
intersectionType = cv.rotatedRectangleIntersection(rr1, rr3, intersectionPoints);
|
||||
|
||||
|
||||
@@ -5,5 +5,5 @@ import sys
|
||||
if sys.version_info[:2] >= (3, 0):
|
||||
def exec_file_wrapper(fpath, g_vars, l_vars):
|
||||
with open(fpath) as f:
|
||||
code = compile(f.read(), os.path.basename(fpath), 'exec')
|
||||
code = compile(f.read(), fpath, 'exec')
|
||||
exec(code, g_vars, l_vars)
|
||||
|
||||
@@ -714,28 +714,29 @@ bool pyopencv_to(PyObject* obj, String &value, const ArgInfo& info)
|
||||
std::string str;
|
||||
|
||||
#if ((PY_VERSION_HEX >= 0x03060000) && !defined(Py_LIMITED_API)) || (Py_LIMITED_API >= 0x03060000)
|
||||
PyObject* path_obj = NULL;
|
||||
if (info.pathlike)
|
||||
{
|
||||
obj = PyOS_FSPath(obj);
|
||||
path_obj = PyOS_FSPath(obj);
|
||||
if (PyErr_Occurred())
|
||||
{
|
||||
failmsg("Expected '%s' to be a str or path-like object", info.name);
|
||||
return false;
|
||||
}
|
||||
obj = path_obj;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool result = false;
|
||||
if (getUnicodeString(obj, str))
|
||||
{
|
||||
value = str;
|
||||
return true;
|
||||
result = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// If error hasn't been already set by Python conversion functions
|
||||
if (!PyErr_Occurred())
|
||||
{
|
||||
// Direct access to underlying slots of PyObjectType is not allowed
|
||||
// when limited API is enabled
|
||||
#ifdef Py_LIMITED_API
|
||||
failmsg("Can't convert object to 'str' for '%s'", info.name);
|
||||
#else
|
||||
@@ -744,7 +745,12 @@ bool pyopencv_to(PyObject* obj, String &value, const ArgInfo& info)
|
||||
#endif
|
||||
}
|
||||
}
|
||||
return false;
|
||||
|
||||
#if ((PY_VERSION_HEX >= 0x03060000) && !defined(Py_LIMITED_API)) || (Py_LIMITED_API >= 0x03060000)
|
||||
Py_XDECREF(path_obj);
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template<>
|
||||
|
||||
@@ -81,7 +81,7 @@ class Hackathon244Tests(NewOpenCVTests):
|
||||
mc, mr = cv.minEnclosingCircle(a)
|
||||
|
||||
be0 = ((150.2511749267578, 150.77322387695312), (158.024658203125, 197.57696533203125), 37.57804489135742)
|
||||
br0 = ((161.2974090576172, 154.41793823242188), (207.7177734375, 199.2301483154297), 80.83544921875)
|
||||
br0 = ((161.2974090576172, 154.41793823242188), (199.2301483154297, 207.7177734375), -9.164555549621582)
|
||||
mc0, mr0 = (160.41790771484375, 144.55152893066406), 136.713500977
|
||||
|
||||
self.check_close_boxes(be, be0, 5, 15)
|
||||
|
||||
@@ -277,6 +277,9 @@ void MultiBandBlender::prepare(Rect dst_roi)
|
||||
else
|
||||
#endif
|
||||
{
|
||||
dst_pyr_laplace_.clear();
|
||||
dst_band_weights_.clear();
|
||||
|
||||
dst_pyr_laplace_.resize(num_bands_ + 1);
|
||||
dst_pyr_laplace_[0] = dst_;
|
||||
|
||||
|
||||
@@ -383,6 +383,51 @@ double findTransformECC(InputArray templateImage, InputArray inputImage,
|
||||
TermCriteria criteria = TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, 50, 0.001),
|
||||
InputArray inputMask = noArray());
|
||||
|
||||
/** @brief Finds the geometric transform (warp) between two images in terms of the ECC criterion @cite EP08
|
||||
using validity masks for both the template and the input images.
|
||||
|
||||
This function extends findTransformECC() by adding a mask for the template image.
|
||||
The Enhanced Correlation Coefficient is evaluated only over pixels that are valid in both images:
|
||||
on each iteration inputMask is warped into the template frame and combined with templateMask, and
|
||||
only the intersection of these masks contributes to the objective function.
|
||||
|
||||
@param templateImage 1 or 3 channel template image; CV_8U, CV_16U, CV_32F, CV_64F type.
|
||||
@param inputImage input image which should be warped with the final warpMatrix in
|
||||
order to provide an image similar to templateImage, same type as templateImage.
|
||||
@param templateMask single-channel 8-bit mask for templateImage indicating valid pixels
|
||||
to be used in the alignment. Must have the same size as templateImage.
|
||||
@param inputMask single-channel 8-bit mask for inputImage indicating valid pixels
|
||||
before warping. Must have the same size as inputImage.
|
||||
@param warpMatrix floating-point \f$2\times 3\f$ or \f$3\times 3\f$ mapping matrix (warp).
|
||||
@param motionType parameter, specifying the type of motion:
|
||||
- **MOTION_TRANSLATION** sets a translational motion model; warpMatrix is \f$2\times 3\f$ with
|
||||
the first \f$2\times 2\f$ part being the unity matrix and the rest two parameters being
|
||||
estimated.
|
||||
- **MOTION_EUCLIDEAN** sets a Euclidean (rigid) transformation as motion model; three
|
||||
parameters are estimated; warpMatrix is \f$2\times 3\f$.
|
||||
- **MOTION_AFFINE** sets an affine motion model (DEFAULT); six parameters are estimated;
|
||||
warpMatrix is \f$2\times 3\f$.
|
||||
- **MOTION_HOMOGRAPHY** sets a homography as a motion model; eight parameters are
|
||||
estimated; warpMatrix is \f$3\times 3\f$.
|
||||
@param criteria parameter, specifying the termination criteria of the ECC algorithm;
|
||||
criteria.epsilon defines the threshold of the increment in the correlation coefficient between two
|
||||
iterations (a negative criteria.epsilon makes criteria.maxcount the only termination criterion).
|
||||
Default values are shown in the declaration above.
|
||||
@param gaussFiltSize size of the Gaussian blur filter used for smoothing images and masks
|
||||
before computing the alignment (DEFAULT: 5).
|
||||
|
||||
@sa
|
||||
findTransformECC, computeECC, estimateAffine2D, estimateAffinePartial2D, findHomography
|
||||
*/
|
||||
CV_EXPORTS_W double findTransformECCWithMask( InputArray templateImage,
|
||||
InputArray inputImage,
|
||||
InputArray templateMask,
|
||||
InputArray inputMask,
|
||||
InputOutputArray warpMatrix,
|
||||
int motionType = MOTION_AFFINE,
|
||||
TermCriteria criteria = TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 50, 1e-6),
|
||||
int gaussFiltSize = 5 );
|
||||
|
||||
/** @example samples/cpp/snippets/kalman.cpp
|
||||
An example using the standard Kalman filter
|
||||
*/
|
||||
|
||||
+72
-25
@@ -333,8 +333,15 @@ double cv::computeECC(InputArray templateImage, InputArray inputImage, InputArra
|
||||
return templateImage_zeromean.dot(inputImage_zeromean) / (templateImagenorm * inputImagenorm);
|
||||
}
|
||||
|
||||
double cv::findTransformECC(InputArray templateImage, InputArray inputImage, InputOutputArray warpMatrix,
|
||||
int motionType, TermCriteria criteria, InputArray inputMask, int gaussFiltSize) {
|
||||
|
||||
double cv::findTransformECCWithMask( InputArray templateImage,
|
||||
InputArray inputImage,
|
||||
InputArray templateMask,
|
||||
InputArray inputMask,
|
||||
InputOutputArray warpMatrix,
|
||||
int motionType,
|
||||
TermCriteria criteria,
|
||||
int gaussFiltSize) {
|
||||
Mat src = templateImage.getMat(); // template image
|
||||
Mat dst = inputImage.getMat(); // input image (to be warped)
|
||||
Mat map = warpMatrix.getMat(); // warp (transformation)
|
||||
@@ -416,7 +423,7 @@ double cv::findTransformECC(InputArray templateImage, InputArray inputImage, Inp
|
||||
Ycoord.release();
|
||||
|
||||
const int channels = src.channels();
|
||||
int type = CV_MAKETYPE(CV_32F, channels); // используем отдельно, если нужно явно
|
||||
int type = CV_MAKETYPE(CV_32F, channels);
|
||||
|
||||
std::vector<cv::Mat> XgridCh(channels, Xgrid);
|
||||
cv::merge(XgridCh, Xgrid);
|
||||
@@ -430,27 +437,10 @@ double cv::findTransformECC(InputArray templateImage, InputArray inputImage, Inp
|
||||
Mat imageWarped = Mat(hs, ws, type); // to store the warped zero-mean input image
|
||||
Mat imageMask = Mat(hs, ws, CV_8U); // to store the final mask
|
||||
|
||||
Mat inputMaskMat = inputMask.getMat();
|
||||
// to use it for mask warping
|
||||
Mat preMask;
|
||||
if (inputMask.empty())
|
||||
preMask = Mat::ones(hd, wd, CV_8U);
|
||||
else
|
||||
threshold(inputMask, preMask, 0, 1, THRESH_BINARY);
|
||||
|
||||
// Gaussian filtering is optional
|
||||
src.convertTo(templateFloat, templateFloat.type());
|
||||
GaussianBlur(templateFloat, templateFloat, Size(gaussFiltSize, gaussFiltSize), 0, 0);
|
||||
|
||||
Mat preMaskFloat;
|
||||
preMask.convertTo(preMaskFloat, type);
|
||||
GaussianBlur(preMaskFloat, preMaskFloat, Size(gaussFiltSize, gaussFiltSize), 0, 0);
|
||||
// Change threshold.
|
||||
preMaskFloat *= (0.5 / 0.95);
|
||||
// Rounding conversion.
|
||||
preMaskFloat.convertTo(preMask, preMask.type());
|
||||
preMask.convertTo(preMaskFloat, preMaskFloat.type());
|
||||
|
||||
dst.convertTo(imageFloat, imageFloat.type());
|
||||
GaussianBlur(imageFloat, imageFloat, Size(gaussFiltSize, gaussFiltSize), 0, 0);
|
||||
|
||||
@@ -466,12 +456,48 @@ double cv::findTransformECC(InputArray templateImage, InputArray inputImage, Inp
|
||||
filter2D(imageFloat, gradientX, -1, dx);
|
||||
filter2D(imageFloat, gradientY, -1, dx.t());
|
||||
|
||||
cv::Mat preMaskFloatNCh;
|
||||
std::vector<cv::Mat> maskChannels(gradientX.channels(), preMaskFloat);
|
||||
cv::merge(maskChannels, preMaskFloatNCh);
|
||||
// To use in mask warping
|
||||
Mat templtMask;
|
||||
if(templateMask.empty())
|
||||
{
|
||||
templtMask = Mat::ones(hs, ws, CV_8U);
|
||||
}
|
||||
else
|
||||
{
|
||||
threshold(templateMask, templtMask, 0, 1, THRESH_BINARY);
|
||||
templtMask.convertTo(templtMask, CV_32F);
|
||||
GaussianBlur(templtMask, templtMask, Size(gaussFiltSize, gaussFiltSize), 0, 0);
|
||||
templtMask *= (0.5/0.95);
|
||||
templtMask.convertTo(templtMask, CV_8U);
|
||||
}
|
||||
|
||||
gradientX = gradientX.mul(preMaskFloatNCh);
|
||||
gradientY = gradientY.mul(preMaskFloatNCh);
|
||||
//to use it for mask warping
|
||||
Mat preMask;
|
||||
if(inputMask.empty())
|
||||
{
|
||||
preMask = Mat::ones(hd, wd, CV_8U);
|
||||
}
|
||||
else
|
||||
{
|
||||
Mat preMaskFloat;
|
||||
threshold(inputMask, preMask, 0, 1, THRESH_BINARY);
|
||||
|
||||
preMask.convertTo(preMaskFloat, CV_32F);
|
||||
GaussianBlur(preMaskFloat, preMaskFloat, Size(gaussFiltSize, gaussFiltSize), 0, 0);
|
||||
// Change threshold.
|
||||
preMaskFloat *= (0.5/0.95);
|
||||
// Rounding conversion.
|
||||
preMaskFloat.convertTo(preMask, CV_8U);
|
||||
|
||||
// If there's no template mask, we can apply image masks to gradients only once.
|
||||
// Otherwise, we'll need to combine the template and image masks at each iteration.
|
||||
if (templateMask.empty())
|
||||
{
|
||||
cv::Mat zeroMask = (preMask == 0);
|
||||
gradientX.setTo(0, zeroMask);
|
||||
gradientY.setTo(0, zeroMask);
|
||||
}
|
||||
}
|
||||
|
||||
// matrices needed for solving linear equation system for maximizing ECC
|
||||
Mat jacobian = Mat(hs, ws * numberOfParameters, type);
|
||||
@@ -505,6 +531,15 @@ double cv::findTransformECC(InputArray templateImage, InputArray inputImage, Inp
|
||||
warpPerspective(preMask, imageMask, map, imageMask.size(), maskFlags);
|
||||
}
|
||||
|
||||
if (!templateMask.empty())
|
||||
{
|
||||
cv::bitwise_and(imageMask, templtMask, imageMask);
|
||||
|
||||
cv::Mat zeroMask = (imageMask == 0);
|
||||
gradientXWarped.setTo(0, zeroMask);
|
||||
gradientYWarped.setTo(0, zeroMask);
|
||||
}
|
||||
|
||||
Scalar imgMean, imgStd, tmpMean, tmpStd;
|
||||
meanStdDev(imageWarped, imgMean, imgStd, imageMask);
|
||||
meanStdDev(templateFloat, tmpMean, tmpStd, imageMask);
|
||||
@@ -576,6 +611,18 @@ double cv::findTransformECC(InputArray templateImage, InputArray inputImage, Inp
|
||||
return rho;
|
||||
}
|
||||
|
||||
double cv::findTransformECC(InputArray templateImage,
|
||||
InputArray inputImage,
|
||||
InputOutputArray warpMatrix,
|
||||
int motionType,
|
||||
TermCriteria criteria,
|
||||
InputArray inputMask,
|
||||
int gaussFiltSize
|
||||
) {
|
||||
return findTransformECCWithMask(templateImage, inputImage, noArray(), inputMask,
|
||||
warpMatrix, motionType, criteria, gaussFiltSize);
|
||||
}
|
||||
|
||||
double cv::findTransformECC(InputArray templateImage, InputArray inputImage, InputOutputArray warpMatrix,
|
||||
int motionType, TermCriteria criteria, InputArray inputMask) {
|
||||
// Use default value of 5 for gaussFiltSize to maintain backward compatibility.
|
||||
|
||||
@@ -342,6 +342,26 @@ bool CV_ECC_Test_Mask::test(const Mat testImg) {
|
||||
// Test with non-default gaussian blur.
|
||||
findTransformECC(warpedImage, testImg, mapTranslation, 0, criteria, mask, 1);
|
||||
|
||||
if (!checkMap(mapTranslation, translationGround))
|
||||
return false;
|
||||
|
||||
// Test with template mask.
|
||||
Mat_<unsigned char> warpedMask = Mat_<unsigned char>::ones(warpedImage.rows, warpedImage.cols);
|
||||
for (int i=warpedImage.rows*1/3; i<warpedImage.rows*2/3; i++) {
|
||||
for (int j=warpedImage.cols*1/3; j<warpedImage.cols*2/3; j++) {
|
||||
warpedMask(i, j) = 0;
|
||||
}
|
||||
}
|
||||
|
||||
findTransformECCWithMask(warpedImage, testImg, warpedMask, mask, mapTranslation, 0,
|
||||
TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, ECC_iterations, ECC_epsilon));
|
||||
|
||||
if (!checkMap(mapTranslation, translationGround))
|
||||
return false;
|
||||
|
||||
// Test with non-default gaussian blur.
|
||||
findTransformECCWithMask(warpedImage, testImg, warpedMask, mask, mapTranslation, 0, criteria, 1);
|
||||
|
||||
if (!checkMap(mapTranslation, translationGround))
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -9,12 +9,10 @@ endif()
|
||||
if(NOT HAVE_ARAVIS_API)
|
||||
find_path(ARAVIS_INCLUDE "arv.h"
|
||||
PATHS "${ARAVIS_ROOT}" ENV ARAVIS_ROOT
|
||||
PATH_SUFFIXES "include/aravis-0.8"
|
||||
NO_DEFAULT_PATH)
|
||||
PATH_SUFFIXES "include/aravis-0.8")
|
||||
find_library(ARAVIS_LIBRARY "aravis-0.8"
|
||||
PATHS "${ARAVIS_ROOT}" ENV ARAVIS_ROOT
|
||||
PATH_SUFFIXES "lib"
|
||||
NO_DEFAULT_PATH)
|
||||
PATH_SUFFIXES "lib")
|
||||
if(ARAVIS_INCLUDE AND ARAVIS_LIBRARY)
|
||||
set(HAVE_ARAVIS_API TRUE)
|
||||
file(STRINGS "${ARAVIS_INCLUDE}/arvversion.h" ver_strings REGEX "#define +ARAVIS_(MAJOR|MINOR|MICRO)_VERSION.*")
|
||||
|
||||
@@ -127,6 +127,8 @@ protected:
|
||||
|
||||
void autoExposureControl(const Mat &);
|
||||
|
||||
double getExpectedMidGrey(ArvPixelFormat fmt) const;
|
||||
|
||||
ArvCamera *camera; // Camera to control.
|
||||
ArvStream *stream; // Object for video stream reception.
|
||||
void *framebuffer; //
|
||||
@@ -269,6 +271,19 @@ bool CvCaptureCAM_Aravis::open( int index )
|
||||
|
||||
// get initial values
|
||||
pixelFormat = arv_camera_get_pixel_format(camera, NULL);
|
||||
|
||||
// If camera's pixel format is not one of the supported formats, set a default
|
||||
if (pixelFormat != ARV_PIXEL_FORMAT_MONO_8 &&
|
||||
pixelFormat != ARV_PIXEL_FORMAT_BAYER_GR_8 &&
|
||||
pixelFormat != ARV_PIXEL_FORMAT_MONO_12 &&
|
||||
pixelFormat != ARV_PIXEL_FORMAT_MONO_16) {
|
||||
pixelFormat = ARV_PIXEL_FORMAT_MONO_8;
|
||||
arv_camera_set_pixel_format(camera, pixelFormat, NULL);
|
||||
CV_LOG_WARNING(NULL, "Current camera pixel format is not supported. Failed back to MONO_8.");
|
||||
}
|
||||
|
||||
midGrey = getExpectedMidGrey(pixelFormat);
|
||||
|
||||
exposure = exposureAvailable ? arv_camera_get_exposure_time(camera, NULL) : 0;
|
||||
gain = gainAvailable ? arv_camera_get_gain(camera, NULL) : 0;
|
||||
fps = arv_camera_get_frame_rate(camera, NULL);
|
||||
@@ -489,6 +504,26 @@ double CvCaptureCAM_Aravis::getProperty( int property_id ) const
|
||||
return -1.0;
|
||||
}
|
||||
|
||||
double CvCaptureCAM_Aravis::getExpectedMidGrey(ArvPixelFormat fmt) const
|
||||
{
|
||||
double grey = 0.;
|
||||
switch(fmt)
|
||||
{
|
||||
case ARV_PIXEL_FORMAT_MONO_8:
|
||||
case ARV_PIXEL_FORMAT_BAYER_GR_8:
|
||||
grey = 128.;
|
||||
break;
|
||||
case ARV_PIXEL_FORMAT_MONO_12:
|
||||
grey = 2048.;
|
||||
break;
|
||||
case ARV_PIXEL_FORMAT_MONO_16:
|
||||
grey = 32768.;
|
||||
break;
|
||||
}
|
||||
|
||||
return grey;
|
||||
}
|
||||
|
||||
bool CvCaptureCAM_Aravis::setProperty( int property_id, double value )
|
||||
{
|
||||
switch(property_id) {
|
||||
@@ -535,24 +570,22 @@ bool CvCaptureCAM_Aravis::setProperty( int property_id, double value )
|
||||
case MODE_GREY:
|
||||
case MODE_Y800:
|
||||
newFormat = ARV_PIXEL_FORMAT_MONO_8;
|
||||
targetGrey = 128;
|
||||
break;
|
||||
case MODE_Y12:
|
||||
newFormat = ARV_PIXEL_FORMAT_MONO_12;
|
||||
targetGrey = 2048;
|
||||
break;
|
||||
case MODE_Y16:
|
||||
newFormat = ARV_PIXEL_FORMAT_MONO_16;
|
||||
targetGrey = 32768;
|
||||
break;
|
||||
case MODE_GRBG:
|
||||
newFormat = ARV_PIXEL_FORMAT_BAYER_GR_8;
|
||||
targetGrey = 128;
|
||||
break;
|
||||
}
|
||||
|
||||
if(newFormat != pixelFormat) {
|
||||
stopCapture();
|
||||
arv_camera_set_pixel_format(camera, pixelFormat = newFormat, NULL);
|
||||
midGrey = getExpectedMidGrey(newFormat);
|
||||
startCapture();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,7 +153,7 @@ public:
|
||||
|
||||
protected:
|
||||
// Known widget names
|
||||
static const char * PROP_EXPOSURE_COMPENSACTION;
|
||||
static const char * PROP_EXPOSURE_COMPENSATION;
|
||||
static const char * PROP_SELF_TIMER_DELAY;
|
||||
static const char * PROP_MANUALFOCUS;
|
||||
static const char * PROP_AUTOFOCUS;
|
||||
@@ -294,7 +294,7 @@ const char * DigitalCameraCapture::lineDelimiter = "\n";
|
||||
* Those are actually substrings of widget name.
|
||||
* ie. for VIEWFINDER, Nikon uses "viewfinder", while Canon can use "eosviewfinder".
|
||||
*/
|
||||
const char * DigitalCameraCapture::PROP_EXPOSURE_COMPENSACTION =
|
||||
const char * DigitalCameraCapture::PROP_EXPOSURE_COMPENSATION =
|
||||
"exposurecompensation";
|
||||
const char * DigitalCameraCapture::PROP_SELF_TIMER_DELAY = "selftimerdelay";
|
||||
const char * DigitalCameraCapture::PROP_MANUALFOCUS = "manualfocusdrive";
|
||||
@@ -555,7 +555,7 @@ CameraWidget * DigitalCameraCapture::getGenericProperty(int propertyId,
|
||||
return NULL;
|
||||
}
|
||||
case CAP_PROP_EXPOSURE:
|
||||
return findWidgetByName(PROP_EXPOSURE_COMPENSACTION);
|
||||
return findWidgetByName(PROP_EXPOSURE_COMPENSATION);
|
||||
case CAP_PROP_TRIGGER_DELAY:
|
||||
return findWidgetByName(PROP_SELF_TIMER_DELAY);
|
||||
case CAP_PROP_ZOOM:
|
||||
@@ -692,7 +692,7 @@ CameraWidget * DigitalCameraCapture::setGenericProperty(int propertyId,
|
||||
output = false;
|
||||
return NULL;
|
||||
case CAP_PROP_EXPOSURE:
|
||||
return findWidgetByName(PROP_EXPOSURE_COMPENSACTION);
|
||||
return findWidgetByName(PROP_EXPOSURE_COMPENSATION);
|
||||
case CAP_PROP_TRIGGER_DELAY:
|
||||
return findWidgetByName(PROP_SELF_TIMER_DELAY);
|
||||
case CAP_PROP_ZOOM:
|
||||
|
||||
@@ -448,50 +448,68 @@ public:
|
||||
|
||||
STDMETHODIMP OnReadSample(HRESULT hrStatus, DWORD dwStreamIndex, DWORD dwStreamFlags, LONGLONG llTimestamp, IMFSample *pSample) CV_OVERRIDE
|
||||
{
|
||||
HRESULT hr = 0;
|
||||
cv::AutoLock lock(m_mutex);
|
||||
|
||||
if (SUCCEEDED(hrStatus))
|
||||
HRESULT hr = S_OK;
|
||||
try
|
||||
{
|
||||
if (pSample)
|
||||
cv::AutoLock lock(m_mutex);
|
||||
|
||||
if (SUCCEEDED(hrStatus))
|
||||
{
|
||||
CV_LOG_DEBUG(NULL, "videoio(MSMF): got frame at " << llTimestamp);
|
||||
if (m_capturedFrames.size() >= MSMF_READER_MAX_QUEUE_SIZE)
|
||||
if (pSample)
|
||||
{
|
||||
CV_LOG_DEBUG(NULL, "videoio(MSMF): got frame at " << llTimestamp);
|
||||
if (m_capturedFrames.size() >= MSMF_READER_MAX_QUEUE_SIZE)
|
||||
{
|
||||
#if 0
|
||||
CV_LOG_DEBUG(NULL, "videoio(MSMF): drop frame (not processed). Timestamp=" << m_capturedFrames.front().timestamp);
|
||||
m_capturedFrames.pop();
|
||||
CV_LOG_DEBUG(NULL, "videoio(MSMF): drop frame (not processed). Timestamp=" << m_capturedFrames.front().timestamp);
|
||||
m_capturedFrames.pop();
|
||||
#else
|
||||
// this branch reduces latency if we drop frames due to slow processing.
|
||||
// avoid fetching of already outdated frames from the queue's front.
|
||||
CV_LOG_DEBUG(NULL, "videoio(MSMF): drop previous frames (not processed): " << m_capturedFrames.size());
|
||||
std::queue<CapturedFrameInfo>().swap(m_capturedFrames); // similar to missing m_capturedFrames.clean();
|
||||
|
||||
CV_LOG_DEBUG(NULL, "videoio(MSMF): drop previous frames (not processed): " << m_capturedFrames.size());
|
||||
std::queue<CapturedFrameInfo>().swap(m_capturedFrames); // similar to missing m_capturedFrames.clean();
|
||||
#endif
|
||||
}
|
||||
m_capturedFrames.emplace(CapturedFrameInfo{ llTimestamp, _ComPtr<IMFSample>(pSample), hrStatus });
|
||||
}
|
||||
m_capturedFrames.emplace(CapturedFrameInfo{ llTimestamp, _ComPtr<IMFSample>(pSample), hrStatus });
|
||||
}
|
||||
else
|
||||
{
|
||||
CV_LOG_WARNING(NULL, "videoio(MSMF): OnReadSample() is called with error status: " << hrStatus);
|
||||
}
|
||||
if (MF_SOURCE_READERF_ENDOFSTREAM & dwStreamFlags)
|
||||
{
|
||||
// Reached the end of the stream.
|
||||
m_bEOS = true;
|
||||
}
|
||||
m_hrStatus = hrStatus;
|
||||
|
||||
if (FAILED(hr = m_reader->ReadSample(dwStreamIndex, 0, NULL, NULL, NULL, NULL)))
|
||||
{
|
||||
CV_LOG_WARNING(NULL, "videoio(MSMF): async ReadSample() call is failed with error status: " << hr);
|
||||
m_bEOS = true;
|
||||
}
|
||||
|
||||
if (pSample || m_bEOS)
|
||||
{
|
||||
SetEvent(m_hEvent);
|
||||
}
|
||||
}
|
||||
else
|
||||
catch (const _com_error& e)
|
||||
{
|
||||
CV_LOG_WARNING(NULL, "videoio(MSMF): OnReadSample() is called with error status: " << hrStatus);
|
||||
std::string msg;
|
||||
#ifdef _UNICODE
|
||||
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> conv;
|
||||
msg = conv.to_bytes(e.ErrorMessage());
|
||||
#else
|
||||
msg = std::string(e.ErrorMessage());
|
||||
#endif
|
||||
CV_LOG_WARNING(NULL, "videoio(MSMF): _com_error in OnReadSample: " << msg);
|
||||
return S_OK; // Keep callback alive
|
||||
}
|
||||
|
||||
if (MF_SOURCE_READERF_ENDOFSTREAM & dwStreamFlags)
|
||||
catch (...)
|
||||
{
|
||||
// Reached the end of the stream.
|
||||
m_bEOS = true;
|
||||
}
|
||||
m_hrStatus = hrStatus;
|
||||
|
||||
if (FAILED(hr = m_reader->ReadSample(dwStreamIndex, 0, NULL, NULL, NULL, NULL)))
|
||||
{
|
||||
CV_LOG_WARNING(NULL, "videoio(MSMF): async ReadSample() call is failed with error status: " << hr);
|
||||
m_bEOS = true;
|
||||
}
|
||||
|
||||
if (pSample || m_bEOS)
|
||||
{
|
||||
SetEvent(m_hEvent);
|
||||
CV_LOG_WARNING(NULL, "videoio(MSMF): Unknown exception in OnReadSample");
|
||||
return S_OK;
|
||||
}
|
||||
return S_OK;
|
||||
}
|
||||
@@ -1758,82 +1776,108 @@ bool CvCapture_MSMF::grabFrame()
|
||||
{
|
||||
CV_TRACE_FUNCTION();
|
||||
|
||||
if (grabIsDone)
|
||||
try
|
||||
{
|
||||
grabIsDone = false;
|
||||
CV_LOG_DEBUG(NULL, "videoio(MSMF): return pre-grabbed frame " << usedVideoSampleTime);
|
||||
return true;
|
||||
}
|
||||
|
||||
audioFrame = Mat();
|
||||
if (readCallback) // async "live" capture mode
|
||||
{
|
||||
audioSamples.push_back(NULL);
|
||||
HRESULT hr = 0;
|
||||
SourceReaderCB* reader = ((SourceReaderCB*)readCallback.Get());
|
||||
DWORD dwStreamIndex = 0;
|
||||
if (videoStream != -1)
|
||||
dwStreamIndex = dwVideoStreamIndex;
|
||||
if (audioStream != -1)
|
||||
dwStreamIndex = dwAudioStreamIndex;
|
||||
if (!reader->m_reader)
|
||||
if (grabIsDone)
|
||||
{
|
||||
// Initiate capturing with async callback
|
||||
reader->m_reader = videoFileSource.Get();
|
||||
reader->m_dwStreamIndex = dwStreamIndex;
|
||||
if (FAILED(hr = videoFileSource->ReadSample(dwStreamIndex, 0, NULL, NULL, NULL, NULL)))
|
||||
grabIsDone = false;
|
||||
CV_LOG_DEBUG(NULL, "videoio(MSMF): return pre-grabbed frame " << usedVideoSampleTime);
|
||||
return true;
|
||||
}
|
||||
|
||||
audioFrame = Mat();
|
||||
if (readCallback) // async "live" capture mode
|
||||
{
|
||||
audioSamples.push_back(NULL);
|
||||
HRESULT hr = 0;
|
||||
SourceReaderCB* reader = ((SourceReaderCB*)readCallback.Get());
|
||||
DWORD dwStreamIndex = 0;
|
||||
if (videoStream != -1)
|
||||
dwStreamIndex = dwVideoStreamIndex;
|
||||
if (audioStream != -1)
|
||||
dwStreamIndex = dwAudioStreamIndex;
|
||||
if (!reader->m_reader)
|
||||
{
|
||||
CV_LOG_ERROR(NULL, "videoio(MSMF): can't grab frame - initial async ReadSample() call failed: " << hr);
|
||||
reader->m_reader = NULL;
|
||||
// Initiate capturing with async callback
|
||||
reader->m_reader = videoFileSource.Get();
|
||||
reader->m_dwStreamIndex = dwStreamIndex;
|
||||
if (FAILED(hr = videoFileSource->ReadSample(dwStreamIndex, 0, NULL, NULL, NULL, NULL)))
|
||||
{
|
||||
CV_LOG_ERROR(NULL, "videoio(MSMF): can't grab frame - initial async ReadSample() call failed: " << hr);
|
||||
reader->m_reader = NULL;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
BOOL bEOS = false;
|
||||
LONGLONG timestamp = 0;
|
||||
if (FAILED(hr = reader->Wait( videoStream == -1 ? INFINITE : 10000, (videoStream != -1) ? usedVideoSample : audioSamples[0], timestamp, bEOS))) // 10 sec
|
||||
{
|
||||
CV_LOG_WARNING(NULL, "videoio(MSMF): can't grab frame. Error: " << hr);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
BOOL bEOS = false;
|
||||
LONGLONG timestamp = 0;
|
||||
if (FAILED(hr = reader->Wait( videoStream == -1 ? INFINITE : 10000, (videoStream != -1) ? usedVideoSample : audioSamples[0], timestamp, bEOS))) // 10 sec
|
||||
{
|
||||
CV_LOG_WARNING(NULL, "videoio(MSMF): can't grab frame. Error: " << hr);
|
||||
return false;
|
||||
}
|
||||
if (bEOS)
|
||||
{
|
||||
CV_LOG_WARNING(NULL, "videoio(MSMF): EOS signal. Capture stream is lost");
|
||||
return false;
|
||||
}
|
||||
if (videoStream != -1)
|
||||
usedVideoSampleTime = timestamp;
|
||||
if (audioStream != -1)
|
||||
return configureAudioFrame();
|
||||
|
||||
CV_LOG_DEBUG(NULL, "videoio(MSMF): grabbed frame " << usedVideoSampleTime);
|
||||
return true;
|
||||
}
|
||||
else if (isOpen)
|
||||
{
|
||||
if (vEOS)
|
||||
return false;
|
||||
|
||||
bool returnFlag = true;
|
||||
|
||||
if (videoStream != -1)
|
||||
{
|
||||
if (!vEOS)
|
||||
returnFlag &= grabVideoFrame();
|
||||
if (!returnFlag)
|
||||
if (bEOS)
|
||||
{
|
||||
CV_LOG_WARNING(NULL, "videoio(MSMF): EOS signal. Capture stream is lost");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (videoStream != -1)
|
||||
usedVideoSampleTime = timestamp;
|
||||
if (audioStream != -1)
|
||||
return configureAudioFrame();
|
||||
|
||||
if (audioStream != -1)
|
||||
CV_LOG_DEBUG(NULL, "videoio(MSMF): grabbed frame " << usedVideoSampleTime);
|
||||
return true;
|
||||
}
|
||||
else if (isOpen)
|
||||
{
|
||||
const int bytesPerSample = (captureAudioFormat.bit_per_sample/8) * captureAudioFormat.nChannels;
|
||||
bufferedAudioDuration = (double)(bufferAudioData.size()/bytesPerSample)/captureAudioFormat.nSamplesPerSec;
|
||||
audioFrame.release();
|
||||
if (!aEOS)
|
||||
returnFlag &= grabAudioFrame();
|
||||
}
|
||||
if (vEOS)
|
||||
return false;
|
||||
|
||||
return returnFlag;
|
||||
bool returnFlag = true;
|
||||
|
||||
if (videoStream != -1)
|
||||
{
|
||||
if (!vEOS)
|
||||
returnFlag &= grabVideoFrame();
|
||||
if (!returnFlag)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (audioStream != -1)
|
||||
{
|
||||
const int bytesPerSample = (captureAudioFormat.bit_per_sample/8) * captureAudioFormat.nChannels;
|
||||
bufferedAudioDuration = (double)(bufferAudioData.size()/bytesPerSample)/captureAudioFormat.nSamplesPerSec;
|
||||
audioFrame.release();
|
||||
if (!aEOS)
|
||||
returnFlag &= grabAudioFrame();
|
||||
}
|
||||
|
||||
return returnFlag;
|
||||
}
|
||||
}
|
||||
catch (const _com_error& e)
|
||||
{
|
||||
std::string msg;
|
||||
#ifdef _UNICODE
|
||||
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> conv;
|
||||
msg = conv.to_bytes(e.ErrorMessage());
|
||||
#else
|
||||
msg = std::string(e.ErrorMessage());
|
||||
#endif
|
||||
CV_LOG_WARNING(NULL, "videoio(MSMF): _com_error caught in grabFrame: " << msg);
|
||||
return false;
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
CV_LOG_WARNING(NULL, "videoio(MSMF): std::exception caught in grabFrame: " << e.what());
|
||||
return false;
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
CV_LOG_WARNING(NULL, "videoio(MSMF): Unknown exception caught in grabFrame");
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user