为什么cv2.bitwise_和opencvpython函数在单个标量值上返回四元素数组

2024-09-30 14:27:50 发布

您现在位置:Python中文网/ 问答频道 /正文

我试图理解opencvpython的cv2.bitwise_and函数。所以我试着:

import cv2
cv2.bitwise_and(1,1)

以上代码返回

^{pr2}$

我不明白它为什么会返回这个。在

Documentation表示:

dst(I) = src1(I) ^ src2(I) if mask(I) != 0

根据这个输出应该是单值1。我哪里出错了?在


Tags: and函数代码importifdocumentationmaskcv2
2条回答

文档在这方面有点模糊,需要对这两个源以及文档进行一些挖掘,以正确地解释正在发生的事情。在

首先是标量。在数据类型的上下文中,我们有一个cv::Scalar,它实际上是模板^{}的专门化。它表示一个4元向量,并从^{}一个表示固定大小向量的模板派生而来,这又是^{}的一个特例,一个表示小的固定大小矩阵的类。在

这是标量数据类型,但是在bitwise_and(以及相关函数)的上下文中,标量和非标量的概念要宽松得多—实际上函数并不知道给它提供了一个cv::Scalar的实例。在

如果你看一下signature of the function,你会注意到输入是^{}s。因此输入总是数组,但它们的某些属性可能不同(种类、元素类型、大小、维度等)。在

特定的check in the code验证大小、类型和种类是否匹配。如果是这样(在您的场景中也是这样),操作dst(I) = src1(I) ^ src2(I) if mask(I) != 0将运行。在

否则,它将检查其中一个输入数组是否表示标量。它使用函数^{}来完成此操作,return语句说明了其中的大部分内容:

return sz == Size(1, 1)
    || sz == Size(1, cn) || sz == Size(cn, 1)
    || (sz == Size(1, 4) && sc.type() == CV_64F && cn <= 4);
  • 任何尺寸为1 x 1的东西
  • 任何大小为1x cncnx1(其中cn是另一个输入数组的通道数)。在
  • 任何大小为1 x 4且元素都是64位浮点值,但仅当另一个输入数组有4个或更少的通道时。在

最后一个例子既匹配默认的cv::Scalar(正如我们前面看到的,它是cv::Matx<double,4,1>),也匹配cv::Mat(4,1,CF_64F)。在


作为中场休息,让我们来测试一下上面所学的内容。在

代码:

^{pr2}$

输出:

[1;
 0;
 0;
 0]
size : [1 x 4]
type==CV_64FC1 : yes

已经覆盖了底层C++接口,让我们看看Python绑定。为Python API创建包装器的生成器相当复杂,所以让我们跳过这一步,而是检查它为bitwise_and生成的内容的相关片段:

    using namespace cv;

    {
    PyObject* pyobj_src1 = NULL;
    Mat src1;
    PyObject* pyobj_src2 = NULL;
    Mat src2;
    PyObject* pyobj_dst = NULL;
    Mat dst;
    PyObject* pyobj_mask = NULL;
    Mat mask;

    const char* keywords[] = { "src1", "src2", "dst", "mask", NULL };
    if( PyArg_ParseTupleAndKeywords(args, kw, "OO|OO:bitwise_and", (char**)keywords, &pyobj_src1, &pyobj_src2, &pyobj_dst, &pyobj_mask) &&
        pyopencv_to(pyobj_src1, src1, ArgInfo("src1", 0)) &&
        pyopencv_to(pyobj_src2, src2, ArgInfo("src2", 0)) &&
        pyopencv_to(pyobj_dst, dst, ArgInfo("dst", 1)) &&
        pyopencv_to(pyobj_mask, mask, ArgInfo("mask", 0)) )
    {
        ERRWRAP2(cv::bitwise_and(src1, src2, dst, mask));
        return pyopencv_from(dst);
    }
    }
    PyErr_Clear();

我们可以看到对应于InputArrayOutputArray的参数被加载到cv::Mat实例中。让我们看看^{}中与您的场景对应的部分:

if( PyInt_Check(o) )
{
    double v[] = {static_cast<double>(PyInt_AsLong((PyObject*)o)), 0., 0., 0.};
    m = Mat(4, 1, CV_64F, v).clone();
    return true;
}

包含转换为double的输入整数的cv::Mat(4, 1, CV_64F)(回想一下,这符合标量测试),其余3个位置用零填充。在

由于没有提供目的地,因此将自动分配一个与输入大小和类型相同的Mat。返回Python时,Mat将成为numpy数组。在

文档清楚地指出,如果输入是两个大小相同的数组,那么函数将执行dst(I) = src1(I) ^ src2(I) if mask(I) != 0操作。在

所以试试看:

import numpy as np  # Opecv works with numpy arrays
import cv2

a = np.uint8([1])
b = np.uint8([1])
cv2.bitwise_and(a, b)

该代码返回:

^{pr2}$

这是一个包含数字1的一维数组。在

文档还提到可以使用数组和标量来完成操作,但不能使用两个标量,因此输入cv2.bitwise_and(1,1)是不正确的。在

相关问题 更多 >