9

I am trying to use a function that uses some OpenCV function on the image. But the data I am getting is a tensor and I am not able to convert it into an image.

def image_func(img):
     img=cv2.cvtColor(img,cv2.COLOR_BGR2YUV) 
     img=cv2.resize(img,(200,66))
     return img

model=Sequential()
model.add(Lambda(get_ideal_img,input_shape=(r,c,ch),output_shape=(r,c,ch)))

When I run this snippet it throws an error in the cvtColor function saying that img is not a numpy array. I printed out img and it seemed to be a tensor.

I do not know how to change the tensor to an image and then return the tensor as well. I want the model to have this layer.

If I cannot achieve this with a lambda layer what else can I do?

3
  • which backend are you using Theano or Tensorflow? Note that by default tensorflow is the backend. So if you didn't change anything tensorflow is what you're using. Commented Mar 19, 2017 at 6:35
  • 1
    I am using tensorflow Commented Mar 19, 2017 at 6:54
  • Did you manage to solve the problem?, I'm facing a similar issue Commented Apr 17, 2021 at 16:05

2 Answers 2

5

You confused with the symbolic operation in the Lambda layer with the numerical operation in a python function.

Basically, your custom operation accepts numerical inputs but not symbolic ones. To fix this, what you need is something like py_func in tensorflow

In addition, you have not considered the backpropagation. In short, although this layer is non-parametric and non-learnable, you need to take care of its gradient as well.

import tensorflow as tf
from keras.layers import Input, Conv2D, Lambda
from keras.models import Model
from keras import backend as K
import cv2

def image_func(img):
    img=cv2.cvtColor(img,cv2.COLOR_BGR2YUV) 
    img=cv2.resize(img,(200,66))
    return img.astype('float32')

def image_tensor_func(img4d) :
    results = []
    for img3d in img4d :
        rimg3d = image_func(img3d )
        results.append( np.expand_dims( rimg3d, axis=0 ) )
    return np.concatenate( results, axis = 0 )

class CustomLayer( Layer ) :
    def call( self, xin )  :
        xout = tf.py_func( image_tensor_func, 
                           [xin],
                           'float32',
                           stateful=False,
                           name='cvOpt')
        xout = K.stop_gradient( xout ) # explicitly set no grad
        xout.set_shape( [xin.shape[0], 66, 200, xin.shape[-1]] ) # explicitly set output shape
        return xout
    def compute_output_shape( self, sin ) :
        return ( sin[0], 66, 200, sin[-1] )

x = Input(shape=(None,None,3))
f = CustomLayer(name='custom')(x)
y = Conv2D(1,(1,1), padding='same')(x)

model = Model( inputs=x, outputs=y )
print model.summary()

Now you can test this layer with some dummy data.

a = np.random.randn(2,100,200,3)
b = model.predict(a)
print b.shape

model.compile('sgd',loss='mse')
model.fit(a,b)
Sign up to request clarification or add additional context in comments.

4 Comments

Nice example, think that helps me a lot, even when tf 2.0 is out now haha. But i think you may have a typing error and not using your custom layer (f) at all, because you defined outputs=y , beforehand just passed x to y and so just skipped your Custom layer. Maybe i talk bul*****, but thanks for your explanation anyway ^^
This is an excellent explanation for neophytes in Keras and Tensorflow. Just change tf.py_func for tf.py_function (dropping stateful parameter) in newest version of Tensorflow. Thxs!!
I followed your template for a similar case where the image tensor has to pass through a transformation (color space, etc), and have been training it with a toy example. Without the custom layer the model trains and generalizes well, however when I use the custom layer the loss never decreases. What could be the problem? Maybe something related to the gradient flowin the custom layer? Any suggestion? thanks
Not sure what's going on, but you shouldn't use this trick unless the function that you are interested in is some kind of preprocessing, i.e. something can placed in between a raw RGB image and a DNN. If your task is about color space, you can always learn a simple 1x1 Conv2D layer for a color transform, e.g. YUV <> RGB.
-1

Im going to assume image_func function does what you want (resize) and image. Note that an image is represent by a numpy array. Since you are using the tensorflow backend you are operating over Tensors (this you knew).

The job now is to convert a Tensor to a numpy array. To do that we need to evaluate the Tensor using its evaluate the tensor. But inorder to do that we need a to grab a tensor flow session.

Use the get_session() method of the keras backend module to grab the current tensorflow session.

Here is the docstring for get_session()

def get_session():
    """Returns the TF session to be used by the backend.
    If a default TensorFlow session is available, we will return it.
    Else, we will return the global Keras session.
    If no global Keras session exists at this point:
    we will create a new global session.
    Note that you can manually set the global session
    via `K.set_session(sess)`.
    # Returns
        A TensorFlow session.
    """

So try:

def image_func(img)

    from keras import backend as K

    sess  = K.get_session()
    img = sess.run(img) # now img is a proper numpy array 

    img=cv2.cvtColor(img,cv2.COLOR_BGR2YUV) 
    img=cv2.resize(img,(200,66))
    return img

Note, I haven't been able to test this

EDIT: Just tested this and it won't work (as you noticed). The lambda function needs to return Tensor. Computation flows throw a Tensor so it also needs to be to be smooth in the sense of differentiation.

I see that essentially the lambda is changing the color and resizing the image, why don't you do this in pre-processing step?

1 Comment

I tested it out. But the lambda layer expects a tensor object. Specifically it says that it should be place holder. But you are returning an image. How should that be changed?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.