diff --git a/README.md b/README.md index 96b971f..1559b55 100644 --- a/README.md +++ b/README.md @@ -34,12 +34,23 @@ The algorithm workflow looks like this: # Installation +This code can be run from a command-line or from a jupyter notebook. The following instructions are for running from the command-line. + ```shell git clone https://github.com/mbari/sdcat.git cd sdcat conda env create -f environment.yml ``` +Or, from a jupyter notebook. + +``` +conda activate sdcat +pip install ipykernel +python -m ipykernel install --user --name=sdcat +jupyter notebook +``` + A GPU is recommended for clustering and detection. If you don't have a GPU, you can still run the code, but it will be slower. If running on a CPU, multiple cores are recommended and will speed up processing. For large datasets, the RapidsAI cuDF library is recommended for faster processing, although it does not currently support diff --git a/environment.yml b/environment.yml index 1b0ce8f..5d8e9bc 100644 --- a/environment.yml +++ b/environment.yml @@ -2,7 +2,7 @@ name: sdcat channels: - conda-forge dependencies: - - python>=3.9 + - python >=3.9,<3.12 - pip - pip: - - -r requirements.txt + - -r requirements.txt \ No newline at end of file diff --git a/examples/.ipynb_checkpoints/sahi_detection-checkpoint.ipynb b/examples/.ipynb_checkpoints/sahi_detection-checkpoint.ipynb new file mode 100644 index 0000000..021f9ba --- /dev/null +++ b/examples/.ipynb_checkpoints/sahi_detection-checkpoint.ipynb @@ -0,0 +1,388 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "5fec46c020b895a", + "metadata": { + "collapsed": false, + "jupyter": { + "outputs_hidden": false + } + }, + "source": [ + "# Welcome to the SAHI detection notebook. \n", + "\n", + "This notebook introduces you to running the sliced detection method (SAHI). This is a lightweight wrapper on the SAHI method that does some pre-processing on the image before detection. Results are returned to a pandas dataframe for further inspection and saved to the output path specified in a CSV formatted output. More features are captured in the command line interface, such as creating a " + ] + }, + { + "cell_type": "markdown", + "id": "3ce3d68ddd33bd3c", + "metadata": { + "collapsed": false, + "jupyter": { + "outputs_hidden": false + } + }, + "source": [ + "# First, import needed dependencies" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "a3f1b6dd-b56f-47a7-948e-86be35336577", + "metadata": {}, + "outputs": [], + "source": [ + "import sys\n", + "sys.path.append('..')\n", + "from pathlib import Path\n", + "from huggingface_hub import hf_hub_download\n", + "from pathlib import Path\n", + "from sdcat.detect.sahi_detector import run_sahi_detect\n", + "from sahi import AutoDetectionModel" + ] + }, + { + "cell_type": "markdown", + "id": "a366e55bf59e7a79", + "metadata": { + "collapsed": false, + "jupyter": { + "outputs_hidden": false + } + }, + "source": [ + "# Run detection\n", + "\n", + "Let's process at 50 percent reduced size since the raw image is very large 7952x5304 and we don't need the full resolution to get reasonable results." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "9f9dd3f8-c886-4d32-a203-5204a343e721", + "metadata": { + "collapsed": false, + "is_executing": true, + "jupyter": { + "outputs_hidden": false + } + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "02/27/2024 10:08:17 - INFO - sdcat - Processing /Users/dcline/Dropbox/code/sdcat/sdcat/tests/data/bird/DSC00770.JPG\n", + "02/27/2024 10:08:17 - INFO - sdcat - Using slice size width: 1600 and height: 1600\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Performing prediction on 12 number of slices.\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "02/27/2024 10:08:26 - INFO - sdcat - ObjectPrediction<\n", + " bbox: BoundingBox: <(1652.4223022460938, 1269.49462890625, 1699.4335327148438, 1308.540771484375), w: 47.01123046875, h: 39.046142578125>,\n", + " mask: None,\n", + " score: PredictionScore: ,\n", + " category: Category: >\n", + "02/27/2024 10:08:26 - INFO - sdcat - ObjectPrediction<\n", + " bbox: BoundingBox: <(1616.7871704101562, 1135.657943725586, 1669.92333984375, 1169.05517578125), w: 53.13616943359375, h: 33.39723205566406>,\n", + " mask: None,\n", + " score: PredictionScore: ,\n", + " category: Category: >\n", + "02/27/2024 10:08:26 - INFO - sdcat - ObjectPrediction<\n", + " bbox: BoundingBox: <(914.9107, 2115.8342, 939.04364, 2148.281), w: 24.1329345703125, h: 32.44677734375>,\n", + " mask: None,\n", + " score: PredictionScore: ,\n", + " category: Category: >\n", + "02/27/2024 10:08:26 - INFO - sdcat - ObjectPrediction<\n", + " bbox: BoundingBox: <(1210.2857666015625, 1622.351806640625, 1255.767333984375, 1649.2919921875), w: 45.4815673828125, h: 26.940185546875>,\n", + " mask: None,\n", + " score: PredictionScore: ,\n", + " category: Category: >\n", + "02/27/2024 10:08:26 - INFO - sdcat - ObjectPrediction<\n", + " bbox: BoundingBox: <(2109.699951171875, 1098.7431640625, 2118.950210571289, 1107.9682922363281), w: 9.250259399414062, h: 9.225128173828125>,\n", + " mask: None,\n", + " score: PredictionScore: ,\n", + " category: Category: >\n", + "02/27/2024 10:08:26 - INFO - sdcat - ObjectPrediction<\n", + " bbox: BoundingBox: <(1197.94580078125, 1631.9464111328125, 1222.2314453125, 1648.218994140625), w: 24.28564453125, h: 16.2725830078125>,\n", + " mask: None,\n", + " score: PredictionScore: ,\n", + " category: Category: >\n", + "02/27/2024 10:08:26 - INFO - sdcat - ObjectPrediction<\n", + " bbox: BoundingBox: <(789.1007690429688, 1922.1368408203125, 802.0631103515625, 1937.4425048828125), w: 12.96234130859375, h: 15.3056640625>,\n", + " mask: None,\n", + " score: PredictionScore: ,\n", + " category: Category: >\n", + "02/27/2024 10:08:26 - INFO - sdcat - ObjectPrediction<\n", + " bbox: BoundingBox: <(1565.7776489257812, 938.5344848632812, 1624.9374389648438, 966.92041015625), w: 59.1597900390625, h: 28.38592529296875>,\n", + " mask: None,\n", + " score: PredictionScore: ,\n", + " category: Category: >\n", + "02/27/2024 10:08:26 - INFO - sdcat - ObjectPrediction<\n", + " bbox: BoundingBox: <(1471.7528076171875, 621.9021606445312, 1521.9717407226562, 647.9461669921875), w: 50.21893310546875, h: 26.04400634765625>,\n", + " mask: None,\n", + " score: PredictionScore: ,\n", + " category: Category: >\n" + ] + } + ], + "source": [ + "scale_percent = 50\n", + "image_path = Path.cwd().parent / 'sdcat' / 'tests' / 'data' / 'bird' / 'DSC00770.JPG'\n", + "csv_out_path = Path.cwd() / 'sahi' / f'{image_path.stem}.csv'\n", + "slice_width = 1600\n", + "slice_height = 1600\n", + "confidence = 0.1\n", + "\n", + "# Download the MBARI UAV model\n", + "model_path = hf_hub_download(repo_id=\"MBARI-org/uav-yolov5\", filename=\"best.pt\")\n", + "detection_model = AutoDetectionModel.from_pretrained(\n", + " model_type='yolov5',\n", + " model_path=model_path,\n", + " config_path=model_path,\n", + " confidence_threshold=confidence,\n", + " device='cpu',\n", + ")\n", + "\n", + "# Create the output directory \n", + "csv_out_path.parent.mkdir(parents=True, exist_ok=True)\n", + "\n", + "# Run the detection\n", + "df_detections = run_sahi_detect(scale_percent=scale_percent, \n", + " image_path=image_path,\n", + " csv_out_path=csv_out_path,\n", + " slice_width=slice_width,\n", + " slice_height=slice_height,\n", + " detection_model=detection_model)" + ] + }, + { + "cell_type": "markdown", + "id": "3bda2110765d92e2", + "metadata": { + "collapsed": false, + "jupyter": { + "outputs_hidden": false + } + }, + "source": [ + "# Results" + ] + }, + { + "cell_type": "markdown", + "id": "ae874cee7b4e83a9", + "metadata": { + "collapsed": false, + "jupyter": { + "outputs_hidden": false + } + }, + "source": [ + "Results are saved to the **csv_out_path**. Let's take a look at the first few rows of the dataframe." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "ee355052-7d9d-4eee-83f1-15ea15328e9e", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
image_pathclassscoreareasaliency...yxxxywh
0/Users/dcline/Dropbox/code/sdcat/sdcat/tests/d...Seagull0.2757941835.607208-1...2538.9892583398.8670652617.08154394.02246178.092285
0/Users/dcline/Dropbox/code/sdcat/sdcat/tests/d...Seagull0.2444111774.600981-1...2271.3158873339.8466802338.110352106.27233966.794464
0/Users/dcline/Dropbox/code/sdcat/sdcat/tests/d...Seagull0.221808783.035950-1...4231.6684571878.0872804296.56201248.26586964.893555
0/Users/dcline/Dropbox/code/sdcat/sdcat/tests/d...Seagull0.1968771225.281864-1...3244.7036132511.5346683298.58398490.96313553.880371
0/Users/dcline/Dropbox/code/sdcat/sdcat/tests/d...Seagull0.18374885.334829-1...2197.4863284237.9004212215.93658418.50051918.450256
\n", + "

5 rows × 11 columns

\n", + "
" + ], + "text/plain": [ + " image_path class score \\\n", + "0 /Users/dcline/Dropbox/code/sdcat/sdcat/tests/d... Seagull 0.275794 \n", + "0 /Users/dcline/Dropbox/code/sdcat/sdcat/tests/d... Seagull 0.244411 \n", + "0 /Users/dcline/Dropbox/code/sdcat/sdcat/tests/d... Seagull 0.221808 \n", + "0 /Users/dcline/Dropbox/code/sdcat/sdcat/tests/d... Seagull 0.196877 \n", + "0 /Users/dcline/Dropbox/code/sdcat/sdcat/tests/d... Seagull 0.183748 \n", + "\n", + " area saliency ... y xx xy \\\n", + "0 1835.607208 -1 ... 2538.989258 3398.867065 2617.081543 \n", + "0 1774.600981 -1 ... 2271.315887 3339.846680 2338.110352 \n", + "0 783.035950 -1 ... 4231.668457 1878.087280 4296.562012 \n", + "0 1225.281864 -1 ... 3244.703613 2511.534668 3298.583984 \n", + "0 85.334829 -1 ... 2197.486328 4237.900421 2215.936584 \n", + "\n", + " w h \n", + "0 94.022461 78.092285 \n", + "0 106.272339 66.794464 \n", + "0 48.265869 64.893555 \n", + "0 90.963135 53.880371 \n", + "0 18.500519 18.450256 \n", + "\n", + "[5 rows x 11 columns]" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df_detections.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "e05e028b-f431-4960-9a0a-779b9e07e58b", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "total 8\n", + "-rw-r--r-- 1 dcline 513 2032 Feb 27 10:08 DSC00770.csv\n" + ] + } + ], + "source": [ + "!ls -l /Users/dcline/Dropbox/code/sdcat/examples/sahi/" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "sdcat", + "language": "python", + "name": "sdcat" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/examples/sahi_detection.ipynb b/examples/sahi_detection.ipynb new file mode 100644 index 0000000..021f9ba --- /dev/null +++ b/examples/sahi_detection.ipynb @@ -0,0 +1,388 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "5fec46c020b895a", + "metadata": { + "collapsed": false, + "jupyter": { + "outputs_hidden": false + } + }, + "source": [ + "# Welcome to the SAHI detection notebook. \n", + "\n", + "This notebook introduces you to running the sliced detection method (SAHI). This is a lightweight wrapper on the SAHI method that does some pre-processing on the image before detection. Results are returned to a pandas dataframe for further inspection and saved to the output path specified in a CSV formatted output. More features are captured in the command line interface, such as creating a " + ] + }, + { + "cell_type": "markdown", + "id": "3ce3d68ddd33bd3c", + "metadata": { + "collapsed": false, + "jupyter": { + "outputs_hidden": false + } + }, + "source": [ + "# First, import needed dependencies" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "a3f1b6dd-b56f-47a7-948e-86be35336577", + "metadata": {}, + "outputs": [], + "source": [ + "import sys\n", + "sys.path.append('..')\n", + "from pathlib import Path\n", + "from huggingface_hub import hf_hub_download\n", + "from pathlib import Path\n", + "from sdcat.detect.sahi_detector import run_sahi_detect\n", + "from sahi import AutoDetectionModel" + ] + }, + { + "cell_type": "markdown", + "id": "a366e55bf59e7a79", + "metadata": { + "collapsed": false, + "jupyter": { + "outputs_hidden": false + } + }, + "source": [ + "# Run detection\n", + "\n", + "Let's process at 50 percent reduced size since the raw image is very large 7952x5304 and we don't need the full resolution to get reasonable results." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "9f9dd3f8-c886-4d32-a203-5204a343e721", + "metadata": { + "collapsed": false, + "is_executing": true, + "jupyter": { + "outputs_hidden": false + } + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "02/27/2024 10:08:17 - INFO - sdcat - Processing /Users/dcline/Dropbox/code/sdcat/sdcat/tests/data/bird/DSC00770.JPG\n", + "02/27/2024 10:08:17 - INFO - sdcat - Using slice size width: 1600 and height: 1600\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Performing prediction on 12 number of slices.\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "02/27/2024 10:08:26 - INFO - sdcat - ObjectPrediction<\n", + " bbox: BoundingBox: <(1652.4223022460938, 1269.49462890625, 1699.4335327148438, 1308.540771484375), w: 47.01123046875, h: 39.046142578125>,\n", + " mask: None,\n", + " score: PredictionScore: ,\n", + " category: Category: >\n", + "02/27/2024 10:08:26 - INFO - sdcat - ObjectPrediction<\n", + " bbox: BoundingBox: <(1616.7871704101562, 1135.657943725586, 1669.92333984375, 1169.05517578125), w: 53.13616943359375, h: 33.39723205566406>,\n", + " mask: None,\n", + " score: PredictionScore: ,\n", + " category: Category: >\n", + "02/27/2024 10:08:26 - INFO - sdcat - ObjectPrediction<\n", + " bbox: BoundingBox: <(914.9107, 2115.8342, 939.04364, 2148.281), w: 24.1329345703125, h: 32.44677734375>,\n", + " mask: None,\n", + " score: PredictionScore: ,\n", + " category: Category: >\n", + "02/27/2024 10:08:26 - INFO - sdcat - ObjectPrediction<\n", + " bbox: BoundingBox: <(1210.2857666015625, 1622.351806640625, 1255.767333984375, 1649.2919921875), w: 45.4815673828125, h: 26.940185546875>,\n", + " mask: None,\n", + " score: PredictionScore: ,\n", + " category: Category: >\n", + "02/27/2024 10:08:26 - INFO - sdcat - ObjectPrediction<\n", + " bbox: BoundingBox: <(2109.699951171875, 1098.7431640625, 2118.950210571289, 1107.9682922363281), w: 9.250259399414062, h: 9.225128173828125>,\n", + " mask: None,\n", + " score: PredictionScore: ,\n", + " category: Category: >\n", + "02/27/2024 10:08:26 - INFO - sdcat - ObjectPrediction<\n", + " bbox: BoundingBox: <(1197.94580078125, 1631.9464111328125, 1222.2314453125, 1648.218994140625), w: 24.28564453125, h: 16.2725830078125>,\n", + " mask: None,\n", + " score: PredictionScore: ,\n", + " category: Category: >\n", + "02/27/2024 10:08:26 - INFO - sdcat - ObjectPrediction<\n", + " bbox: BoundingBox: <(789.1007690429688, 1922.1368408203125, 802.0631103515625, 1937.4425048828125), w: 12.96234130859375, h: 15.3056640625>,\n", + " mask: None,\n", + " score: PredictionScore: ,\n", + " category: Category: >\n", + "02/27/2024 10:08:26 - INFO - sdcat - ObjectPrediction<\n", + " bbox: BoundingBox: <(1565.7776489257812, 938.5344848632812, 1624.9374389648438, 966.92041015625), w: 59.1597900390625, h: 28.38592529296875>,\n", + " mask: None,\n", + " score: PredictionScore: ,\n", + " category: Category: >\n", + "02/27/2024 10:08:26 - INFO - sdcat - ObjectPrediction<\n", + " bbox: BoundingBox: <(1471.7528076171875, 621.9021606445312, 1521.9717407226562, 647.9461669921875), w: 50.21893310546875, h: 26.04400634765625>,\n", + " mask: None,\n", + " score: PredictionScore: ,\n", + " category: Category: >\n" + ] + } + ], + "source": [ + "scale_percent = 50\n", + "image_path = Path.cwd().parent / 'sdcat' / 'tests' / 'data' / 'bird' / 'DSC00770.JPG'\n", + "csv_out_path = Path.cwd() / 'sahi' / f'{image_path.stem}.csv'\n", + "slice_width = 1600\n", + "slice_height = 1600\n", + "confidence = 0.1\n", + "\n", + "# Download the MBARI UAV model\n", + "model_path = hf_hub_download(repo_id=\"MBARI-org/uav-yolov5\", filename=\"best.pt\")\n", + "detection_model = AutoDetectionModel.from_pretrained(\n", + " model_type='yolov5',\n", + " model_path=model_path,\n", + " config_path=model_path,\n", + " confidence_threshold=confidence,\n", + " device='cpu',\n", + ")\n", + "\n", + "# Create the output directory \n", + "csv_out_path.parent.mkdir(parents=True, exist_ok=True)\n", + "\n", + "# Run the detection\n", + "df_detections = run_sahi_detect(scale_percent=scale_percent, \n", + " image_path=image_path,\n", + " csv_out_path=csv_out_path,\n", + " slice_width=slice_width,\n", + " slice_height=slice_height,\n", + " detection_model=detection_model)" + ] + }, + { + "cell_type": "markdown", + "id": "3bda2110765d92e2", + "metadata": { + "collapsed": false, + "jupyter": { + "outputs_hidden": false + } + }, + "source": [ + "# Results" + ] + }, + { + "cell_type": "markdown", + "id": "ae874cee7b4e83a9", + "metadata": { + "collapsed": false, + "jupyter": { + "outputs_hidden": false + } + }, + "source": [ + "Results are saved to the **csv_out_path**. Let's take a look at the first few rows of the dataframe." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "ee355052-7d9d-4eee-83f1-15ea15328e9e", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
image_pathclassscoreareasaliency...yxxxywh
0/Users/dcline/Dropbox/code/sdcat/sdcat/tests/d...Seagull0.2757941835.607208-1...2538.9892583398.8670652617.08154394.02246178.092285
0/Users/dcline/Dropbox/code/sdcat/sdcat/tests/d...Seagull0.2444111774.600981-1...2271.3158873339.8466802338.110352106.27233966.794464
0/Users/dcline/Dropbox/code/sdcat/sdcat/tests/d...Seagull0.221808783.035950-1...4231.6684571878.0872804296.56201248.26586964.893555
0/Users/dcline/Dropbox/code/sdcat/sdcat/tests/d...Seagull0.1968771225.281864-1...3244.7036132511.5346683298.58398490.96313553.880371
0/Users/dcline/Dropbox/code/sdcat/sdcat/tests/d...Seagull0.18374885.334829-1...2197.4863284237.9004212215.93658418.50051918.450256
\n", + "

5 rows × 11 columns

\n", + "
" + ], + "text/plain": [ + " image_path class score \\\n", + "0 /Users/dcline/Dropbox/code/sdcat/sdcat/tests/d... Seagull 0.275794 \n", + "0 /Users/dcline/Dropbox/code/sdcat/sdcat/tests/d... Seagull 0.244411 \n", + "0 /Users/dcline/Dropbox/code/sdcat/sdcat/tests/d... Seagull 0.221808 \n", + "0 /Users/dcline/Dropbox/code/sdcat/sdcat/tests/d... Seagull 0.196877 \n", + "0 /Users/dcline/Dropbox/code/sdcat/sdcat/tests/d... Seagull 0.183748 \n", + "\n", + " area saliency ... y xx xy \\\n", + "0 1835.607208 -1 ... 2538.989258 3398.867065 2617.081543 \n", + "0 1774.600981 -1 ... 2271.315887 3339.846680 2338.110352 \n", + "0 783.035950 -1 ... 4231.668457 1878.087280 4296.562012 \n", + "0 1225.281864 -1 ... 3244.703613 2511.534668 3298.583984 \n", + "0 85.334829 -1 ... 2197.486328 4237.900421 2215.936584 \n", + "\n", + " w h \n", + "0 94.022461 78.092285 \n", + "0 106.272339 66.794464 \n", + "0 48.265869 64.893555 \n", + "0 90.963135 53.880371 \n", + "0 18.500519 18.450256 \n", + "\n", + "[5 rows x 11 columns]" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "df_detections.head()" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "e05e028b-f431-4960-9a0a-779b9e07e58b", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "total 8\n", + "-rw-r--r-- 1 dcline 513 2032 Feb 27 10:08 DSC00770.csv\n" + ] + } + ], + "source": [ + "!ls -l /Users/dcline/Dropbox/code/sdcat/examples/sahi/" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "sdcat", + "language": "python", + "name": "sdcat" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/requirements.txt b/requirements.txt index 068efb9..17e14fd 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,6 +9,7 @@ hdbscan==0.8.33 torch tator piexif +yolov5==7.0.13 torchvision transformers timm @@ -24,6 +25,6 @@ huggingface-hub==0.19.4 umap-learn==0.5.5 hdbscan>=0.8.27 matplotlib==3.7.0 -numpy==1.24.1 numba==0.57 ephem +jupyter diff --git a/sdcat/detect/sahi_detector.py b/sdcat/detect/sahi_detector.py index dd70049..20d8ea8 100644 --- a/sdcat/detect/sahi_detector.py +++ b/sdcat/detect/sahi_detector.py @@ -25,17 +25,19 @@ def run_sahi_detect_bulk(scale_percent: int, slice_width: int, slice_height: int, images: list, - out_path: Path, + csv_out_path: Path, detection_model, allowable_classes: list = None, class_agnostic: bool = False): info(f'Processing {len(images)} images') + if not csv_out_path.is_dir(): + csv_out_path.mkdir(parents=True, exist_ok=True) for f in images: run_sahi_detect(scale_percent, slice_width, slice_height, f, - (out_path / f'{f.stem}.sahi.csv'), + (csv_out_path / f'{f.stem}.sahi.csv'), detection_model, allowable_classes=allowable_classes, class_agnostic=class_agnostic) @@ -45,7 +47,7 @@ def run_sahi_detect(scale_percent: int, slice_width: int, slice_height: int, image_path: Path, - out_path: Path, + csv_out_path: Path, detection_model, allowable_classes: list = None, class_agnostic: bool = False) -> pd.DataFrame: @@ -55,7 +57,7 @@ def run_sahi_detect(scale_percent: int, :param slice_width: slice size width :param slice_height: slice size height :param image_path: path to the image - :param out_path: output path for the detections + :param csv_out_path: output path for the detections :param image_color: color image :param detection_model: detection model :param allowable_classes: list of allowable classes @@ -63,6 +65,11 @@ def run_sahi_detect(scale_percent: int, :return: dataframe of detections """ df = pd.DataFrame() + # Abort if the image_path is not a file + if not image_path.is_file(): + exception(f'Image path {image_path} is not a file') + return df + info(f'Processing {image_path}') img_color = cv2.imread(image_path.as_posix()) img_color_rescaled = rescale(img_color, scale_percent=scale_percent) @@ -148,6 +155,8 @@ def run_sahi_detect(scale_percent: int, df[['y', 'xy', 'h']] *= scale_height # Write out the detections - df.to_csv(out_path.as_posix(), index=False) + df.to_csv(csv_out_path.as_posix(), index=False) except Exception as e: exception(f"Error processing {image_path}: {e}") + + return df