Problem with BandMathX syntax

What’s wrong with this expression?
`otbcli_BandMathX -il input.tif -out output.tif -exp '(im1<0) ? 0:im1'`
I get:
Can’t evaluate function/operator “<”: Argument 1 of function/operator “” is of type ‘i’ whereas type ‘m’ was expected.

Actually, what I would like to do is the equivalent to this pseuocode:
if(ima>0 & ima <=1) ima
if (ima<0) 0
if(ima>1) 1

which I thought would be:

`'(im1<0) ? 0:im1 ; (im1>1) ? 1:im1'`
or
`'(im1<0) ? 0:(im1>1) ? 1:im1'`

But none are correct and the error messages are inextricable.

Is there a guide to BandMathX with examples of use?
The syntax is not trivial at all and what is offered in the Cookbook
is very insufficient. May be just a wiki page with examples
of successful expressions would be enough.

Agus

I hope this helps. I think you miss the band number.

I use expressions like (with Python):

`band_expressions = ['(im1b3 + im1b2) !=0 ? (im1b3 - im1b2) / (im1b3 + im1b2) : -1']`

And this works.

Fabrice

Thanks, but I want it to be applied to all bands, hence the use of BandMathX:
“‘im1’ a pixel from 1st input, made of n components (n bands)”
from https://www.orfeo-toolbox.org/CookBook/Applications/app_BandMathX.html

You can do some naughty tricks with BandMathX !
`0.5*(vabs(im1)+im1)` will return a pixel with negative components replaced by 0.
The clipping below 1 should be doable but complicated.
I once helped a guy with some similar tricky expression on the old forum

“0.5*(vabs(im1)+im1) will return a pixel with negative components replaced by 0.”

Yes, I confirm that works. Unfortunately, replacing negative values by 0 only is not sufficient

“The clipping below 1 should be doable but complicated.”

Well, that’s the problem: such a simple task is complicated using OTB…
(and please note the goal is clipping above 1)

But let’s stick to the question: what’s wrong with these expressions?
According to the OTB documentation they are correct:
‘(im1<0) ? 0:im1’
‘(im1<0) ? 0:im1 ; (im1>1) ? 1:im1’
‘(im1<0) ? 0:(im1>1) ? 1:im1’

Note that considering the fact that some (many? all?) OTB commands
do not deal with no-data values, it is important to set image values in all bands to
the appropriate range

Perhaps we need an specific OTB tool for this operation, something like:
`otbcli_SetValidRange -input imain.tif -output imaout.tif -minvalid 0 -maxvalid 1 -minoutclip 0 -maxoutclip 1`

Hi alobo,
I think your equation is inconsistent. You are trying to compare a vector (your pixel with several bands) with an integer. Which is not defined in a mathematical sense. So, either you compare the norm of your pixel, or you compare each component.

According to the OTB documentation they are correct:
‘(im1<0) ? 0:im1’
‘(im1<0) ? 0:im1 ; (im1>1) ? 1:im1’
‘(im1<0) ? 0:(im1>1) ? 1:im1’

I wonder where you find that because according to documentation:

Always keep in mind that this application only addresses mathematically well-defined formulas. For instance, it is not possible to add vectors of different dimensions (e.g. addition of a row vector with a column vector), or a scalar to a vector or matrix, or divide two vectors, etc.
Thus, it is important to remember that a pixel of n components is always represented as a row vector.

Antoine

In any vectorial language (i.e., R or matlab), operating a vector or matrix by a scalar is always implicitely
taken (and accepted) as operating each element of the vector or matrix by that scalar. A different thing would be adding vectors or matrices of different dimensions, but this is not the case. Actually, from a user point of view, I do not see why this expression works:
`"0.5 * im1"`
but this expression does not work
`"0.5 + im1"`
Both are acceptd in R or matlab, which also would accept logical operators.

Now, considering you do not actually suggest any solution, I have to conjecture that the point is that OTB does not actually have a way to implement this simple pseudocode:
`ifelse(A<0,0,ifelse(A>1,1,A))`

for A being a multi-spectral image

In R this would be:
#in 2 steps

A[A<0] <-0
A[A>1] <-1

#or define a function and apply it:

mif <- function(x) ifelse(x<0,0,ifelse(x>1,1,x))
B <- calc(A,mif)

Unfortunately, this is too slow for large images as the ones we deal with now.

Perhaps, in OTB, we would have to create images im2 and im3 of the same dimensions as im1 and set them to constant values 0 and 1, i.e.,
‘(im1<im2) ? im2:im1 ; (im1>im3) ? im3:im1’

would that be the only way of doing this operation in OTB?

Perhaps, in OTB, we would have to create images im2 and im3 of the same dimensions as im1 and set them to constant values 0 and 1, i.e.,
‘(im1<im2) ? im2:im1 ; (im1>im3) ? im3:im1’
would that be the only way of doing this operation in OTB?

Yes!

In math you cannot do `"0.5 + im1"`, this is some basic algebra knowledge… Same in OTB, but what you can do is `"0.5*ones(1,n) + im1"` with n the number of bands of im1 (in bandmathx)!

Regarding your request of a specific tools, if you are already a programmer you are welcome to try and contribute with such an application. We already have a ThresholdVectorImageFilter, which will do exactly what you are asking!

In math you cannot do `"0.5 + im1"` , this is some basic algebra knowledge…

Oh I see! people behind R or matlab and the several millions using them “lack some basic algebra knowledge”:

Instead, in OTB we are so lucky that we can do the same provided we take care of repeating the scalar tenths of thousands of times so that we match the dimensions of the array! Brilliant! why letting the software taking care of that if we can do it ourselves?

Regarding your request of specific tools, if you are already a programmer you are welcome to try and contribute with such an application.

No I’m not. Scripting in R or matlab for data analysis is not the same than being a programmer. I just let the forum know where I find difficulties to get help and, in the passing, you can take users comments into account for improving OTB.

`We already have a ThresholdVectorImageFilter, which will do exactly what you are asking!`

Well, I’ve googled OTB ThresholdVectorImageFilter and could not find the module, so I presume is an internal function that can be used within a python script only. But, of course, this should not be too easy.