<p>文档在这方面有点模糊,需要对这两个源以及文档进行一些挖掘,以正确地解释正在发生的事情。在</p>
<p>首先是标量。在数据类型的上下文中,我们有一个<code>cv::Scalar</code>,它实际上是模板<a href="https://docs.opencv.org/3.4.1/d1/da0/classcv_1_1Scalar__.html" rel="nofollow noreferrer">^{<cd2>}</a>的专门化。它表示一个4元向量,并从<a href="https://docs.opencv.org/3.4.1/d6/dcf/classcv_1_1Vec.html" rel="nofollow noreferrer">^{<cd3>}</a>一个表示固定大小向量的模板派生而来,这又是<a href="https://docs.opencv.org/3.4.1/de/de1/classcv_1_1Matx.html" rel="nofollow noreferrer">^{<cd4>}</a>的一个特例,一个表示小的固定大小矩阵的类。在</p>
<p>这是标量数据类型,但是在<code>bitwise_and</code>(以及相关函数)的上下文中,标量和非标量的概念要宽松得多—实际上函数并不知道给它提供了一个<code>cv::Scalar</code>的实例。在</p>
<p>如果你看一下<a href="https://docs.opencv.org/3.4.1/d2/de8/group__core__array.html#ga60b4d04b251ba5eb1392c34425497e14" rel="nofollow noreferrer">signature of the function</a>,你会注意到输入是<a href="https://docs.opencv.org/3.4.1/d4/d32/classcv_1_1__InputArray.html" rel="nofollow noreferrer">^{<cd7>}</a>s。因此输入总是</strong>数组,但它们的某些属性可能不同(种类、元素类型、大小、维度等)。在</p>
<p>特定的<a href="https://github.com/opencv/opencv/blob/69103a9fab13d81c41f37806a37ff56c37dae204/modules/core/src/arithm.cpp#L183" rel="nofollow noreferrer">check in the code</a>验证大小、类型和种类是否匹配。如果是这样(在您的场景中也是这样),操作<code>dst(I) = src1(I) ^ src2(I) if mask(I) != 0</code>将运行。在</p>
<p>否则,它将检查其中一个输入数组是否表示标量。它使用函数<a href="https://github.com/opencv/opencv/blob/17233c687e2d51010dab2587f2532a460ccdb4b6/modules/core/src/precomp.hpp#L230" rel="nofollow noreferrer">^{<cd9>}</a>来完成此操作,return语句说明了其中的大部分内容:</p>
<pre><code>return sz == Size(1, 1)
|| sz == Size(1, cn) || sz == Size(cn, 1)
|| (sz == Size(1, 4) && sc.type() == CV_64F && cn <= 4);
</code></pre>
<ul>
<li>任何尺寸为1 x 1的东西</li>
<li>任何大小为1x <code>cn</code>或<code>cn</code>x1(其中<code>cn</code>是另一个输入数组的通道数)。在</li>
<li>任何大小为1 x 4且元素都是64位浮点值,但仅当另一个输入数组有4个或更少的通道时。在</li>
</ul>
<p>最后一个例子既匹配默认的<code>cv::Scalar</code>(正如我们前面看到的,它是<code>cv::Matx<double,4,1></code>),也匹配<code>cv::Mat(4,1,CF_64F)</code>。在</p>
<hr/>
<p>作为中场休息,让我们来测试一下上面所学的内容。在</p>
<p>代码:</p>
^{pr2}$
<p>输出:</p>
<pre><code>[1;
0;
0;
0]
size : [1 x 4]
type==CV_64FC1 : yes
</code></pre>
<hr/>
<P>已经覆盖了底层C++接口,让我们看看Python绑定。为Python API创建包装器的生成器相当复杂,所以让我们跳过这一步,而是检查它为<code>bitwise_and</code>生成的内容的相关片段:</p>
<pre><code> 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();
</code></pre>
<p>我们可以看到对应于<code>InputArray</code>或<code>OutputArray</code>的参数被加载到<code>cv::Mat</code>实例中。让我们看看<a href="https://github.com/opencv/opencv/blob/17233c687e2d51010dab2587f2532a460ccdb4b6/modules/python/src2/cv2.cpp#L224" rel="nofollow noreferrer">^{<cd20>}</a>中与您的场景对应的部分:</p>
<pre><code>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;
}
</code></pre>
<p>包含转换为double的输入整数的<code>cv::Mat(4, 1, CV_64F)</code>(回想一下,这符合标量测试),其余3个位置用零填充。在</p>
<p>由于没有提供目的地,因此将自动分配一个与输入大小和类型相同的<code>Mat</code>。返回Python时,<code>Mat</code>将成为numpy数组。在</p>