1
0
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:
Alexander Smorkalov
2025-08-27 15:50:00 +03:00
69 changed files with 7807 additions and 768 deletions
+1 -1
View File
@@ -774,7 +774,7 @@ struct CV_EXPORTS_W_SIMPLE CirclesGridFinderParameters
{
SYMMETRIC_GRID, ASYMMETRIC_GRID
};
GridType gridType;
CV_PROP_RW GridType gridType;
CV_PROP_RW float squareSize; //!< Distance between two adjacent points. Used by CALIB_CB_CLUSTERING.
CV_PROP_RW float maxRectifiedDistance; //!< Max deviation from prediction. Used by CALIB_CB_CLUSTERING.
+34
View File
@@ -648,6 +648,31 @@
"jni_var": "Vec3d %(n)s(%(n)s_val0, %(n)s_val1, %(n)s_val2)",
"suffix": "DDD"
},
"Vec4i": {
"j_type": "int[]",
"jn_args": [
[
"int",
".val[0]"
],
[
"int",
".val[1]"
],
[
"int",
".val[2]"
],
[
"int",
".val[3]"
]
],
"jn_type": "int[]",
"jni_type": "jintArray",
"jni_var": "Vec4i %(n)s(%(n)s_val0, %(n)s_val1, %(n)s_val2, %(n)s_val3)",
"suffix": "IIII"
},
"c_string": {
"j_type": "String",
"jn_type": "String",
@@ -852,6 +877,15 @@
"v_type": "Mat",
"j_import": "org.opencv.core.MatOfByte"
},
"vector_vector_Mat": {
"j_type": "List<List<Mat>>",
"jn_type": "long",
"jni_type": "jlong",
"jni_var": "std::vector< std::vector<Mat> > %(n)s",
"suffix": "J",
"v_type": "vector_Mat",
"j_import": "org.opencv.core.Mat"
},
"vector_vector_DMatch": {
"j_type": "List<MatOfDMatch>",
"jn_type": "long",
+197
View File
@@ -3,6 +3,8 @@
#ifdef HAVE_OPENCV_CORE
#include "dlpack/dlpack.h"
static PyObject* pycvMakeType(PyObject* , PyObject* args, PyObject* kw) {
const char *keywords[] = { "depth", "channels", NULL };
@@ -20,6 +22,201 @@ static PyObject* pycvMakeTypeCh(PyObject*, PyObject *value) {
return PyInt_FromLong(CV_MAKETYPE(depth, channels));
}
#define CV_DLPACK_CAPSULE_NAME "dltensor"
#define CV_DLPACK_USED_CAPSULE_NAME "used_dltensor"
template<typename T>
bool fillDLPackTensor(const T& src, DLManagedTensor* tensor, const DLDevice& device);
template<typename T>
bool parseDLPackTensor(DLManagedTensor* tensor, T& obj, bool copy);
template<typename T>
int GetNumDims(const T& src);
// source: https://github.com/dmlc/dlpack/blob/7f393bbb86a0ddd71fde3e700fc2affa5cdce72d/docs/source/python_spec.rst#L110
static void dlpack_capsule_deleter(PyObject *self){
if (PyCapsule_IsValid(self, CV_DLPACK_USED_CAPSULE_NAME)) {
return;
}
DLManagedTensor *managed = (DLManagedTensor *)PyCapsule_GetPointer(self, CV_DLPACK_CAPSULE_NAME);
if (managed == NULL) {
PyErr_WriteUnraisable(self);
return;
}
if (managed->deleter) {
managed->deleter(managed);
}
}
static void array_dlpack_deleter(DLManagedTensor *self)
{
if (!Py_IsInitialized()) {
return;
}
PyGILState_STATE state = PyGILState_Ensure();
PyObject *array = (PyObject *)self->manager_ctx;
PyMem_Free(self);
Py_XDECREF(array);
PyGILState_Release(state);
}
template<typename T>
static PyObject* to_dlpack(const T& src, PyObject* self, PyObject* py_args, PyObject* kw)
{
int stream = 0;
PyObject* maxVersion = nullptr;
PyObject* dlDevice = nullptr;
bool copy = false;
const char* keywords[] = { "stream", "max_version", "dl_device", "copy", NULL };
if (!PyArg_ParseTupleAndKeywords(py_args, kw, "|iOOp:__dlpack__", (char**)keywords, &stream, &maxVersion, &dlDevice, &copy))
return nullptr;
DLDevice device = {(DLDeviceType)-1, 0};
if (dlDevice && dlDevice != Py_None && PyTuple_Check(dlDevice))
{
device.device_type = static_cast<DLDeviceType>(PyLong_AsLong(PyTuple_GetItem(dlDevice, 0)));
device.device_id = PyLong_AsLong(PyTuple_GetItem(dlDevice, 1));
}
int ndim = GetNumDims(src);
void* ptr = PyMem_Malloc(sizeof(DLManagedTensor) + sizeof(int64_t) * ndim * 2);
if (!ptr) {
PyErr_NoMemory();
return nullptr;
}
DLManagedTensor* tensor = reinterpret_cast<DLManagedTensor*>(ptr);
tensor->manager_ctx = self;
tensor->deleter = array_dlpack_deleter;
tensor->dl_tensor.ndim = ndim;
tensor->dl_tensor.shape = reinterpret_cast<int64_t*>(reinterpret_cast<char*>(ptr) + sizeof(DLManagedTensor));
tensor->dl_tensor.strides = tensor->dl_tensor.shape + ndim;
fillDLPackTensor(src, tensor, device);
PyObject* capsule = PyCapsule_New(ptr, CV_DLPACK_CAPSULE_NAME, dlpack_capsule_deleter);
if (!capsule) {
PyMem_Free(ptr);
return nullptr;
}
// the capsule holds a reference
Py_INCREF(self);
return capsule;
}
template<typename T>
static PyObject* from_dlpack(PyObject* py_args, PyObject* kw)
{
PyObject* arr = nullptr;
PyObject* device = nullptr;
bool copy = false;
const char* keywords[] = { "device", "copy", NULL };
if (!PyArg_ParseTupleAndKeywords(py_args, kw, "O|Op:from_dlpack", (char**)keywords, &arr, &device, &copy))
return nullptr;
PyObject* capsule = nullptr;
if (PyCapsule_CheckExact(arr))
{
capsule = arr;
}
else
{
PyGILState_STATE gstate;
gstate = PyGILState_Ensure();
capsule = PyObject_CallMethodObjArgs(arr, PyString_FromString("__dlpack__"), NULL);
PyGILState_Release(gstate);
}
DLManagedTensor* tensor = reinterpret_cast<DLManagedTensor*>(PyCapsule_GetPointer(capsule, CV_DLPACK_CAPSULE_NAME));
if (tensor == nullptr)
{
if (capsule != arr)
Py_DECREF(capsule);
return nullptr;
}
T retval;
bool success = parseDLPackTensor(tensor, retval, copy);
if (success)
{
PyCapsule_SetName(capsule, CV_DLPACK_USED_CAPSULE_NAME);
}
if (capsule != arr)
Py_DECREF(capsule);
return success ? pyopencv_from(retval) : nullptr;
}
static DLDataType GetDLPackType(size_t elemSize1, int depth) {
DLDataType dtype;
dtype.bits = static_cast<uint8_t>(8 * elemSize1);
dtype.lanes = 1;
switch (depth)
{
case CV_8S: case CV_16S: case CV_32S: dtype.code = kDLInt; break;
case CV_8U: case CV_16U: dtype.code = kDLUInt; break;
case CV_16F: case CV_32F: case CV_64F: dtype.code = kDLFloat; break;
default:
CV_Error(Error::StsNotImplemented, "__dlpack__ data type");
}
return dtype;
}
static int DLPackTypeToCVType(const DLDataType& dtype, int channels) {
if (dtype.code == kDLInt)
{
switch (dtype.bits)
{
case 8: return CV_8SC(channels);
case 16: return CV_16SC(channels);
case 32: return CV_32SC(channels);
default:
{
PyErr_SetString(PyExc_BufferError,
format("Unsupported int dlpack depth: %d", dtype.bits).c_str());
return -1;
}
}
}
if (dtype.code == kDLUInt)
{
switch (dtype.bits)
{
case 8: return CV_8UC(channels);
case 16: return CV_16UC(channels);
default:
{
PyErr_SetString(PyExc_BufferError,
format("Unsupported uint dlpack depth: %d", dtype.bits).c_str());
return -1;
}
}
}
if (dtype.code == kDLFloat)
{
switch (dtype.bits)
{
case 16: return CV_16FC(channels);
case 32: return CV_32FC(channels);
case 64: return CV_64FC(channels);
default:
{
PyErr_SetString(PyExc_BufferError,
format("Unsupported float dlpack depth: %d", dtype.bits).c_str());
return -1;
}
}
}
PyErr_SetString(PyExc_BufferError, format("Unsupported dlpack data type: %d", dtype.code).c_str());
return -1;
}
#define PYOPENCV_EXTRA_METHODS_CV \
{"CV_MAKETYPE", CV_PY_FN_WITH_KW(pycvMakeType), "CV_MAKETYPE(depth, channels) -> retval"}, \
{"CV_8UC", (PyCFunction)(pycvMakeTypeCh<CV_8U>), METH_O, "CV_8UC(channels) -> retval"}, \
+158
View File
@@ -21,17 +21,175 @@ template<> struct pyopencvVecConverter<cuda::GpuMat>
};
CV_PY_TO_CLASS(cuda::GpuMat)
CV_PY_TO_CLASS(cuda::GpuMatND)
CV_PY_TO_CLASS(cuda::Stream)
CV_PY_TO_CLASS(cuda::Event)
CV_PY_TO_CLASS(cuda::HostMem)
CV_PY_TO_CLASS_PTR(cuda::GpuMat)
CV_PY_TO_CLASS_PTR(cuda::GpuMatND)
CV_PY_TO_CLASS_PTR(cuda::GpuMat::Allocator)
CV_PY_FROM_CLASS(cuda::GpuMat)
CV_PY_FROM_CLASS(cuda::GpuMatND)
CV_PY_FROM_CLASS(cuda::Stream)
CV_PY_FROM_CLASS(cuda::HostMem)
CV_PY_FROM_CLASS_PTR(cuda::GpuMat::Allocator)
template<>
bool fillDLPackTensor(const Ptr<cv::cuda::GpuMat>& src, DLManagedTensor* tensor, const DLDevice& device)
{
if ((device.device_type != -1 && device.device_type != kDLCUDA) || device.device_id != 0)
{
PyErr_SetString(PyExc_BufferError, "GpuMat can be exported only on GPU:0");
return false;
}
tensor->dl_tensor.data = src->cudaPtr();
tensor->dl_tensor.device.device_type = kDLCUDA;
tensor->dl_tensor.device.device_id = 0;
tensor->dl_tensor.dtype = GetDLPackType(src->elemSize1(), src->depth());
tensor->dl_tensor.shape[0] = src->rows;
tensor->dl_tensor.shape[1] = src->cols;
tensor->dl_tensor.shape[2] = src->channels();
tensor->dl_tensor.strides[0] = src->step1();
tensor->dl_tensor.strides[1] = src->channels();
tensor->dl_tensor.strides[2] = 1;
tensor->dl_tensor.byte_offset = 0;
return true;
}
template<>
bool fillDLPackTensor(const Ptr<cv::cuda::GpuMatND>& src, DLManagedTensor* tensor, const DLDevice& device)
{
if ((device.device_type != -1 && device.device_type != kDLCUDA) || device.device_id != 0)
{
PyErr_SetString(PyExc_BufferError, "GpuMatND can be exported only on GPU:0");
return false;
}
tensor->dl_tensor.data = src->getDevicePtr();
tensor->dl_tensor.device.device_type = kDLCUDA;
tensor->dl_tensor.device.device_id = 0;
tensor->dl_tensor.dtype = GetDLPackType(src->elemSize1(), CV_MAT_DEPTH(src->flags));
for (int i = 0; i < src->dims; ++i)
tensor->dl_tensor.shape[i] = src->size[i];
for (int i = 0; i < src->dims; ++i)
tensor->dl_tensor.strides[i] = src->step[i];
tensor->dl_tensor.byte_offset = 0;
return true;
}
template<>
bool parseDLPackTensor(DLManagedTensor* tensor, cv::cuda::GpuMat& obj, bool copy)
{
if (tensor->dl_tensor.byte_offset != 0)
{
PyErr_SetString(PyExc_BufferError, "Unimplemented from_dlpack for GpuMat with memory offset");
return false;
}
if (tensor->dl_tensor.ndim != 3)
{
PyErr_SetString(PyExc_BufferError, "cuda_GpuMat.from_dlpack expects a 3D tensor. Use cuda_GpuMatND.from_dlpack instead");
return false;
}
if (tensor->dl_tensor.device.device_type != kDLCUDA)
{
PyErr_SetString(PyExc_BufferError, "cuda_GpuMat.from_dlpack expects a tensor on CUDA device");
return false;
}
if (tensor->dl_tensor.strides[1] != tensor->dl_tensor.shape[2] ||
tensor->dl_tensor.strides[2] != 1)
{
PyErr_SetString(PyExc_BufferError, "Unexpected strides for image. Try use GpuMatND");
return false;
}
int type = DLPackTypeToCVType(tensor->dl_tensor.dtype, (int)tensor->dl_tensor.shape[2]);
if (type == -1)
return false;
obj = cv::cuda::GpuMat(
static_cast<int>(tensor->dl_tensor.shape[0]),
static_cast<int>(tensor->dl_tensor.shape[1]),
type,
tensor->dl_tensor.data,
tensor->dl_tensor.strides[0] * tensor->dl_tensor.dtype.bits / 8
);
if (copy)
obj = obj.clone();
return true;
}
template<>
bool parseDLPackTensor(DLManagedTensor* tensor, cv::cuda::GpuMatND& obj, bool copy)
{
if (tensor->dl_tensor.byte_offset != 0)
{
PyErr_SetString(PyExc_BufferError, "Unimplemented from_dlpack for GpuMat with memory offset");
return false;
}
if (tensor->dl_tensor.device.device_type != kDLCUDA)
{
PyErr_SetString(PyExc_BufferError, "cuda_GpuMat.from_dlpack expects a tensor on CUDA device");
return false;
}
int type = DLPackTypeToCVType(tensor->dl_tensor.dtype, (int)tensor->dl_tensor.shape[2]);
if (type == -1)
return false;
std::vector<size_t> steps(tensor->dl_tensor.ndim - 1);
std::vector<int> sizes(tensor->dl_tensor.ndim);
for (int i = 0; i < tensor->dl_tensor.ndim - 1; ++i)
{
steps[i] = tensor->dl_tensor.strides[i] * tensor->dl_tensor.dtype.bits / 8;
sizes[i] = static_cast<int>(tensor->dl_tensor.shape[i]);
}
sizes.back() = static_cast<int>(tensor->dl_tensor.shape[tensor->dl_tensor.ndim - 1]);
obj = cv::cuda::GpuMatND(sizes, type, tensor->dl_tensor.data, steps);
if (copy)
obj = obj.clone();
return true;
}
template<>
int GetNumDims(const Ptr<cv::cuda::GpuMat>& src) { return 3; }
template<>
int GetNumDims(const Ptr<cv::cuda::GpuMatND>& src) { return src->dims; }
static PyObject* pyDLPackGpuMat(PyObject* self, PyObject* py_args, PyObject* kw) {
Ptr<cv::cuda::GpuMat> * self1 = 0;
if (!pyopencv_cuda_GpuMat_getp(self, self1))
return failmsgp("Incorrect type of self (must be 'cuda_GpuMat' or its derivative)");
return to_dlpack(*(self1), self, py_args, kw);
}
static PyObject* pyDLPackGpuMatND(PyObject* self, PyObject* py_args, PyObject* kw) {
Ptr<cv::cuda::GpuMatND> * self1 = 0;
if (!pyopencv_cuda_GpuMatND_getp(self, self1))
return failmsgp("Incorrect type of self (must be 'cuda_GpuMatND' or its derivative)");
return to_dlpack(*(self1), self, py_args, kw);
}
static PyObject* pyDLPackDeviceCUDA(PyObject*, PyObject*, PyObject*) {
return pyopencv_from(std::tuple<int, int>(kDLCUDA, 0));
}
static PyObject* pyGpuMatFromDLPack(PyObject*, PyObject* py_args, PyObject* kw) {
return from_dlpack<cv::cuda::GpuMat>(py_args, kw);
}
static PyObject* pyGpuMatNDFromDLPack(PyObject*, PyObject* py_args, PyObject* kw) {
return from_dlpack<cv::cuda::GpuMatND>(py_args, kw);
}
#define PYOPENCV_EXTRA_METHODS_cuda_GpuMat \
{"__dlpack__", CV_PY_FN_WITH_KW(pyDLPackGpuMat), ""}, \
{"__dlpack_device__", CV_PY_FN_WITH_KW(pyDLPackDeviceCUDA), ""}, \
{"from_dlpack", CV_PY_FN_WITH_KW_(pyGpuMatFromDLPack, METH_STATIC), ""}, \
#define PYOPENCV_EXTRA_METHODS_cuda_GpuMatND \
{"__dlpack__", CV_PY_FN_WITH_KW(pyDLPackGpuMatND), ""}, \
{"__dlpack_device__", CV_PY_FN_WITH_KW(pyDLPackDeviceCUDA), ""}, \
{"from_dlpack", CV_PY_FN_WITH_KW_(pyGpuMatNDFromDLPack, METH_STATIC), ""}, \
#endif
+9 -1
View File
@@ -60,6 +60,14 @@ namespace cv
#undef USE_IPP_DFT
#endif
#if defined USE_IPP_DFT
#if IPP_VERSION_X100 >= 202220
#define IPP_DISABLE_DFT32F ((depth == CV_32F) && (ippCPUID_AVX512F&cv::ipp::getIppFeatures()))
#else
#define IPP_DISABLE_DFT32F false
#endif
#endif
/****************************************************************************************\
Discrete Fourier Transform
\****************************************************************************************/
@@ -3258,7 +3266,7 @@ public:
opt.ipp_spec = 0;
opt.ipp_work = 0;
if( CV_IPP_CHECK_COND && (opt.n*count >= 64) ) // use IPP DFT if available
if( CV_IPP_CHECK_COND && (opt.n*count >= 64) && !IPP_DISABLE_DFT32F) // use IPP DFT if available
{
int ipp_norm_flag = (flags & CV_HAL_DFT_SCALE) == 0 ? 8 : opt.isInverse ? 2 : 1;
int specsize=0, initsize=0, worksize=0;
@@ -0,0 +1,67 @@
package org.opencv.test.dnn;
import java.util.ArrayList;
import java.util.List;
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.MatOfByte;
import org.opencv.core.Range;
import org.opencv.dnn.Dnn;
import org.opencv.dnn.Net;
import org.opencv.test.OpenCVTestCase;
public class DnnForwardAndRetrieve extends OpenCVTestCase {
public void testForwardAndRetrieve()
{
// Create a simple Caffe prototxt with a Slice layer
String prototxt =
"input: \"data\"\n" +
"layer {\n" +
" name: \"testLayer\"\n" +
" type: \"Slice\"\n" +
" bottom: \"data\"\n" +
" top: \"firstCopy\"\n" +
" top: \"secondCopy\"\n" +
" slice_param {\n" +
" axis: 0\n" +
" slice_point: 2\n" +
" }\n" +
"}";
// Read network from prototxt
MatOfByte bufferProto = new MatOfByte();
bufferProto.fromArray(prototxt.getBytes());
MatOfByte bufferModel = new MatOfByte();
Net net = Dnn.readNetFromCaffe(bufferProto, bufferModel, Dnn.ENGINE_CLASSIC);
net.setPreferableBackend(Dnn.DNN_BACKEND_OPENCV);
// Create input data
Mat inp = new Mat(4, 5, CvType.CV_32F);
Core.randu(inp, -1, 1);
net.setInput(inp);
// Define output names
List<String> outNames = new ArrayList<>();
outNames.add("testLayer");
// Forward and retrieve multiple outputs
List<List<Mat>> outBlobs = new ArrayList<>();
net.forwardAndRetrieve(outBlobs, outNames);
// Verify results
assertEquals(1, outBlobs.size());
assertEquals(2, outBlobs.get(0).size());
// Compare results
Mat expectedFirst = inp.rowRange(0, 2);
Mat expectedSecond = inp.rowRange(2, 4);
Mat actualFirst = outBlobs.get(0).get(0);
Mat actualSecond = outBlobs.get(0).get(1);
assertEquals(0, Core.norm(expectedFirst, actualFirst, Core.NORM_INF), EPS);
assertEquals(0, Core.norm(expectedSecond, actualSecond, Core.NORM_INF), EPS);
}
}
+15 -1
View File
@@ -1110,13 +1110,27 @@ public:
*/
CV_WRAP Subdiv2D(Rect rect);
/** @brief Creates a new empty Delaunay subdivision
/** @overload */
CV_WRAP Subdiv2D(Rect2f rect2f);
/** @overload
@brief Creates a new empty Delaunay subdivision
@param rect Rectangle that includes all of the 2D points that are to be added to the subdivision.
*/
CV_WRAP void initDelaunay(Rect rect);
/** @overload
@brief Creates a new empty Delaunay subdivision
@param rect Rectangle that includes all of the 2d points that are to be added to the subdivision.
*/
CV_WRAP_AS(initDelaunay2f) CV_WRAP void initDelaunay(Rect2f rect);
/** @brief Insert a single point into a Delaunay triangulation.
@param pt Point to insert.
+56
View File
@@ -118,6 +118,16 @@ Subdiv2D::Subdiv2D(Rect rect)
initDelaunay(rect);
}
Subdiv2D::Subdiv2D(Rect2f rect)
{
validGeometry = false;
freeQEdge = 0;
freePoint = 0;
recentEdge = 0;
initDelaunay(rect);
}
Subdiv2D::QuadEdge::QuadEdge()
{
@@ -535,6 +545,52 @@ void Subdiv2D::initDelaunay( Rect rect )
recentEdge = edge_AB;
}
void Subdiv2D::initDelaunay( Rect2f rect )
{
CV_INSTRUMENT_REGION();
float big_coord = 6.f * MAX( rect.width, rect.height );
float rx = rect.x;
float ry = rect.y;
vtx.clear();
qedges.clear();
recentEdge = 0;
validGeometry = false;
topLeft = Point2f( rx, ry );
bottomRight = Point2f( rx + rect.width, ry + rect.height );
Point2f ppA( rx + big_coord, ry );
Point2f ppB( rx, ry + big_coord );
Point2f ppC( rx - big_coord, ry - big_coord );
vtx.push_back(Vertex());
qedges.push_back(QuadEdge());
freeQEdge = 0;
freePoint = 0;
int pA = newPoint(ppA, false);
int pB = newPoint(ppB, false);
int pC = newPoint(ppC, false);
int edge_AB = newEdge();
int edge_BC = newEdge();
int edge_CA = newEdge();
setEdgePoints( edge_AB, pA, pB );
setEdgePoints( edge_BC, pB, pC );
setEdgePoints( edge_CA, pC, pA );
splice( edge_AB, symEdge( edge_CA ));
splice( edge_BC, symEdge( edge_AB ));
splice( edge_CA, symEdge( edge_BC ));
recentEdge = edge_AB;
}
void Subdiv2D::clearVoronoi()
{
+6 -3
View File
@@ -11,10 +11,13 @@ namespace opencv_test { namespace {
// return true if point lies inside ellipse
static bool check_pt_in_ellipse(const Point2f& pt, const RotatedRect& el) {
Point2f to_pt = pt - el.center;
double pt_angle = atan2(to_pt.y, to_pt.x);
double el_angle = el.angle * CV_PI / 180;
double x_dist = 0.5 * el.size.width * cos(pt_angle + el_angle);
double y_dist = 0.5 * el.size.height * sin(pt_angle + el_angle);
const Point2d to_pt_el(
to_pt.x * cos(-el_angle) - to_pt.y * sin(-el_angle),
to_pt.x * sin(-el_angle) + to_pt.y * cos(-el_angle));
const double pt_angle = atan2(to_pt_el.y / el.size.height, to_pt_el.x / el.size.width);
const double x_dist = 0.5 * el.size.width * cos(pt_angle);
const double y_dist = 0.5 * el.size.height * sin(pt_angle);
double el_dist = sqrt(x_dist * x_dist + y_dist * y_dist);
return cv::norm(to_pt) < el_dist;
}
@@ -64,4 +64,57 @@ TEST(Imgproc_Subdiv2D, issue_25696) {
ASSERT_EQ(static_cast<size_t>(2), triangles.size());
}
// Initialization test
TEST(Imgproc_Subdiv2D, rect2f_constructor_and_init)
{
cv::Rect2f rect_f(0.5f, 1.5f, 100.7f, 200.3f);
cv::Subdiv2D subdiv_f(rect_f);
cv::Point2f pt1(50.2f, 80.1f);
cv::Point2f pt2(75.8f, 120.9f);
cv::Point2f pt3(25.5f, 150.3f);
EXPECT_NO_THROW(subdiv_f.insert(pt1));
EXPECT_NO_THROW(subdiv_f.insert(pt2));
EXPECT_NO_THROW(subdiv_f.insert(pt3));
cv::Subdiv2D subdiv_init;
EXPECT_NO_THROW(subdiv_init.initDelaunay(rect_f));
EXPECT_NO_THROW(subdiv_init.insert(pt1));
EXPECT_NO_THROW(subdiv_init.insert(pt2));
EXPECT_NO_THROW(subdiv_init.insert(pt3));
std::vector<cv::Vec6f> triangles;
EXPECT_NO_THROW(subdiv_f.getTriangleList(triangles));
EXPECT_GT(triangles.size(), 0u);
}
// test with small coordinates
TEST(Imgproc_Subdiv2D, rect2f_edge_cases)
{
cv::Rect2f small_rect(0.0f, 0.0f, 0.1f, 0.1f);
cv::Subdiv2D subdiv_small(small_rect);
cv::Point2f small_pt(0.05f, 0.05f);
EXPECT_NO_THROW(subdiv_small.insert(small_pt));
cv::Rect2f float_rect(10.25f, 20.75f, 50.5f, 30.25f);
cv::Subdiv2D subdiv_float(float_rect);
cv::Point2f float_pt1(35.125f, 35.875f);
cv::Point2f float_pt2(45.375f, 25.625f);
cv::Point2f float_pt3(55.750f, 45.125f);
EXPECT_NO_THROW(subdiv_float.insert(float_pt1));
EXPECT_NO_THROW(subdiv_float.insert(float_pt2));
EXPECT_NO_THROW(subdiv_float.insert(float_pt3));
std::vector<cv::Vec6f> triangles;
subdiv_float.getTriangleList(triangles);
EXPECT_GT(triangles.size(), 0u);
}
}}
+27 -4
View File
@@ -756,6 +756,13 @@ class JavaWrapperGenerator(object):
"jdouble _tmp_retval_[%(cnt)i] = {%(args)s}; " +
"env->SetDoubleArrayRegion(_da_retval_, 0, %(cnt)i, _tmp_retval_);") %
{ "cnt" : len(fields), "args" : ", ".join(["(jdouble)_retval_" + f[1] for f in fields]) } )
elif type_dict[fi.ctype]["jni_type"] == "jintArray":
fields = type_dict[fi.ctype]["jn_args"]
c_epilogue.append(
("jintArray _ia_retval_ = env->NewIntArray(%(cnt)i); " +
"jint _tmp_retval_[%(cnt)i] = {%(args)s}; " +
"env->SetIntArrayRegion(_ia_retval_, 0, %(cnt)i, _tmp_retval_);") %
{ "cnt" : len(fields), "args" : ", ".join(["(jint)_retval_" + f[1] for f in fields]) } )
if fi.classname and fi.ctype and not fi.static: # non-static class method except c-tor
# adding 'self'
jn_args.append ( ArgInfo([ "__int64", "nativeObj", "", [], "" ]) )
@@ -803,7 +810,14 @@ class JavaWrapperGenerator(object):
fields = type_dict[a.ctype].get("jn_args", ((a.ctype, ""),))
if "I" in a.out or not a.out or self.isWrapped(a.ctype): # input arg, pass by primitive fields
for f in fields:
jn_args.append ( ArgInfo([ f[0], a.name + f[1], "", [], "" ]) )
# Use array access format for Java code when jn_type is array type
if type_dict[a.ctype].get("jn_type", "").endswith("[]"):
# For Java code: convert .val[0] format to [0] format
jn_args.append ( ArgInfo([ f[0], a.name + f[1].replace(".val[", "["), "", [], "" ]) )
else:
# For non-array types, use conventional format
jn_args.append ( ArgInfo([ f[0], a.name + f[1], "", [], "" ]) )
# For C++ code: use conventional format as is
jni_args.append( ArgInfo([ f[0], a.name + normalize_field_name(f[1]), "", [], "" ]) )
if "O" in a.out and not self.isWrapped(a.ctype): # out arg, pass as double[]
jn_args.append ( ArgInfo([ "double[]", "%s_out" % a.name, "", [], "" ]) )
@@ -818,9 +832,16 @@ class JavaWrapperGenerator(object):
set_vals = []
i = 0
for f in fields:
set_vals.append( "%(n)s%(f)s = %(t)s%(n)s_out[%(i)i]" %
{"n" : a.name, "t": ("("+type_dict[f[0]]["j_type"]+")", "")[f[0]=="double"], "f" : f[1], "i" : i}
)
# Use array access format for Java code when jn_type is array type
if type_dict[a.ctype].get("jn_type", "").endswith("[]"):
# For Java code: convert .val[0] format to [0] format
set_vals.append( "%(n)s%(f)s = %(t)s%(n)s_out[%(i)i]" %
{"n" : a.name, "t": ("("+type_dict[f[0]]["j_type"]+")", "")[f[0]=="double"], "f" : f[1].replace(".val[", "["), "i" : i}
)
else:
set_vals.append( "%(n)s%(f)s = %(t)s%(n)s_out[%(i)i]" %
{"n" : a.name, "t": ("("+type_dict[f[0]]["j_type"]+")", "")[f[0]=="double"], "f" : f[1], "i" : i}
)
i += 1
j_epilogue.append( "if("+a.name+"!=null){ " + "; ".join(set_vals) + "; } ")
@@ -1015,6 +1036,8 @@ class JavaWrapperGenerator(object):
ret = "return (jlong) _retval_;"
elif type_dict[fi.ctype]["jni_type"] == "jdoubleArray":
ret = "return _da_retval_;"
elif type_dict[fi.ctype]["jni_type"] == "jintArray":
ret = "return _ia_retval_;"
elif "jni_var" in type_dict[ret_type]:
c_epilogue.append(type_dict[ret_type]["jni_var"] % {"n" : '_retval_'})
ret = f"return {type_dict[ret_type]['jni_name'] % {'n' : '_retval_'}};"
@@ -219,6 +219,32 @@ void vector_Mat_to_Mat(std::vector<cv::Mat>& v_mat, cv::Mat& mat)
}
}
void Mat_to_vector_vector_Mat(Mat& mat, std::vector< std::vector< Mat > >& vv_mat)
{
std::vector<Mat> vm;
vm.reserve( mat.rows );
Mat_to_vector_Mat(mat, vm);
for(size_t i=0; i<vm.size(); i++)
{
std::vector<Mat> vmat;
Mat_to_vector_Mat(vm[i], vmat);
vv_mat.push_back(vmat);
}
}
void vector_vector_Mat_to_Mat(std::vector< std::vector< Mat > >& vv_mat, Mat& mat)
{
std::vector<Mat> vm;
vm.reserve( vv_mat.size() );
for(size_t i=0; i<vv_mat.size(); i++)
{
Mat m;
vector_Mat_to_Mat(vv_mat[i], m);
vm.push_back(m);
}
vector_Mat_to_Mat(vm, mat);
}
void Mat_to_vector_vector_Point(Mat& mat, std::vector< std::vector< Point > >& vv_pt)
{
std::vector<Mat> vm;
@@ -50,6 +50,9 @@ void vector_Vec6f_to_Mat(std::vector<cv::Vec6f>& v_vec, cv::Mat& mat);
void Mat_to_vector_Mat(cv::Mat& mat, std::vector<cv::Mat>& v_mat);
void vector_Mat_to_Mat(std::vector<cv::Mat>& v_mat, cv::Mat& mat);
void Mat_to_vector_vector_Mat(cv::Mat& mat, std::vector< std::vector< cv::Mat > >& vv_mat);
void vector_vector_Mat_to_Mat(std::vector< std::vector< cv::Mat > >& vv_mat, cv::Mat& mat);
void Mat_to_vector_vector_char(cv::Mat& mat, std::vector< std::vector< char > >& vv_ch);
void vector_vector_char_to_Mat(std::vector< std::vector< char > >& vv_ch, cv::Mat& mat);
@@ -7,6 +7,7 @@ import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.MatOfByte;
import org.opencv.core.MatOfDMatch;
import org.opencv.core.MatOfInt;
import org.opencv.core.MatOfKeyPoint;
import org.opencv.core.MatOfPoint;
import org.opencv.core.MatOfPoint2f;
@@ -514,6 +515,41 @@ public class Converters {
}
}
// vector_vector_Mat
public static Mat vector_vector_Mat_to_Mat(List<List<Mat>> vecMats, List<Mat> mats) {
Mat res;
int lCount = (vecMats != null) ? vecMats.size() : 0;
if (lCount > 0) {
for (List<Mat> matList : vecMats) {
Mat mat = vector_Mat_to_Mat(matList);
mats.add(mat);
}
res = vector_Mat_to_Mat(mats);
} else {
res = new Mat();
}
return res;
}
public static void Mat_to_vector_vector_Mat(Mat m, List<List<Mat>> vecMats) {
if (vecMats == null)
throw new IllegalArgumentException("Output List can't be null");
if (m == null)
throw new IllegalArgumentException("Input Mat can't be null");
vecMats.clear();
List<Mat> mats = new ArrayList<Mat>(m.rows());
Mat_to_vector_Mat(m, mats);
for (Mat mi : mats) {
List<Mat> rowList = new ArrayList<Mat>(mi.rows());
Mat_to_vector_Mat(mi, rowList);
vecMats.add(rowList);
mi.release();
}
mats.clear();
}
// vector_vector_Point
public static Mat vector_vector_Point_to_Mat(List<MatOfPoint> pts, List<Mat> mats) {
Mat res;
@@ -803,4 +839,75 @@ public class Converters {
rs.add(new RotatedRect(new Point(buff[5 * i], buff[5 * i + 1]), new Size(buff[5 * i + 2], buff[5 * i + 3]), buff[5 * i + 4]));
}
}
// vector_MatShape
public static Mat vector_MatShape_to_Mat(List<MatOfInt> matOfInts) {
Mat res;
int count = (matOfInts != null) ? matOfInts.size() : 0;
if (count > 0) {
res = new Mat(count, 1, CvType.CV_32SC2);
int[] buff = new int[count * 2];
for (int i = 0; i < count; i++) {
long addr = matOfInts.get(i).nativeObj;
buff[i * 2] = (int) (addr >> 32);
buff[i * 2 + 1] = (int) (addr & 0xffffffff);
}
res.put(0, 0, buff);
} else {
res = new Mat();
}
return res;
}
public static void Mat_to_vector_MatShape(Mat m, List<MatOfInt> matOfInts) {
if (matOfInts == null)
throw new IllegalArgumentException("matOfInts == null");
int count = m.rows();
if (CvType.CV_32SC2 != m.type() || m.cols() != 1)
throw new IllegalArgumentException(
"CvType.CV_32SC2 != m.type() || m.cols()!=1\n" + m);
matOfInts.clear();
int[] buff = new int[count * 2];
m.get(0, 0, buff);
for (int i = 0; i < count; i++) {
long addr = (((long) buff[i * 2]) << 32) | (((long) buff[i * 2 + 1]) & 0xffffffffL);
matOfInts.add(MatOfInt.fromNativeAddr(addr));
}
}
// vector_vector_MatShape
public static Mat vector_vector_MatShape_to_Mat(List<List<MatOfInt>> vecMatOfInts, List<Mat> mats) {
Mat res;
int lCount = (vecMatOfInts != null) ? vecMatOfInts.size() : 0;
if (lCount > 0) {
for (List<MatOfInt> matList : vecMatOfInts) {
Mat mat = vector_MatShape_to_Mat(matList);
mats.add(mat);
}
res = vector_Mat_to_Mat(mats);
} else {
res = new Mat();
}
return res;
}
public static void Mat_to_vector_vector_MatShape(Mat m, List<List<MatOfInt>> vecMatOfInts) {
if (vecMatOfInts == null)
throw new IllegalArgumentException("Output List can't be null");
if (m == null)
throw new IllegalArgumentException("Input Mat can't be null");
vecMatOfInts.clear();
List<Mat> mats = new ArrayList<Mat>(m.rows());
Mat_to_vector_Mat(m, mats);
for (Mat mi : mats) {
List<MatOfInt> rowList = new ArrayList<MatOfInt>(mi.rows());
Mat_to_vector_MatShape(mi, rowList);
vecMatOfInts.add(rowList);
mi.release();
}
mats.clear();
}
}
+9 -2
View File
@@ -68,13 +68,20 @@ if(DEFINED OPENCV_PYTHON_INSTALL_PATH)
endif()
set(CMAKE_PYTHON_BINARIES_PATH "${CMAKE_PYTHON_BINARIES_INSTALL_PATH}")
if (WIN32 AND HAVE_CUDA)
set(_cuda_bin_dir "bin")
if (ENABLE_CUDA_FIRST_CLASS_LANGUAGE)
if (DEFINED CUDAToolkit_LIBRARY_ROOT)
list(APPEND CMAKE_PYTHON_BINARIES_PATH "os.path.join(os.getenv('CUDA_PATH', '${CUDAToolkit_LIBRARY_ROOT}'), 'bin')")
if(DEFINED CUDAToolkit_VERSION_MAJOR AND CUDAToolkit_VERSION_MAJOR GREATER_EQUAL 13)
set(_cuda_bin_dir "bin/x64")
endif()
list(APPEND CMAKE_PYTHON_BINARIES_PATH "os.path.join(os.getenv('CUDA_PATH', '${CUDAToolkit_LIBRARY_ROOT}'), '${_cuda_bin_dir}')")
endif()
else()
if (DEFINED CUDA_TOOLKIT_ROOT_DIR)
list(APPEND CMAKE_PYTHON_BINARIES_PATH "os.path.join(os.getenv('CUDA_PATH', '${CUDA_TOOLKIT_ROOT_DIR}'), 'bin')")
if(DEFINED CUDA_VERSION_MAJOR AND CUDA_VERSION_MAJOR GREATER_EQUAL 13)
set(_cuda_bin_dir "bin/x64")
endif()
list(APPEND CMAKE_PYTHON_BINARIES_PATH "os.path.join(os.getenv('CUDA_PATH', '${CUDA_TOOLKIT_ROOT_DIR}'), '${_cuda_bin_dir}')")
endif()
endif()
endif()
+3
View File
@@ -133,6 +133,9 @@ static PyGetSetDef pyopencv_${name}_getseters[] =
static PyMethodDef pyopencv_${name}_methods[] =
{
#ifdef PYOPENCV_EXTRA_METHODS_${name}
PYOPENCV_EXTRA_METHODS_${name}
#endif
${methods_inits}
{NULL, NULL}
};
+15
View File
@@ -70,6 +70,7 @@ class cuda_test(NewOpenCVTests):
self.assertTrue(cuMat.step == 0)
self.assertTrue(cuMat.size() == (0, 0))
@unittest.skip("failed test")
def test_cuda_convertTo(self):
# setup
npMat_8UC4 = (np.random.random((128, 128, 4)) * 255).astype(np.uint8)
@@ -105,6 +106,7 @@ class cuda_test(NewOpenCVTests):
stream.waitForCompletion()
self.assertTrue(np.array_equal(npMat_32FC4, npMat_32FC4_out))
@unittest.skip("failed test")
def test_cuda_copyTo(self):
# setup
npMat_8UC4 = (np.random.random((128, 128, 4)) * 255).astype(np.uint8)
@@ -143,5 +145,18 @@ class cuda_test(NewOpenCVTests):
self.assertEqual(True, hasattr(cv.cuda, 'fastNlMeansDenoisingColored'))
self.assertEqual(True, hasattr(cv.cuda, 'nonLocalMeans'))
def test_dlpack_GpuMat(self):
for dtype in [np.int8, np.uint8, np.int16, np.uint16, np.float16, np.int32, np.float32, np.float64]:
for channels in [2, 3, 5]:
ref = (np.random.random((64, 128, channels)) * 255).astype(dtype)
src = cv.cuda_GpuMat()
src.upload(ref)
dst = cv.cuda_GpuMat.from_dlpack(src)
test = dst.download()
equal = np.array_equal(ref, test)
if not equal:
print(f"Failed test with dtype {dtype} and {channels} channels")
self.assertTrue(equal)
if __name__ == '__main__':
NewOpenCVTests.bootstrap()
+9 -1
View File
@@ -711,7 +711,15 @@ enum VideoCaptureOBSensorProperties{
CAP_PROP_OBSENSOR_DEPTH_POS_MSEC=26006,
CAP_PROP_OBSENSOR_DEPTH_WIDTH=26007,
CAP_PROP_OBSENSOR_DEPTH_HEIGHT=26008,
CAP_PROP_OBSENSOR_DEPTH_FPS=26009
CAP_PROP_OBSENSOR_DEPTH_FPS=26009,
CAP_PROP_OBSENSOR_COLOR_DISTORTION_K1=26010,
CAP_PROP_OBSENSOR_COLOR_DISTORTION_K2=26011,
CAP_PROP_OBSENSOR_COLOR_DISTORTION_K3=26012,
CAP_PROP_OBSENSOR_COLOR_DISTORTION_K4=26013,
CAP_PROP_OBSENSOR_COLOR_DISTORTION_K5=26014,
CAP_PROP_OBSENSOR_COLOR_DISTORTION_K6=26015,
CAP_PROP_OBSENSOR_COLOR_DISTORTION_P1=26016,
CAP_PROP_OBSENSOR_COLOR_DISTORTION_P2=26017
};
//! @} OBSENSOR
+14
View File
@@ -685,7 +685,10 @@ void CvCapture_FFMPEG::close()
if( video_st )
{
#ifdef CV_FFMPEG_CODECPAR
// avcodec_close removed in FFmpeg release 8.0
# if (LIBAVCODEC_BUILD < CALC_FFMPEG_VERSION(62, 11, 100))
avcodec_close( context );
# endif
#endif
video_st = NULL;
}
@@ -2005,7 +2008,18 @@ void CvCapture_FFMPEG::get_rotation_angle()
rotation_angle = 0;
#if LIBAVFORMAT_BUILD >= CALC_FFMPEG_VERSION(57, 68, 100)
const uint8_t *data = 0;
// av_stream_get_side_data removed in FFmpeg release 8.0
# if (LIBAVCODEC_BUILD < CALC_FFMPEG_VERSION(62, 11, 100))
data = av_stream_get_side_data(video_st, AV_PKT_DATA_DISPLAYMATRIX, NULL);
# else
AVPacketSideData* sd = video_st->codecpar->coded_side_data;
int nb_sd = video_st->codecpar->nb_coded_side_data;
if (sd && nb_sd > 0)
{
const AVPacketSideData* mtx = av_packet_side_data_get(sd, nb_sd, AV_PKT_DATA_DISPLAYMATRIX);
data = mtx->data;
}
# endif
if (data)
{
rotation_angle = -cvRound(av_display_rotation_get((const int32_t*)data));
+42 -8
View File
@@ -84,10 +84,19 @@ VideoCapture_obsensor::VideoCapture_obsensor(int, const cv::VideoCaptureParamete
});
auto param = pipe->getCameraParam();
camParam.p1[0] = param.rgbIntrinsic.fx;
camParam.p1[1] = param.rgbIntrinsic.fy;
camParam.p1[2] = param.rgbIntrinsic.cx;
camParam.p1[3] = param.rgbIntrinsic.cy;
camParam.intrinsicColor[0] = param.rgbIntrinsic.fx;
camParam.intrinsicColor[1] = param.rgbIntrinsic.fy;
camParam.intrinsicColor[2] = param.rgbIntrinsic.cx;
camParam.intrinsicColor[3] = param.rgbIntrinsic.cy;
camParam.distortionColor[0] = param.depthDistortion.k1;
camParam.distortionColor[1] = param.depthDistortion.k2;
camParam.distortionColor[2] = param.depthDistortion.k3;
camParam.distortionColor[3] = param.depthDistortion.k4;
camParam.distortionColor[4] = param.depthDistortion.k5;
camParam.distortionColor[5] = param.depthDistortion.k6;
camParam.distortionColor[6] = param.depthDistortion.p1;
camParam.distortionColor[7] = param.depthDistortion.p2;
}
VideoCapture_obsensor::~VideoCapture_obsensor(){
@@ -101,17 +110,42 @@ double VideoCapture_obsensor::getProperty(int propIdx) const
switch (propIdx)
{
case CAP_PROP_OBSENSOR_INTRINSIC_FX:
rst = camParam.p1[0];
rst = camParam.intrinsicColor[0];
break;
case CAP_PROP_OBSENSOR_INTRINSIC_FY:
rst = camParam.p1[1];
rst = camParam.intrinsicColor[1];
break;
case CAP_PROP_OBSENSOR_INTRINSIC_CX:
rst = camParam.p1[2];
rst = camParam.intrinsicColor[2];
break;
case CAP_PROP_OBSENSOR_INTRINSIC_CY:
rst = camParam.p1[3];
rst = camParam.intrinsicColor[3];
break;
case CAP_PROP_OBSENSOR_COLOR_DISTORTION_K1:
rst = camParam.distortionColor[0];
break;
case CAP_PROP_OBSENSOR_COLOR_DISTORTION_K2:
rst = camParam.distortionColor[1];
break;
case CAP_PROP_OBSENSOR_COLOR_DISTORTION_K3:
rst = camParam.distortionColor[2];
break;
case CAP_PROP_OBSENSOR_COLOR_DISTORTION_K4:
rst = camParam.distortionColor[3];
break;
case CAP_PROP_OBSENSOR_COLOR_DISTORTION_K5:
rst = camParam.distortionColor[4];
break;
case CAP_PROP_OBSENSOR_COLOR_DISTORTION_K6:
rst = camParam.distortionColor[5];
break;
case CAP_PROP_OBSENSOR_COLOR_DISTORTION_P1:
rst = camParam.distortionColor[6];
break;
case CAP_PROP_OBSENSOR_COLOR_DISTORTION_P2:
rst = camParam.distortionColor[7];
break;
case CAP_PROP_POS_MSEC:
case CAP_PROP_OBSENSOR_RGB_POS_MSEC:
if (grabbedColorFrame)
@@ -33,14 +33,8 @@ namespace cv
struct CameraParam
{
float p0[4];
float p1[4];
float p2[9];
float p3[3];
float p4[5];
float p5[5];
uint32_t p6[2];
uint32_t p7[2];
float intrinsicColor[4];
float distortionColor[8];
};
class VideoCapture_obsensor : public IVideoCapture