How to create PointsItemList with ImageBBox for Localization?

I want to use Image Regression for Bounding Boxes. I thought the objects ImageBBox were supposed to be the labels of images, when creating a PointsItemList, calling a BBox creating function create_bbox :

def np_from_img(img_file):
    t = np.atleast_2d(np.genfromtxt(img2txt_name(file_exmpl))[...,:-1])
    # Reordering coordinates to fit fastai standard
    t[:,0],t[:,1] = t[:,1],t[:,0].copy()
    t[:,2],t[:,3] = t[:,3],t[:,2].copy()
    return t 

def create_bbox(item, show=False):
    img = open_image(item)
    bbox = ImageBBox.create(*img.size, np_from_img(item))
    if show: 
        img.show(y=bbox)
    return bbox

items = PointsItemList.from_folder(data_folder).split_by_folder(valid='test')
items.label_from_func(create_bbox)

I get the error:

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-12-fb422eb58eeb> in <module>
----> 1 items.label_from_func(create_bbox)

~/miniconda3/envs/fastai/lib/python3.7/site-packages/fastai/data_block.py in _inner(*args, **kwargs)
    391             self.valid = fv(*args, **kwargs)
    392             self.__class__ = LabelLists
--> 393             self.process()
    394             return self
    395         return _inner

~/miniconda3/envs/fastai/lib/python3.7/site-packages/fastai/data_block.py in process(self)
    437     def process(self):
    438         "Process the inner datasets."
--> 439         xp,yp = self.get_processors()
    440         for i,ds in enumerate(self.lists): ds.process(xp, yp, filter_missing_y=i==0)
    441         return self

~/miniconda3/envs/fastai/lib/python3.7/site-packages/fastai/data_block.py in get_processors(self)
    432         procs_x,procs_y = listify(self.train.x._processor),listify(self.train.y._processor)
    433         xp = ifnone(self.train.x.processor, [p(ds=self.train.x) for p in procs_x])
--> 434         yp = ifnone(self.train.y.processor, [p(ds=self.train.y) for p in procs_y])
    435         return xp,yp
    436 

~/miniconda3/envs/fastai/lib/python3.7/site-packages/fastai/data_block.py in <listcomp>(.0)
    432         procs_x,procs_y = listify(self.train.x._processor),listify(self.train.y._processor)
    433         xp = ifnone(self.train.x.processor, [p(ds=self.train.x) for p in procs_x])
--> 434         yp = ifnone(self.train.y.processor, [p(ds=self.train.y) for p in procs_y])
    435         return xp,yp
    436 

~/miniconda3/envs/fastai/lib/python3.7/site-packages/fastai/vision/data.py in __init__(self, ds)
    385 class PointsProcessor(PreProcessor):
    386     "`PreProcessor` that stores the number of targets for point regression."
--> 387     def __init__(self, ds:ItemList): self.c = len(ds.items[0].reshape(-1))
    388     def process(self, ds:ItemList):  ds.c = self.c
    389 

AttributeError: 'ImageBBox' object has no attribute 'reshape'

I guess this means, it accepts numpy arrays instead of ImageBBox objects, and I am not understanding how to use them.

I saw here that @sgugger was mentioning PointsItemList should be subclassed, but I am not sure if he refers to the same.

I am Using:

python        : 3.7.1
fastai        : 1.0.38 
1 Like

If you’re using bounding boxes with ImageBBox, you should use ObjetDetectList (or whatever the exact name).

1 Like

I’m trying the to make a PointsItemList and I"m getting the same error. I have

data = (Data.PointsItemList.from_df(
            path=IMG_PATH,
            df=dataset_df,
        )
        .random_split_by_pct()
        .label_from_func(get_y_func)

and I get

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-57-23caaa3ee122> in <module>
     14         )
     15         .random_split_by_pct()
---> 16         .label_from_func(get_y_func)

~/anaconda3/envs/fastai/lib/python3.7/site-packages/fastai/data_block.py in _inner(*args, **kwargs)
    373             self.valid = fv(*args, **kwargs)
    374             self.__class__ = LabelLists
--> 375             self.process()
    376             return self
    377         return _inner

~/anaconda3/envs/fastai/lib/python3.7/site-packages/fastai/data_block.py in process(self)
    419     def process(self):
    420         "Process the inner datasets."
--> 421         xp,yp = self.get_processors()
    422         for i,ds in enumerate(self.lists): ds.process(xp, yp, filter_missing_y=i==0)
    423         return self

~/anaconda3/envs/fastai/lib/python3.7/site-packages/fastai/data_block.py in get_processors(self)
    413         "Read the default class processors if none have been set."
    414         procs_x,procs_y = listify(self.train.x._processor),listify(self.train.y._processor)
--> 415         xp = ifnone(self.train.x.processor, [p(ds=self.train.x) for p in procs_x])
    416         yp = ifnone(self.train.y.processor, [p(ds=self.train.y) for p in procs_y])
    417         return xp,yp

~/anaconda3/envs/fastai/lib/python3.7/site-packages/fastai/data_block.py in <listcomp>(.0)
    413         "Read the default class processors if none have been set."
    414         procs_x,procs_y = listify(self.train.x._processor),listify(self.train.y._processor)
--> 415         xp = ifnone(self.train.x.processor, [p(ds=self.train.x) for p in procs_x])
    416         yp = ifnone(self.train.y.processor, [p(ds=self.train.y) for p in procs_y])
    417         return xp,yp

~/anaconda3/envs/fastai/lib/python3.7/site-packages/fastai/vision/data.py in __init__(self, ds)
    377 class PointsProcessor(PreProcessor):
    378     "`PreProcessor` that stores the number of targets for point regression."
--> 379     def __init__(self, ds:ItemList): self.c = len(ds.items[0].reshape(-1))
    380     def process(self, ds:ItemList):  ds.c = self.c
    381 

AttributeError: 'str' object has no attribute 'reshape'

The str object that doesn’t have reshape is the IMG_PATH passed in as path. If I were to venture at what’s happening I guess the create_func (that I think existed before) isn’t used any more and the path is used as is rather than being loaded?

I’m a little bit confused by the documentation of this.

Be careful, you’re giving the arguments in the wrong order (first df then path).

They’re named arguments so order should not matter, right? Also, switching the arguments gives the same error.

Oh yes, you’re right. Are you sure you don’t have headers in your dataframe? It looks like the first item picked is a string and not an array of floats.

The dataframe has two colums, filename and points. Filename is a path, points are numpy arrays shape=(2, 2). .label_from_func(get_y_func) takes the filesnames and returns the corresponding nd array from the dataframe. It still gets AttributeError: 'str' object has no attribute 'reshape' when working on self.train.x which makes me think the image is not being loaded and the path is sent around instead.

This is really weird as the PointsProcessor shouldn’t be called on the xs but on the ys. Are you sure you have the latest fastai?

Sorry for the late reply. Using this program

 from pathlib import Path
 import pandas as pd
 import numpy as np
 
 from torch.utils.data import Dataset, DataLoader
 
 from fastai.vision import (data as Data,
                            transform as Transform)
 
 JPEG_PATH = Path('/some/folder')
 
 dataDict = {'filename': ['someJpgInFolder.jpg']*10}
 DATASET = pd.DataFrame.from_dict(dataDict)
 
 path2coords = {'someJpgInFolder.jnp.array([[200, 200]])}
 
 def get_y_func(pathStr):
     name = Path(pathStr).name
     coords = path2coords[name]
     return coords
 
 data = (Data.PointsItemList.from_df(
             df = DATASET,
             path = JPEG_PATH,
         )
 .random_split_by_pct()
 .label_from_func(get_y_func)
 .transform(Transform.get_transforms(), tfm_y=True, size=(224,224))
 .databunch())

with

pip freeze | grep fastai
fastai==1.0.36

I get

ds items
someJpgInFolder.jpg

AttributeError Traceback (most recent call last)
in
25 )
26 .random_split_by_pct()
—> 27 .label_from_func(get_y_func)
28 .transform(Transform.get_transforms(), tfm_y=True, size=(224,224))
29 .databunch())

~/anaconda3/envs/fastai/lib/python3.7/site-packages/fastai/data_block.py in _inner(*args, **kwargs)
373 self.valid = fv(*args, **kwargs)
374 self.class = LabelLists
–> 375 self.process()
376 return self
377 return _inner

~/anaconda3/envs/fastai/lib/python3.7/site-packages/fastai/data_block.py in process(self)
419 def process(self):
420 “Process the inner datasets.”
–> 421 xp,yp = self.get_processors()
422 for i,ds in enumerate(self.lists): ds.process(xp, yp, filter_missing_y=i==0)
423 return self

~/anaconda3/envs/fastai/lib/python3.7/site-packages/fastai/data_block.py in get_processors(self)
413 “Read the default class processors if none have been set.”
414 procs_x,procs_y = listify(self.train.x._processor),listify(self.train.y._processor)
–> 415 xp = ifnone(self.train.x.processor, [p(ds=self.train.x) for p in procs_x])
416 yp = ifnone(self.train.y.processor, [p(ds=self.train.y) for p in procs_y])
417 return xp,yp

~/anaconda3/envs/fastai/lib/python3.7/site-packages/fastai/data_block.py in (.0)
413 “Read the default class processors if none have been set.”
414 procs_x,procs_y = listify(self.train.x._processor),listify(self.train.y._processor)
–> 415 xp = ifnone(self.train.x.processor, [p(ds=self.train.x) for p in procs_x])
416 yp = ifnone(self.train.y.processor, [p(ds=self.train.y) for p in procs_y])
417 return xp,yp

~/anaconda3/envs/fastai/lib/python3.7/site-packages/fastai/vision/data.py in init(self, ds)
380 print(‘ds items’)
381 print(ds.items[0])
–> 382 self.c = len(ds.items[0].reshape(-1))
383 def process(self, ds:ItemList): ds.c = self.c
384

AttributeError: ‘str’ object has no attribute ‘reshape’

It feels like I’m using the framework right, but I might have missed something?

It looks correct to me. Can you try the same code with v1.0.40?

Not sure how to get 1.0.40. Doing conda install fastai leaves me with fastai=1.0.36. Do I have to get a developer install instead or something?

Does anyone have an explanation for this error yet? I also get this when trying to label a PointsItemList created from a data frame. Running 1.0.49.

1 Like