mirror of
https://github.com/opencv/opencv.git
synced 2026-09-13 05:42:51 -05:00
map 64bit int anf bfloat16
This commit is contained in:
@@ -127,25 +127,20 @@ bool pyopencv_to(PyObject* o, Mat& m, const ArgInfo& info)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool needcopy = false, needcast = false;
|
||||
int typenum = PyArray_TYPE(oarr), new_typenum = typenum;
|
||||
bool needcopy = false;
|
||||
int typenum = PyArray_TYPE(oarr);
|
||||
int type = numpyTypeToCvDepth(typenum);
|
||||
|
||||
if( type < 0 )
|
||||
{
|
||||
if( typenum == NPY_INT64 || typenum == NPY_UINT64 || typenum == NPY_LONG )
|
||||
{
|
||||
needcopy = needcast = true;
|
||||
new_typenum = NPY_INT;
|
||||
type = CV_32S;
|
||||
}
|
||||
else
|
||||
{
|
||||
const std::string dtype_name = getArrayTypeName(oarr);
|
||||
failmsg("%s data type = %s is not supported", info.name,
|
||||
dtype_name.c_str());
|
||||
return false;
|
||||
}
|
||||
// 64-bit integers used to be force-cast to CV_32S here, which silently
|
||||
// truncated any value outside the int32 range. They now map to
|
||||
// CV_64S/CV_64U in numpyTypeToCvDepth(), so reaching this point means
|
||||
// the dtype genuinely has no cv::Mat equivalent.
|
||||
const std::string dtype_name = getArrayTypeName(oarr);
|
||||
failmsg("%s data type = %s is not supported", info.name,
|
||||
dtype_name.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifndef CV_MAX_DIM
|
||||
@@ -220,14 +215,8 @@ bool pyopencv_to(PyObject* o, Mat& m, const ArgInfo& info)
|
||||
return false;
|
||||
}
|
||||
|
||||
if( needcast ) {
|
||||
o = PyArray_Cast(oarr, new_typenum);
|
||||
oarr = (PyArrayObject*) o;
|
||||
}
|
||||
else {
|
||||
oarr = PyArray_GETCONTIGUOUS(oarr);
|
||||
o = (PyObject*) oarr;
|
||||
}
|
||||
oarr = PyArray_GETCONTIGUOUS(oarr);
|
||||
o = (PyObject*) oarr;
|
||||
|
||||
_strides = PyArray_STRIDES(oarr);
|
||||
}
|
||||
@@ -315,6 +304,16 @@ bool pyopencv_to(PyObject* o, Mat& m, const ArgInfo& info)
|
||||
template<>
|
||||
PyObject* pyopencv_from(const cv::Mat& m)
|
||||
{
|
||||
// NumPy has no bfloat16 dtype, so CV_16BF is widened to float32 (lossless).
|
||||
// The values must actually be converted, not just relabelled: cvDepthToNumpyType()
|
||||
// reports NPY_FLOAT for CV_16BF, and handing a 2-byte-per-element buffer to the
|
||||
// NumPy allocator under a 4-byte dtype would misinterpret the payload.
|
||||
if( m.depth() == CV_16BF )
|
||||
{
|
||||
cv::Mat m32f;
|
||||
ERRWRAP2(m.convertTo(m32f, CV_32F));
|
||||
return pyopencv_from(m32f); // m32f is CV_32F, so this recurses at most once
|
||||
}
|
||||
if( m.empty() )
|
||||
{
|
||||
// empty() also catches a live buffer with a zero-length dim: return an empty array, not None.
|
||||
|
||||
@@ -34,6 +34,14 @@ UMatData* NumpyAllocator::allocate(int dims0, const int* sizes, int type, void*
|
||||
|
||||
int depth = CV_MAT_DEPTH(type);
|
||||
int cn = CV_MAT_CN(type);
|
||||
// cvDepthToNumpyType() widens CV_16BF to NPY_FLOAT for export, which is only
|
||||
// valid when the values are converted (see pyopencv_from). Backing a CV_16BF
|
||||
// Mat with a float32 buffer here would instead pair a 2-byte element step with
|
||||
// 4-byte NumPy strides and silently corrupt the data, so refuse it outright.
|
||||
if( depth == CV_16BF )
|
||||
CV_Error(Error::StsNotImplemented,
|
||||
"CV_16BF (bfloat16) arrays cannot be allocated through the NumPy allocator: "
|
||||
"NumPy has no bfloat16 dtype");
|
||||
int typenum = cvDepthToNumpyType(depth);
|
||||
int i, dims = dims0;
|
||||
cv::AutoBuffer<npy_intp> _sizes(dims + 1);
|
||||
|
||||
@@ -8,21 +8,56 @@ cv::TLSData<std::vector<std::string> > conversionErrorsTLS;
|
||||
|
||||
int cvDepthToNumpyType(int depth)
|
||||
{
|
||||
const int f = (int)(sizeof(size_t)/8);
|
||||
return depth == CV_8U ? NPY_UBYTE : depth == CV_8S ? NPY_BYTE :
|
||||
depth == CV_16U ? NPY_USHORT : depth == CV_16S ? NPY_SHORT :
|
||||
depth == CV_32U ? NPY_UINT32 : depth == CV_32S ? NPY_INT32 : depth == CV_64S ? NPY_INT64 :
|
||||
depth == CV_32F ? NPY_FLOAT : depth == CV_64F ? NPY_DOUBLE : depth == CV_16F ? NPY_HALF :
|
||||
depth == CV_Bool ? NPY_BOOL : f*NPY_ULONGLONG + (f^1)*NPY_UINT;
|
||||
switch (depth)
|
||||
{
|
||||
case CV_8U: return NPY_UBYTE;
|
||||
case CV_8S: return NPY_BYTE;
|
||||
case CV_16U: return NPY_USHORT;
|
||||
case CV_16S: return NPY_SHORT;
|
||||
case CV_32U: return NPY_UINT32;
|
||||
case CV_32S: return NPY_INT32;
|
||||
case CV_64U: return NPY_UINT64;
|
||||
case CV_64S: return NPY_INT64;
|
||||
case CV_32F: return NPY_FLOAT;
|
||||
case CV_64F: return NPY_DOUBLE;
|
||||
case CV_16F: return NPY_HALF;
|
||||
// NumPy has no bfloat16 dtype, so CV_16BF is exported as float32 (a lossless
|
||||
// widening). pyopencv_from() performs the value conversion; without it the
|
||||
// 2-byte payload would be reinterpreted as 4-byte elements.
|
||||
case CV_16BF: return NPY_FLOAT;
|
||||
case CV_Bool: return NPY_BOOL;
|
||||
default:
|
||||
// Deliberately an error rather than a fallback: silently mapping an
|
||||
// unknown depth to some default dtype mislabels the payload.
|
||||
CV_Error(cv::Error::StsNotImplemented,
|
||||
cv::format("Mat depth %d has no corresponding NumPy dtype", depth));
|
||||
}
|
||||
}
|
||||
|
||||
int numpyTypeToCvDepth(int typenum)
|
||||
{
|
||||
return typenum == NPY_UBYTE ? CV_8U : typenum == NPY_BYTE ? CV_8S :
|
||||
typenum == NPY_USHORT ? CV_16U : typenum == NPY_SHORT ? CV_16S :
|
||||
typenum == NPY_INT ? CV_32S : typenum == NPY_UINT32 ? CV_32U : typenum == NPY_INT32 ? CV_32S :
|
||||
typenum == NPY_HALF ? CV_16F : typenum == NPY_FLOAT ? CV_32F : typenum == NPY_DOUBLE ? CV_64F :
|
||||
typenum == NPY_BOOL ? CV_Bool : -1;
|
||||
// Only canonical NPY_* values may appear as case labels: the fixed-width
|
||||
// aliases (NPY_INT32, NPY_INT64, ...) expand to these and would collide.
|
||||
switch (typenum)
|
||||
{
|
||||
case NPY_UBYTE: return CV_8U;
|
||||
case NPY_BYTE: return CV_8S;
|
||||
case NPY_USHORT: return CV_16U;
|
||||
case NPY_SHORT: return CV_16S;
|
||||
case NPY_UINT: return CV_32U;
|
||||
case NPY_INT: return CV_32S;
|
||||
case NPY_ULONGLONG: return CV_64U;
|
||||
case NPY_LONGLONG: return CV_64S;
|
||||
// 'long' is 64-bit on LP64 (Linux/macOS) but 32-bit on LLP64 (Windows),
|
||||
// so this must be decided by size rather than by name.
|
||||
case NPY_ULONG: return NPY_SIZEOF_LONG == 8 ? CV_64U : CV_32U;
|
||||
case NPY_LONG: return NPY_SIZEOF_LONG == 8 ? CV_64S : CV_32S;
|
||||
case NPY_HALF: return CV_16F;
|
||||
case NPY_FLOAT: return CV_32F;
|
||||
case NPY_DOUBLE: return CV_64F;
|
||||
case NPY_BOOL: return CV_Bool;
|
||||
default: return -1;
|
||||
}
|
||||
}
|
||||
|
||||
using namespace cv;
|
||||
|
||||
Reference in New Issue
Block a user