4

I recently stumbled upon this question: Interactive labeling of images in jupyter notebook which I found quite interesting.

Having little experience in Python coding, I tried to run the provided code from the answer using a Jupyter Notebook, but I somehow cannot get it to work. I believe that I am doing something wrong when importing the images. I am trying to import all images from a folder called "images" which is located in "PATH".

Here is the complete code:

import cv2
import os

import ipywidgets as widgets
import functools

images_list = []

os.chdir(PATH)
# Load in the images
for filepath in os.listdir('images/'):
    images_list.append(cv2.imread('images/{0}'.format(filepath),0))


COLS = 4
ROWS = 2
IMAGES = images_list 
IMG_WIDTH = 200
IMG_HEIGHT = 200

def on_click(index):
    print('Image %d clicked' % index)


rows = []

for row in range(ROWS):
    cols = []
    for col in range(COLS):
        index = row * COLS + col
        image = widgets.Image(
            value=IMAGES[index], width=IMG_WIDTH, height=IMG_HEIGHT
        )
        button = widgets.Button(description='Image %d' % index)
        # Bind the click event to the on_click function, with our index as argument
        button.on_click(functools.partial(on_click, index))

        # Create a vertical layout box, image above the button
        box = widgets.VBox([image, button])
        cols.append(box)

    # Create a horizontal layout box, grouping all the columns together
    rows.append(widgets.HBox(cols))

# Create a vertical layout box, grouping all the rows together
result = widgets.VBox(rows)

Edit

After fixing the syntax error, I get the following error:

--------------------------------------------------------------------------- 
TraitError 
Traceback (most recent call last) <ipython-input-87-2ca2a1eb59b4> in <module>()
     36         index = row * COLS + col
     37         image = widgets.Image(
---> 38             value=IMAGES[index], width=IMG_WIDTH, height=IMG_HEIGHT
     39         )
     40         button = widgets.Button(description='Image %d' % index)

~\Anaconda3\lib\site-packages\ipywidgets\widgets\widget.py in __init__(self, **kwargs)
    409         """Public constructor"""
    410         self._model_id = kwargs.pop('model_id', None)
--> 411         super(Widget, self).__init__(**kwargs)
    412
    413         Widget._call_widget_constructed(self)

~\Anaconda3\lib\site-packages\traitlets\traitlets.py in __init__(self, *args, **kwargs)
    995             for key, value in kwargs.items():
    996                 if self.has_trait(key):
--> 997                     setattr(self, key, value)
    998                 else:
    999                     # passthrough args that don't set traits to super

~\Anaconda3\lib\site-packages\traitlets\traitlets.py in __set__(self, obj, value)
    583             raise TraitError('The "%s" trait is read-only.' % self.name)
    584         else:
--> 585             self.set(obj, value)
    586 
    587     def _validate(self, obj, value):

~\Anaconda3\lib\site-packages\traitlets\traitlets.py in set(self, obj, value)
    557 
    558     def set(self, obj, value):
--> 559         new_value = self._validate(obj, value)
    560         try:
    561             old_value = obj._trait_values[self.name]

~\Anaconda3\lib\site-packages\traitlets\traitlets.py in _validate(self, obj, value)
    589             return value
    590         if hasattr(self, 'validate'):
--> 591             value = self.validate(obj, value)
    592         if obj._cross_validation_lock is False:
    593             value = self._cross_validate(obj, value)

~\Anaconda3\lib\site-packages\traitlets\traitlets.py in validate(self, obj, value)
   2024         if isinstance(value, bytes):
   2025             return value
-> 2026         self.error(obj, value)
   2027 
   2028 

~\Anaconda3\lib\site-packages\traitlets\traitlets.py in error(self, obj, value)
    623             e = "The '%s' trait must be %s, but a value of %r was specified." \
    624                 % (self.name, self.info(), repr_type(value))
--> 625         raise TraitError(e)
    626 
    627     def get_metadata(self, key, default=None):

TraitError: The 'value' trait of an Image instance must be a bytes object, but a value of 
    array([[232, 242, 243, ..., 243, 246, 232],
           [244, 254, 255, ..., 254, 255, 243],
           [244, 254, 255, ..., 254, 255, 242],
           ...,
           [242, 253, 253, ..., 254, 254, 243],
           [245, 255, 255, ..., 255, 255, 244],
           [238, 249, 248, ..., 245, 245, 234]], dtype=uint8) 
    <class 'numpy.ndarray'> 
was specified.

Edit

Here is my Jupyter Notebook version:

enter image description here

halfer
  • 19,824
  • 17
  • 99
  • 186
henry
  • 875
  • 1
  • 18
  • 48
  • For your edited question: The TraitError looks like the Traitlets package is expecting a Bytes object, but IPyWidget is sending it a numpy array. Considering that you don't do anything with numpy yourself, I would guess that this is a compatibility issue. What version of ipywidgets are you using? What about traitlets? Are they compatible? – Niayesh Isky Mar 18 '19 at 00:44
  • @NiayeshIsky Thanks for your comment. I have updated my question with my jupyter version, but I don't know how to check traitlets. How would you do that ? Thanks. – henry Mar 18 '19 at 07:12
  • It looks like you're using Anaconda, so according to [this answer](https://stackoverflow.com/a/33694864/7315159), just run `conda env export -n YOUR_ENV_NAME > environment.yml` and look for `traitlets` in the output `environment.yml` file. (Or you can [pastebin](https://pastebin.com/) the whole output file and link to it here, if you prefer.) – Niayesh Isky Mar 18 '19 at 12:46

2 Answers2

2

The code you copied has a missing colon at the end of the second for line, which should look like this:

    for col in range(COLS):

(I would recommend a good IDE, or, at the very least, a syntax checker, to catch these sorts of errors, though!)

Once you've fixed any syntax issues, you can verify if you really have any actual problems with the way you're importing the images. But from what I can see, your code is fine - you're opening a bunch of files as greyscale images and passing them to the code from the linked question. (If you still have issues after the syntax errors are gone, though, you can edit this question or post another.)

Niayesh Isky
  • 1,100
  • 11
  • 17
  • Thanks for noting my typo ! I fixed it, but now I get another error message (see updated question) – henry Mar 17 '19 at 16:43
  • @henry please, if you edit your original and you get answers, just add below your own question, the new coming issue you are facing, after an "Edit:" so everyone can traceback what happened. Cheers. – Paradox Mar 17 '19 at 16:48
1

For what it's worth, you can also use QSL for this task. I added an example to the original question but, in your case, it could be as simple as the following. You can add inputs from within the widget itself (using the "Add New Label Type" button). More information about qsl here. Full disclosure, QSL is one of my projects.

import glob
from IPython.display import display
import qsl

widget = qsl.MediaLabeler(
    items=[{"target": f} for f in glob.glob("images/*")],
    jsonpath="labels.json"
)
display(widget)
Fausto Morales
  • 163
  • 1
  • 8