Skip to content

Commit

Permalink
Added legacy tabulate mode
Browse files Browse the repository at this point in the history
  • Loading branch information
ppizarror committed Aug 19, 2024
1 parent 89e57c9 commit 7b8c9dc
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 40 deletions.
6 changes: 3 additions & 3 deletions MLStructFP/__init__.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
"""
MLSTRUCTFP
MLSTRUCT-FP
Machine learning structural floor plan dataset.
Machine Learning STRUCTural Floor Plan dataset.
"""

# Basic information
__author__ = 'Pablo Pizarro R.'
__description__ = 'Machine learning structural floor plan dataset'
__keywords__ = ['ml', 'ai', 'floor plan', 'architectural', 'dataset', 'cnn']
__email__ = '[email protected]'
__version__ = '0.6.5'
__version__ = '0.6.6'

# URL
__url__ = 'https://github.com/MLSTRUCT/MLSTRUCT-FP'
Expand Down
27 changes: 15 additions & 12 deletions MLStructFP/db/_db_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -175,21 +175,23 @@ def set_filter(self, f_filter: Callable[['Floor'], bool]) -> None:
self.__filter = f_filter
self.__filtered_floors.clear()

def tabulate(self, limit: int = 0, show_project: bool = False,
def tabulate(self, limit: int = 0, legacy: bool = False,
f_filter: Optional[Callable[['Floor'], bool]] = None) -> None:
"""
Tabulates each floor, with their file and number of rects.
:param limit: Limits the number of items
:param show_project: Show project data (if exists)
:param legacy: Show legacy mode
:param f_filter: Floor filter
"""
assert isinstance(limit, int) and limit >= 0, 'Limit must be an integer greater or equal than zero'
theads = ['#']
if show_project:
theads.append('Project ID')
theads.append('Project label')
for t in ('Floor ID', 'Cat', 'Elev', 'Rects', 'Points', 'Slabs', 'Rooms', 'Items', 'Floor image path'):
for t in (
('Project ID', 'Project label', 'Floor ID', 'Cat', 'Elev',
'Rects', 'Points', 'Slabs', 'Rooms', 'Items', 'Floor image path'
) if not legacy else
('Floor ID', 'Rects', 'Floor image path')
):
theads.append(t)
table = [theads]
floors = self.floors
Expand All @@ -198,12 +200,13 @@ def tabulate(self, limit: int = 0, show_project: bool = False,
if f_filter is not None and not f_filter(f):
continue
table_data = [j]
if show_project:
table_data.append(f.project_id)
table_data.append(f.project_label)
for i in (f.id, f.category, 1 if f.elevation else 0,
len(f.rect), len(f.point), len(f.slab), len(f.room), len(f.item), # Item count
os.path.basename(f.image_path)):
f_file: str = os.path.basename(f.image_path)
for i in (
(f.project_id, f.project_label, f.id, f.category, 1 if f.elevation else 0,
len(f.rect), len(f.point), len(f.slab), len(f.room), len(f.item), f_file
) if not legacy else
(f.id, len(f.rect), f_file)
):
table_data.append(i)
table.append(table_data)
if 0 < limit - 1 <= j:
Expand Down
4 changes: 2 additions & 2 deletions MLStructFP/db/_floor.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,15 @@ class Floor(object):
project_id: int
project_label: str

def __init__(self, floor_id: int, image_path: str, image_scale: NumberType, project_id: int = -1,
def __init__(self, floor_id: int, image_path: str, image_scale: NumberType, project_id: int,
project_label: str = '', category: int = 0, category_name: str = '', elevation: bool = False) -> None:
"""
Constructor.
:param floor_id: Floor ID
:param image_path: Image path
:param image_scale: Image scale (px to units)
:param project_id: Project ID (default: -1)
:param project_id: Project ID
:param project_label: Project label (default empty)
:param category: Project category
:param category_name: Project category name
Expand Down
46 changes: 23 additions & 23 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,19 @@ MLSTRUCT-FP
:target: https://opensource.org/licenses/MIT
:alt: License MIT

Multi-unit floor plan dataset.
**M**\ achine **L**\ earning **STRUCT**\ ural **F**\ loor **P**\ lan: A multi-unit floor plan dataset.


Description
-----------

This repo contains the base library to load and parse floor plans from the MLSTRUCT-FP dataset, which
contains over 954 large-scale floor plan images, alongside annotations for their walls in JSON
format. The database loader just loads in memory the Floor, Walls, and Slab objects, and also
format. The database loader loads in memory the Floor, Walls, and Slab objects, and also
offers methods to create custom images from floor plans by applying a crop, a rotation, and a custom
scaling.

The images can be generated from the real rasterized plan, or by using the polygons stored in the
The images can be generated from the real rasterized plan or by using the polygons stored in the
JSON file. Both image and wall polygons are consistent in their placement.

See more information in our `published article <https://doi.org/10.1016/j.autcon.2023.105132>`_; also,
Expand All @@ -45,13 +45,13 @@ check out the `AI segmentation model <https://github.com/MLSTRUCT/MLSTRUCT-FP_be
First steps
-----------

In order to install the library, use the following python-pip commands:
To install the library, use the following python-pip commands:

.. code-block:: bash
python -m pip install MLStructFP
To download the dataset (compressed in .zip), request a public download link by completing a
To download the dataset (compressed in .zip), request a public download link by completing a
`simple form <https://forms.gle/HigdGxngnTEvnNC37>`_.


Expand All @@ -61,7 +61,7 @@ Dataset details
The dataset (uncompressed) has the following structure:

.. code-block:: bash
dataset/
0a0...736.png
0a7...b41.png
Expand All @@ -77,7 +77,7 @@ whose labels (wall polygons, slabs) and metadata are stored within fp.json.
The format of the fp.json file is characterized as follows:

.. code-block:: JSON
{
"rect": {
"1000393": {
Expand Down Expand Up @@ -134,7 +134,7 @@ The format of the fp.json file is characterized as follows:
}
Note the dataset comprises a list of "rect" representing the rectangles (wall segments),
"slab" and "floor". Each item has a distinct ID for querying and grouping elements. In the example,
"slab," and "floor." Each item has a distinct ID for querying and grouping elements. In the example,
the rect ID ``1000393`` is within floor ID ``8970646``, with an angle of ``0`` degrees, a length
of ``2.6 m``, and within the wall ID ``5969311``. Likewise, the slab ``1002588`` is within floor
ID ``5980221``, whose its first point (x, y) is ``(-1.153, -22.622) m``. Finally, the floor ID
Expand All @@ -145,15 +145,15 @@ there are ``70873`` rects, ``954`` slabs and ``954`` floors.
Object API
----------

The basic usage of the API is illustrated on the
`jupyter notebook <https://github.com/MLSTRUCT/MLSTRUCT-FP/blob/master/example.ipynb>`_. The most basic
The primary usage of the API is illustrated on the
`jupyter notebook <https://github.com/MLSTRUCT/MLSTRUCT-FP/blob/master/example.ipynb>`_. The most fundamental
object is `DbLoader <https://github.com/MLSTRUCT/MLSTRUCT-FP/blob/master/MLStructFP/db/_db_loader.py>`_,
which receives the path of the ``fp.json`` file.

.. code-block:: python
class DbLoader(db: str)
# Example
db = DbLoader('test/data/fp.json')
db.tabulate()
Expand All @@ -165,21 +165,21 @@ which receives the path of the ``fp.json`` file.
DbLoader creates a dict of `Floor <https://github.com/MLSTRUCT/MLSTRUCT-FP/blob/master/MLStructFP/db/_floor.py>`_ object,
which each contains a dict of `Rect <https://github.com/MLSTRUCT/MLSTRUCT-FP/blob/master/MLStructFP/db/_c_rect.py>`_ and
`Slab <https://github.com/MLSTRUCT/MLSTRUCT-FP/blob/master/MLStructFP/db/_c_slab.py>`_ objects. Each item is associated
using their respective ids. Floor objects also have many methods to retrieve their elements, plot, and apply
transformations (aka mutations) such as scaling or rotation using ``mutate()`` method:
with their respective IDs. Floor objects also have many methods to retrieve their elements, plot, and apply
transformations (aka mutations) such as scaling or rotation using the ``mutate()`` method:

.. code-block:: python
class Floor:
...
def mutate(self, angle: NumberType = 0, sx: NumberType = 1, sy: NumberType = 1,
scale_first: bool = True) -> 'Floor':
...
# Example
plot_floor = db.floor[302]
plot_floor.mutate(30, 1, 1) # 30 degrees, scale 1 on the x-axis, 1 on the y-axis
plot_floor.mutate(30, 1, 1) # 30 degrees, scale one on the x-axis, one on the y-axis
plot_floor.plot_complex()
.. image:: docs/example-plot.png
Expand All @@ -193,19 +193,19 @@ main responsibilities are creating plan crops for machine learning model trainin
and downsampling on any image size and scale factor. For both objects, the main methods are:

.. code-block:: python
def make_rect(self, rect: 'Rect', crop_length: NumberType = 5) -> Tuple[int, 'np.ndarray']:
def make_region(self, xmin: NumberType, xmax: NumberType, ymin: NumberType, ymax: NumberType,
floor: 'Floor', rect: Optional['Rect'] = None) -> Tuple[int, 'np.ndarray']:
The first one creates a crop around the provided rect (using its position as the center, adding ``crop_length`` m
The first creates a crop around the provided rect (using its position as the center, adding ``crop_length`` m
for each axis). The second one creates a region on any arbitrary ``(xmin, ymin, xmax, ymax)`` region. Consider
each position in meters.

From the provided notebook example, the following image shows two crops generated using a mutated floor plan
with 30 30-degree angle rotation. Crops are ``256x256 px`` size and display a ``10x10 m`` region, for a selected
rectangle as origin.
with 30 30-degree angle rotation. Crops are 256x256 px`` in size and display a ``10x10 m`` region for a selected
rectangle as the origin.

.. image:: docs/example-rects.png
:width: 640
Expand Down

0 comments on commit 7b8c9dc

Please sign in to comment.