Skip to content

Commit

Permalink
Moved all requirements to pyproject.toml along with scripts
Browse files Browse the repository at this point in the history
Scripts are now proper entry points

Marimapper can now also be installed as a library

Added test to ensure that scripts are not malformed
  • Loading branch information
TheMariday committed Jul 14, 2024
1 parent a00ad62 commit 2a5a1d2
Show file tree
Hide file tree
Showing 61 changed files with 313 additions and 231 deletions.
2 changes: 1 addition & 1 deletion .flake8
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[flake8]
ignore = E402
exclude = backends/fadecandy/opc.py, venv, lib/sfm/database.py, lib/sfm/read_write_model.py
exclude = marimapper/backends/fadecandy/opc.py, venv, marimapper/database.py, marimapper/read_write_model.py
max-line-length=127
max-complexity = 10
extend-ignore = W503, E203
3 changes: 1 addition & 2 deletions .github/workflows/test_mac.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,7 @@ jobs:
run: |
python -m pip install --upgrade pip
pip cache purge
pip install pytest
pip install -r requirements.txt
pip install .[develop]
- name: Pytest
run: |
Expand Down
3 changes: 1 addition & 2 deletions .github/workflows/test_ubuntu.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,7 @@ jobs:
run: |
python -m pip install --upgrade pip
pip cache purge
pip install pytest
pip install -r requirements.txt
pip install .[develop]
- name: Pytest
run: |
Expand Down
3 changes: 1 addition & 2 deletions .github/workflows/test_windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,7 @@ jobs:
run: |
python -m pip install --upgrade pip
pip cache purge
pip install pytest
pip install -r requirements.txt
pip install .[develop]
- name: Pytest
run: |
Expand Down
67 changes: 38 additions & 29 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,32 @@ The basic algorithms behind this is what I used to map [Highbeam](https://www.yo
![](docs/images/reconstruct_with_normals_and_strips.png)


## Step 0: Install requirements
## Step 0: Install

Marimapper supports the following pre-built backends:

- `fadecandy`
- [`wled`](https://kno.wled.ge/)
- [`fcmega`](https://github.com/TheMariday/FC-Mega)
- [`pixelblaze`](https://electromage.com/docs)

To install Marimapper with a
`pixelblaze`
backend, download this repository and run
`pip install .[pixelblaze]`

<details>
<summary>Using pixelblaze?</summary>
Using Pixelblaze as a backend requires you to upload the [`marimapper.epe`](marimapper/backends/pixelblaze/marimapper.epe) pattern to your pixelblaze before running Marimapper.
</details>

If you would like to write your own LED backend, just run `pip install .`

After downloading this repository and installing Python, run `pip install -r requirements.txt`

## Step 1: Run the camera checker (recommended)

Run `python scripts/check_camera.py` to ensure your camera is compatible with MariMapper, or check the list below:

Run `marimapper_check_camera` to ensure your camera is compatible with MariMapper, or check the list below:

<details>

Expand All @@ -37,53 +56,45 @@ Run `python scripts/check_camera.py` to ensure your camera is compatible with Ma

</details>

> [IMPORTANT]
> Scripts on windows need to be appended with `.exe`

Test LED identification by turning down the lights and holding a torch or led up to the camera
This should start with few warnings, no errors and produce a **very** dark image
with a single crosshair on centered on your LED.

As long as your webcam has exposure control, this should even work in a relatively well lit room!

> [!TIP]
> You can append `--help` to any command to show you all argument options
![alt text](docs/images/camera_check.png "Camera Check window")


> [!TIP]
> If your camera doesn't support exposure adjustment, or the image is still too bright, try dimming the lights and playing around with the --exposure and --threshold arguments
## Step 2: Choose / Write your LED backend

MariMapper needs to be able to communicate with your LEDs and it does this via a `--backend`

MariMapper support the following pre-made backends:

- `fadecandy`
- [`wled`](https://kno.wled.ge/)
- [`fcmega`](https://github.com/TheMariday/FC-Mega)
- [`pixelblaze`](https://electromage.com/docs)
- `custom`

If you choose a pre-built backend, remember to install its dependencies using
`pip install -r backends/fadecandy/requirements.txt`
## Step 2: Write your LED backend if needed

When using Fadecandy, WLED, or Pixelblaze backends, pass the server IP or URI with the `--server` flag.
If your LED backend isn't supported, you need to write your own!
This is luckily very simple!

Using Pixelblaze as a backend requires you to upload the [`marimapper.epe`](backends/pixelblaze/marimapper.epe) pattern to your pixelblaze before running Marimapper.
Open a new python file called `my_backend.py` and copy the below stub into it.

However, your LEDs are as unique as you are,
so it's super simple to implemenet your own `custom` backend by filling in the blanks
in [backends/custom/custom_backend.py](backends/custom/custom_backend.py):
Fill out the blanks and check it by running `marimapper_check_backend --backend my_backend.py`

```python
# import some_led_library

class Backend:

def __init__(self):
# connect to some device here!

def get_led_count(self):
def get_led_count(self) -> int:
# return the number of leds your system can control here

def set_led(self, led_index: int, on: bool):
def set_led(self, led_index: int, on: bool) -> None:
# Write your code for controlling your LEDs here
# It should turn on or off the led at the led_index depending on the "on" variable
# For example:
Expand All @@ -92,14 +103,12 @@ class Backend:
# else:
# some_led_library.set_led(led_index, (0, 0, 0))
```
> [!TIP]
> You can test your backend with `python scripts/check_backend.py`

## Step 3: [It's time to thunderize!](https://youtu.be/-5KJiHc3Nuc?t=121)

Run `python marimapper.py my_scan --backend fadecandy`
Run `marimapper my_scan --backend fadecandy`

change `fadecandy` to whatever backend you're using
Change `fadecandy` to whatever backend you're using
and `my_scan` to the directory you want to save your scan

Set up your LEDs so most of them are in view and when you're ready, type `y` when prompted with `Start scan? [y/n]`
Expand Down
24 changes: 0 additions & 24 deletions backends/custom/custom_backend.py

This file was deleted.

2 changes: 0 additions & 2 deletions backends/fadecandy/requirements.txt

This file was deleted.

3 changes: 0 additions & 3 deletions backends/fcmega/requirements.txt

This file was deleted.

3 changes: 0 additions & 3 deletions backends/pixelblaze/requirements.txt

This file was deleted.

3 changes: 0 additions & 3 deletions backends/wled/requirements.txt

This file was deleted.

File renamed without changes.
3 changes: 3 additions & 0 deletions marimapper/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from marimapper.scripts.scanner_cli import main

main()
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from backends.fadecandy import opc
from marimapper.backends.fadecandy import opc


class Backend:
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import time
import threading

from backends.fcmega.fcmega import FCMega
from marimapper.backends.fcmega.fcmega import FCMega


class Backend:
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
import argparse
import sys
import csv

sys.path.append("./")

from lib import utils
from marimapper import utils


def read_coordinates_from_csv(csv_file_name):
Expand Down
File renamed without changes.
File renamed without changes.
2 changes: 1 addition & 1 deletion lib/camera.py → marimapper/camera.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import cv2
from lib import logging
from marimapper import logging


class CameraSettings:
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

import numpy as np

from lib.sfm.database import COLMAPDatabase
from marimapper.database import COLMAPDatabase


def populate(db_path, led_maps_2d):
Expand Down
4 changes: 2 additions & 2 deletions lib/led_identifier.py → marimapper/led_identifier.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import cv2
from lib.led_map_2d import LEDDetection
from lib import logging
from marimapper.led_map_2d import LEDDetection
from marimapper import logging


class LedFinder:
Expand Down
2 changes: 1 addition & 1 deletion lib/led_map_2d.py → marimapper/led_map_2d.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import os
from parse import parse
from lib import logging
from marimapper import logging


class LEDDetection:
Expand Down
2 changes: 1 addition & 1 deletion lib/led_map_3d.py → marimapper/led_map_3d.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import numpy as np
import math
from lib import logging
from marimapper import logging


class LEDMap3D:
Expand Down
File renamed without changes.
File renamed without changes.
6 changes: 3 additions & 3 deletions lib/sfm/model.py → marimapper/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@

import numpy as np

from lib.sfm.read_write_model import (
from marimapper.read_write_model import (
qvec2rotmat,
read_images_binary,
read_points3D_binary,
)
from lib.remesher import fix_normals
from lib.led_map_3d import LEDMap3D
from marimapper.remesher import fix_normals
from marimapper.led_map_3d import LEDMap3D


def binary_to_led_map_3d(path):
Expand Down
File renamed without changes.
8 changes: 4 additions & 4 deletions lib/reconstructor.py → marimapper/reconstructor.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
import math
from threading import Thread

from lib.camera import Camera, CameraSettings
from lib.led_identifier import LedFinder
from lib import logging
from lib.timeout_controller import TimeoutController
from marimapper.camera import Camera, CameraSettings
from marimapper.led_identifier import LedFinder
from marimapper import logging
from marimapper.timeout_controller import TimeoutController


class Reconstructor:
Expand Down
File renamed without changes.
57 changes: 12 additions & 45 deletions marimapper.py → marimapper/scanner.py
Original file line number Diff line number Diff line change
@@ -1,31 +1,25 @@
import argparse
import os
import time
import signal
from tqdm import tqdm
from pathlib import Path

from lib.reconstructor import Reconstructor
from lib import utils
from lib import logging
from lib.utils import get_user_confirmation
from lib.led_map_2d import LEDMap2D
from lib.sfm.sfm import SFM
from lib.visualize_model import Renderer3D
from marimapper.reconstructor import Reconstructor
from marimapper import utils
from marimapper import logging
from marimapper.utils import get_user_confirmation
from marimapper.led_map_2d import LEDMap2D
from marimapper.sfm import SFM
from marimapper.visualize_model import Renderer3D
from multiprocessing import Queue
from lib.led_map_2d import get_all_2d_led_maps
from marimapper.led_map_2d import get_all_2d_led_maps


# PYCHARM DEVELOPER WARNING!
# You MUST enable "Emulate terminal in output console" in the run configuration or
# really weird stuff happens with multiprocessing!


class MariMapper:
class Scanner:

def __init__(self, cli_args):
self.output_dir = cli_args.output_dir
self.led_backend = utils.get_backend(cli_args.backend, cli_args.server)
os.makedirs(args.output_dir, exist_ok=True)
os.makedirs(cli_args.output_dir, exist_ok=True)

self.led_map_2d_queue = Queue()
self.led_map_3d_queue = Queue()
Expand Down Expand Up @@ -86,7 +80,7 @@ def mainloop(self):
# The filename is made out of the date, then the resolution of the camera
string_time = time.strftime("%Y%m%d-%H%M%S")

filepath = os.path.join(args.output_dir, f"led_map_2d_{string_time}.csv")
filepath = os.path.join(self.output_dir, f"led_map_2d_{string_time}.csv")

led_map_2d = LEDMap2D()

Expand Down Expand Up @@ -141,30 +135,3 @@ def mainloop(self):
self.led_maps_2d.append(led_map_2d)
self.sfm.add_led_maps_2d(self.led_maps_2d)
self.sfm.reload()


if __name__ == "__main__":

logging.info("Starting MariMapper")

parser = argparse.ArgumentParser(description="Captures LED flashes to file")

utils.add_camera_args(parser)
utils.add_backend_args(parser)

parser.add_argument(
"output_dir",
type=str,
help="The output folder for your capture",
)

args = parser.parse_args()

marimapper = MariMapper(cli_args=args)

marimapper.mainloop()
marimapper.close()

# For some reason python refuses to actually exit here, so I'm brute forcing it
os.kill(os.getpid(), signal.SIGINT)
os.kill(os.getpid(), signal.CTRL_C_EVENT)
File renamed without changes.
Loading

0 comments on commit 2a5a1d2

Please sign in to comment.