在 OpenCV 中实现复值矩阵方程
Posted
技术标签:
【中文标题】在 OpenCV 中实现复值矩阵方程【英文标题】:Implementing complex-valued matrix equation in OpenCV 【发布时间】:2012-11-28 14:12:56 【问题描述】:我正在尝试在 OpenCV 中实现复数值矩阵方程。我已经在 MATLAB 中进行了原型设计,效果很好。从方程开始(精确的 MATLAB 实现):
kernel = exp(1i .* k .* Circ3D) .* z ./ (1i .* lambda .* Circ3D .* Circ3D)
其中
1i = complex number
k = constant (float)
Circ3D = real-valued matrix of known size
lambda = constant (float)
.* = element-wise multiplication
./ = element-wise division
结果是一个复值矩阵。我成功地将必要的 Circ3D 矩阵生成为 CV_32F,但是乘以复数 i 给我带来了麻烦。从 OpenCV 文档中,我了解到复杂矩阵只是一个两通道矩阵 (CV_32FC2)。
真正的麻烦在于如何定义 i。我尝试了几个选项,其中将 i 定义为
cv::Vec2d complex = cv::Vec2d(0,1);
然后乘以矩阵
kernel = complex * Circ3D
但这不起作用(虽然我没想到会这样)。我怀疑我需要对 std::complex 做点什么,但我不知道是什么 (http://docs.opencv.org/modules/core/doc/basic_structures.html)。
提前感谢您的帮助。
编辑:在写完这篇文章后,我确实取得了一些进展,将 i 定义如下:
std::complex<float> complex(0,1)
然后我可以按如下方式分配复杂值:
kernel.at<std::complex<float>>(i,j) = cv::exp(complex * k * Circ3D.at<float>(i,j)) * ...
z / (complex * lambda * pow(Circ3D.at<float>(i,j),2));
但是,这在循环中工作,这使得过程非常缓慢。有什么方法可以一次性完成吗?
【问题讨论】:
【参考方案1】:还有函数mulSpectrums,它可以让你对复杂矩阵进行元素乘法。因此,如果 K 是您的内核矩阵,而 I 是一些复杂矩阵,即 CV_32FC2(浮点两通道),您可以执行以下操作来计算元素乘法,
// Make K a complex matrix
cv::Mat Ktmp[] = cv::Mat_<float>(K), cv::Mat::zeros(K.size(), CV_32FC1);
cv::Mat Kc;
cv::merge(Ktmp,2,Kc);
// Do matrix multiplication
cv::mulSpectrums(Kc,I,I,0);
【讨论】:
除法有吗?【参考方案2】:OpenCV 将std::complex
视为简单的一对数字(参见example in the documentation)。没有应用关于算术运算的特殊规则。你可以通过直接乘以std::complex
来克服这个问题。所以基本上,这很简单:您要么选择自动复数算术(就像你现在所做的那样),要么选择自动矢量化(在矩阵上使用 OpenCV 函数时)。
我认为,在您的情况下,您应该自己进行所有复杂的算术运算。将复数值矩阵Cai + b
存储为两个矩阵Aa
和Bb
。实现求幂by yourself。标量的乘法和加法应该不是问题。
【讨论】:
抱歉回复晚了。我最终听从了你的建议。使用欧拉公式实现了复幂运算。这非常容易,因为我先验地知道 k 和 Circ3D 是真实的,所以方程只需要重写一次并实现。 供将来参考:我创建了一个通用 cv::Mat complexMul(cv::Mat A, cv::Mat B) 函数,该函数通过拆分 ( cv::split) 将两个矩阵 A = A1 + A2*i 和 B = B1 + B2*i 分成实数 (A1, B1) 和复数 (A2, B2) 部分,然后计算 C = A.*B = (A1 + A2*i)(B1 + B2*i) 通过分别计算 C1 = (A1.*B1 - A2.*B2) 和 C2 = (A1.*B2 + A2.*B1) 并使用 cv::merge 创建C = C1 + C2 * i。请注意,i=sqrt(-1) 和 .* 表示逐元素乘法。 *** 不允许我将这两个小 cmets 合二为一,因为它变得太长了?!这是什么,推特? ;) 我猜,你做对了。很高兴我的回答有帮助。感谢您接受它。以上是关于在 OpenCV 中实现复值矩阵方程的主要内容,如果未能解决你的问题,请参考以下文章
如何在 C++ 中将 OpenCV 2D 矩阵转换为 1D 数组?
OpenCV 中的矩阵乘法 - 结合 cv::Mat 和 cv::Scalar 对象