【问题标题】:Parameters of OpenCV Mat::MulOpenCV Mat::Mul 的参数
【发布时间】:2017-11-27 06:54:12
【问题描述】:

最近我正在将 C++ 代码移植到 Java。发现下面的C++代码可以编译,但是对应的Java代码说有问题。

  • C++ 代码(编译)

    void NormEveryRow(Mat &var1) {
        double normSum;
        int rowNum = var1.rows;
        for(size_t i=0; i<rowNum; ++i) {
            Mat Mi2 = var1.row(i);
            normSum = norm(Mi2, NORM_L2);
            Mi2 = Mi2.mul(1/normSum);
            var1.row(i) = Mi2;
        }
    }
    
  • Java 代码(错误)

    protected static void normEveryRow(Mat var1) {
        double normSum;
        int rowNum = var1.rows();
        for(int i=0; i<rowNum; ++i) {
            Mat Mi2 = var1.row(i);
            normSum = norm(Mi2, NORM_L2);
            Mi2 = Mi2.mul(1/normSum); // it expects Mat as a parameter
            var1.row(i) = Mi2; // 'variable expected' error
        }
    }
    

根据OpenCV documentation (link here)mat.mul() 接受inputArray 作为其参数。因此,当第一个 C++ 代码编译时,我感到很惊讶。我猜 C++ 会以某种方式自动将 double 转换为 inputArray 兼容格式。

您能帮我理解 (1) 为什么 C++ 代码可以编译,以及 (2) 如何制作没有错误的等效 Java 代码吗? (我认为Core.multiply(Mi2, new Scalar(1/normSum), var1.row(i)); 可能有效,但我不确定。)

提前致谢!

【问题讨论】:

  • 错误代码是什么意思?
  • (1) Mat 中的 mul (org.opencv.core.Mat) 不能应用于 (double) (2) 预期变量
  • 在 c++ 中它能够接受一个标量(inputArray 可以转换成很多东西,如果它是需要的类型,它会在运行时检查),但是 in java 它只接受 Mat。也许function multiply 有帮助,因为它也接受一个标量,并且它是相同的操作(元素明智的乘法)。同样在 c++ 中(在 java 中不确定)你可以做 Mi2 = Mi2 * (1/normSum);或者直接,Mi2 = Mi2 / nurmSum;

标签: java c++ opencv


【解决方案1】:

试试

Mat Mi2 = var1.row(i);
Mat result = new Mat();
normSum = norm(Mi2, NORM_L2);
//advice: remember to avoid or not if normSum == 0.0
Scalar scalar = new Scalar(1.0/normSum);
Core.multiply(Mi2, scalar, result);
var1.row(i) = result;

乘法还有其他重载形式。见他们here

编辑:

是的,最后一行在 Java 中不起作用。由于 row(i) 只返回位置 i 处原始 Mat 数据的别名,因此您应该使用下面稍作修改的代码:

Mat Mi2 = var1.row(i);
normSum = norm(Mi2, NORM_L2);
Scalar scalar = new Scalar(1.0/normSum);
Core.multiply(Mi2, scalar, Mi2);

【讨论】:

  • 谢谢!我可以再问一点吗?我试图缩短 for 循环中的代码,例如: normSum = norm(var1.row(i), NORM_L2); Core.multiply(var1.row(i), new Scalar(1/normSum), var1.row(i));与 C++ 代码相比,它似乎工作但非常慢。这是一个合法的代码,是否有任何缺陷使它变慢?
  • 声明 Mi2 局部变量比调用 var1.row(i) 好几次。这是因为 javac 实际上会创建一个变量来保存您对 var1.row(i) 的调用,即使您没有显式声明它们。此外,对象 var1 内的调用查找 row(i) 将运行多次而不是仅运行一次。因此,第一次编写的代码应该比最后一个代码执行得更好。
  • 我明白了。我在想这样一种方式,更短的代码可能运行得更快,这并不总是正确的。感谢您的清晰解释!
  • 哦,对不起,还有一个问题。在最后一行,var1.row(i) = result;,Android Studio 说“'variable expected' error”。这种情况下是不是禁止直接给var1.row(i)赋值?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-07-21
  • 1970-01-01
  • 1970-01-01
  • 2015-04-30
  • 2014-12-18
  • 1970-01-01
  • 2014-10-21
相关资源
最近更新 更多