Using Eigen Array-of-Arrays for RGB images
Asked Answered
P

3

8

I'm trying to use the Eigen library for some simple image processing. I'd use Array3f for an RGB triple and an Array to hold an RGB image. This seems to work partially, and I can conveniently do component-wise addition, multiplication and division of images. But certain operations (specifically involving subtraction or negation) seem to create compile errors. Here is a minimal example:

#include <Eigen/Core>

using namespace Eigen;

int main(void)
{
    typedef Array<Array3f, Dynamic, Dynamic> MyArray;
    MyArray m(2,2);

    // all of the following should have the same mathematical effect

    Array3f v = -Array3f(5.0f);             // this compiles

    MyArray a = m + v;                      // this compiles
    MyArray b = m + Array3f(-5.0f);         // this compiles
    MyArray c = m + (-Array3f(5.0f));       // this doesn't compile
    MyArray d = m - Array3f(5.0f);          // this doesn't compile
}

The above code gives me three errors:

./Eigen/src/Core/CwiseBinaryOp.h:128:7: error: no member named
      'YOU_MIXED_DIFFERENT_NUMERIC_TYPES__YOU_NEED_TO_USE_THE_CAST_METHOD_OF_MATRIXBASE_TO_CAST_NUMERIC_TYPES_EXPLICITLY' in
      'Eigen::internal::static_assertion<false>'
      EIGEN_CHECK_BINARY_COMPATIBILIY(BinaryOp,typename Lhs::Scalar,typename Rhs::Scalar);
...

./Eigen/src/Core/CwiseBinaryOp.h:187:14: error: no matching function for call to object of type 'const
      Eigen::internal::scalar_sum_op<Eigen::Array<float, 3, 1, 0, 3, 1> >'
      return derived().functor()(derived().lhs().coeff(index),
...

./Eigen/src/Core/../plugins/ArrayCwiseBinaryOps.h:208:10: error: no viable conversion from 'const
      CwiseBinaryOp<internal::scalar_sum_op<Scalar>, const Eigen::Array<Eigen::Array<float, 3, 1, 0, 3, 1>, -1, -1, 0, -1, -1>, const
      Eigen::CwiseUnaryOp<Eigen::internal::scalar_opposite_op<float>, const Eigen::Array<float, 3, 1, 0, 3, 1> > >' to 'const
      CwiseUnaryOp<internal::scalar_add_op<Scalar>, const Eigen::Array<Eigen::Array<float, 3, 1, 0, 3, 1>, -1, -1, 0, -1, -1> >'
  return *this + (-scalar);
...
Postal answered 28/8, 2015 at 18:48 Comment(0)
J
2

In case someone is interested: The above example compiles and runs fine with Eigen 3.3rc1 (most likely anything since Eigen 3.3-alpha is fine as well).

I would still consider this feature as experimental, since it is neither documented, nor part of the test suite (as far as I see).

Jovanjove answered 23/10, 2016 at 18:56 Comment(0)
R
1

The problem is that Eigen is using lazy evaluation and that (-Array3f(5.0f)) is actually an expression and not an array. I'm not sure exactly what's failing and I don't have enough time to look into it right now. Before I continue, I have to say that there is no valid constructor for Array3f(float) and will continue the answer Array3f(5.0f, 4.0f, 3.1f) instead.

The simple fast and easy hack would be to force evaluation of the negated array and use a + operation. Not ideal for many reasons, but

MyArray c = m + (-Array3f(5.0f, 4.0f, 3.1f)).eval();

works. Advantage: quickly implemented. Disadvantage: no lazy evaluation, as the eval() will create a new negated array. Also makes the code much uglier.

Roguish answered 29/8, 2015 at 20:30 Comment(2)
Note that for such small fixed size arrays, explicit evaluation is not an issue as values stay in registers and no actual temporary is created.Feudality
This seems like an unsatisfactory workaround (even if it is fast). For context: the goal was to use the Eigen array class as a container for color data in a framework that will be handed out to university students as part of a homework assignment. Asking students to call eval() in various special cases is likely cause a lot of confusion and frustrating debugging sessions.Codpiece
B
0

I think Eigen was not meant to be used in this way (with vectors as "scalar" types). I don't know what causes some of the expressions to compile, but for the ones that don't, it's because Eigen sees a + operation on two Arrays, with the left Array's scalar = Array3f, right Array's scalar = float and flags it incompatible.

Benbow answered 28/8, 2015 at 19:15 Comment(1)
I don't understand why this should be a problem. This page explains the requirements for using custom scalar types, and an Array3f itself seems to satisfy all of these requirements. Namely, it 1) overloads the standard arithmetic operators, 2) specializes NumTraits, and 3) overloads the math functions that make sense. Note, that if I define by own Color3f class, which does not inherit from Array3f, everything works fine. Also worth noting, Array3f works fine for add, multiply & divide. Only subtract & negate fail.Postal

© 2022 - 2024 — McMap. All rights reserved.