Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

devel -> master #153

Merged
merged 24 commits into from
Feb 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
d4b3b66
Fix 'remove overlaping detection' issue
bartoszptak Feb 12, 2024
d4031a9
Fix and add new test for OD
bartoszptak Feb 12, 2024
f31eb02
Remove unnecessary import causing errors
przemyslaw-aszkowski Feb 13, 2024
a6b78ef
Merge pull request #144 from PUTvision/fix_error_after_installation
przemyslaw-aszkowski Feb 13, 2024
d514372
added solar pv segmentation model
Kleebaue Feb 20, 2024
eb994e7
Merge pull request #146 from Kleebaue/devel
bartoszptak Feb 20, 2024
2ff484e
Merge pull request #147 from PUTvision/devel
bartoszptak Feb 20, 2024
1a25d1f
Replace global nms with kde
bartoszptak Feb 20, 2024
f3f5c98
Remove remove overlapping option, collapse export by default
bartoszptak Feb 21, 2024
76cea7b
Remove batching from export
bartoszptak Feb 21, 2024
02c5b9d
Remove scipy with own implementation of cKD, add test
bartoszptak Feb 21, 2024
0c4ed82
Update requirements
bartoszptak Feb 21, 2024
877085c
Update requirements
bartoszptak Feb 21, 2024
336a1a2
Update requirement message
bartoszptak Feb 21, 2024
0d93923
Change requirements branch
bartoszptak Feb 21, 2024
e531992
Merge pull request #142 from PUTvision/fix_nms
bartoszptak Feb 21, 2024
925fa21
Update gitignore
bartoszptak Feb 22, 2024
159edeb
Move requirements to plugin, update installator
bartoszptak Feb 22, 2024
667fce2
Update preprocessing_utils.py
bartoszptak Feb 22, 2024
d0d21c0
Update deepness_dockwidget.py
bartoszptak Feb 22, 2024
59cd225
Fix installation dialog error
przemyslaw-aszkowski Feb 23, 2024
6dbba77
Merge pull request #148 from PUTvision/update_requirements
przemyslaw-aszkowski Feb 23, 2024
4a95992
version bumped
przemyslaw-aszkowski Feb 23, 2024
cfd70a6
Merge pull request #152 from PUTvision/update_requirements
przemyslaw-aszkowski Feb 23, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/python-app-ubuntu.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,8 @@ jobs:
- name: Install dependencies
run: |
pip install --upgrade pip
pip install --upgrade -r requirements.txt
pip install --upgrade -r requirements_development.txt
pip install --upgrade -r ./src/deepness/python_requirements/requirements.txt
pip install --upgrade -r ./src/deepness/python_requirements/requirements_development.txt
- name: Lint with flake8
run: |
# stop the build if there are Python syntax errors or undefined names
Expand All @@ -56,7 +56,7 @@ jobs:
# apparently there is some issue with opencv-python-headless, we need to reinstall it
pip uninstall opencv-python-headless --yes

pip install opencv-python-headless==4.6.0.66
pip install --upgrade -r ./src/deepness/python_requirements/requirements.txt
# run one this without pytest, because pytest creates obfuscated error messages
# we need 'xvfb-run' to simulate UI - otherwise qgis crushes
xvfb-run python3 test/test_map_processor_segmentation.py
Expand Down
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,7 @@ compile_commands.json

# End of https://www.toptal.com/developers/gitignore/api/python,pycharm,qt


grid_data
.idea/

src/deepness/python3.10/
_autosummary/
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ ln -s $PROJECT_DIR/src/deepness ~/.local/share/QGIS/QGIS3/profiles/default/pytho

```bash
. venv/bin/activate
pip install -r requirements.txt
pip install -r ./src/deepness/python_requirements/requirements.txt
```

- Run QGis in the virtual environment:
Expand Down
2 changes: 0 additions & 2 deletions docs/source/creators/creators_add_metadata_to_model.rst
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,6 @@ List of parameters parsed by plugin
+----------------------+-------+---------------------------------------+-------------------------------------------------------------+
| det_type | str | :code:`YOLO_v5_or_v7_default` | Detector: type of the detector model format |
+----------------------+-------+---------------------------------------+-------------------------------------------------------------+
| det_remove_overlap | bool | :code:`True` | Detector: Whether overlapping detection should be removed |
+----------------------+-------+---------------------------------------+-------------------------------------------------------------+

=======
Example
Expand Down
68 changes: 37 additions & 31 deletions docs/source/main/main_installation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,37 +2,6 @@ Installation
============


============
Requirements
============

* Ubuntu

* (option 1) Install requirements using system Python interpreter:

.. code-block::

python3 -m pip install opencv-python-headless onnxruntime-gpu

* (option 2) Run QGIS and Python Console. Then call command:

.. code-block::

import pip; pip.main(['install', 'opencv-python-headless', 'onnxruntime-gpu'])


* Windows

* Go to QGIS installation path (for example :code:`C:\Program Files\QGIS 3.26.3\`)

* Run :code:`OSGeo4W.bat` and type installation command:

.. code-block::

python3 -m pip install opencv-python-headless onnxruntime-gpu

* MacOS - SOON

===================
Plugin installation
===================
Expand Down Expand Up @@ -69,3 +38,40 @@ Plugin installation
* Select the ZIP file using system prompt

* Click the Install Plugin button

============
Requirements
============

The plugin should install all required dependencies automatically during the first run. However, if you want to install them manually, you can use the following commands:

.. note::

The plugin requirements and versions are listed in the `requirements.txt <https://github.com/PUTvision/qgis-plugin-deepness/blob/master/src/deepness/python_requirements/requirements.txt>`_ file.

* Ubuntu

* (option 1) Install requirements using system Python interpreter:

.. code-block::

python3 -m pip install opencv-python-headless onnxruntime-gpu

* (option 2) Run QGIS and Python Console. Then call command:

.. code-block::

import pip; pip.main(['install', 'opencv-python-headless', 'onnxruntime-gpu'])


* Windows

* Go to QGIS installation path (for example :code:`C:\Program Files\QGIS 3.26.3\`)

* Run :code:`OSGeo4W.bat` and type installation command:

.. code-block::

python3 -m pip install opencv-python-headless onnxruntime-gpu

* MacOS - SOON
1 change: 1 addition & 0 deletions docs/source/main/model_zoo/MODEL_ZOO.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ The [Model ZOO](https://chmura.put.poznan.pl/s/2pJk4izRurzQwu3) is a collection
| [Agriculture segmentation RGB+NIR](https://chmura.put.poznan.pl/s/wf5Ml1ZDyiVdNiy) | 256 | 30 | Trained on the [Agriculture Vision 2021 dataset](https://www.agriculture-vision.com/agriculture-vision-2021/dataset-2021). 4 channels input (RGB + NIR). 9 output classes within agricultural field (weed_cluster, waterway, ...). Uses X-UNet. | [Image](https://chmura.put.poznan.pl/s/35A5ISUxLxcK7kL) |
| [Fire risk assesment](https://chmura.put.poznan.pl/s/NxKLdfdr9s9jsVA) | 384 | 100 | Trained on the FireRisk dataset (RGB data). Classifies risk of fires (ver_high, high, low, ...). Uses ConvNeXt XXL. Val F1-score 65.5. | [Image](https://chmura.put.poznan.pl/s/Ijn3VgG76NvYtDY) |
| [Roads Segmentation](https://chmura.put.poznan.pl/s/y6S3CmodPy1fYYz) | 512 | 21 | The model segments the Google Earth satellite images into 'road' and 'not-road' classes. Model works best on wide car roads, crossroads and roundabouts. | [Image](https://chmura.put.poznan.pl/s/rln6mpbjpsXWpKg) |
| [Solar PV Segmentation](https://owncloud.fraunhofer.de/index.php/s/Ph9TC6BTxPi5oZZ) | 512 | 3 | Model trained by M Kleebauer et al. in "[Multi-resolution segmentation of solar photovoltaic systems using deep learning](https://www.mdpi.com/2596164) on a diverse range of image data, spanning UAV, aerial, and satellite imagery at both native and aggregated resolutions of 0.1 m, 0.2 m, 0.3 m, 0.8 m, 1.6 m, and 3.2 m. | [Image](https://github.com/Kleebaue/multi-resolution-pv-system-segmentation/blob/main/figures/prediction_multi_res.png) |

## Regression models

Expand Down
9 changes: 0 additions & 9 deletions requirements.txt

This file was deleted.

1 change: 0 additions & 1 deletion src/deepness/common/config_entry_key.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ class ConfigEntryKey(enum.Enum):

DETECTION_CONFIDENCE = enum.auto(), 0.5
DETECTION_IOU = enum.auto(), 0.5
DETECTION_REMOVE_OVERLAPPING = enum.auto(), True
DETECTOR_TYPE = enum.auto(), 'YOLO_v5_v7_DEFAULT'

DATA_EXPORT_DIR = enum.auto(), ''
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,5 @@ class DetectionParameters(MapProcessingParameters):

confidence: float
iou_threshold: float
remove_overlapping_detections: bool # whether overlapping detections can be deleted

detector_type: DetectorType = DetectorType.YOLO_v5_v7_DEFAULT # parameters specific for each model type
3 changes: 2 additions & 1 deletion src/deepness/deepness.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
MapProcessingResultFailed,
MapProcessingResultSuccess)
from deepness.processing.map_processor.map_processor_training_data_export import MapProcessorTrainingDataExport
from deepness.processing.models.model_types import ModelDefinition

cv2 = LazyPackageLoader('cv2')

Expand Down Expand Up @@ -252,6 +251,8 @@ def _run_training_data_export(self, training_data_export_parameters: TrainingDat
self._display_processing_started_info()

def _run_model_inference(self, params: MapProcessingParameters):
from deepness.processing.models.model_types import ModelDefinition # import here to avoid pulling external dependencies to early

if not self._are_map_processing_parameters_are_correct(params):
return

Expand Down
44 changes: 26 additions & 18 deletions src/deepness/deepness_dockwidget.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from deepness.common.config_entry_key import ConfigEntryKey
from deepness.common.defines import IS_DEBUG, PLUGIN_NAME
from deepness.common.errors import OperationFailedException
from deepness.common.lazy_package_loader import LazyPackageLoader
from deepness.common.processing_overlap import ProcessingOverlap, ProcessingOverlapOptions
from deepness.common.processing_parameters.detection_parameters import DetectionParameters, DetectorType
from deepness.common.processing_parameters.map_processing_parameters import (MapProcessingParameters, ModelOutputFormat,
Expand All @@ -23,12 +24,11 @@
from deepness.common.processing_parameters.segmentation_parameters import SegmentationParameters
from deepness.common.processing_parameters.superresolution_parameters import SuperresolutionParameters
from deepness.common.processing_parameters.training_data_export_parameters import TrainingDataExportParameters
from deepness.processing.models.detector import Detector
from deepness.processing.models.model_base import ModelBase
from deepness.processing.models.model_types import ModelDefinition, ModelType
from deepness.widgets.input_channels_mapping.input_channels_mapping_widget import InputChannelsMappingWidget
from deepness.widgets.training_data_export_widget.training_data_export_widget import TrainingDataExportWidget


FORM_CLASS, _ = uic.loadUiType(os.path.join(
os.path.dirname(__file__), 'deepness_dockwidget.ui'))

Expand Down Expand Up @@ -113,7 +113,6 @@ def _load_ui_from_config(self):

self.doubleSpinBox_confidence.setValue(ConfigEntryKey.DETECTION_CONFIDENCE.get())
self.doubleSpinBox_iouScore.setValue(ConfigEntryKey.DETECTION_IOU.get())
self.checkBox_removeOverlappingDetections.setChecked(ConfigEntryKey.DETECTION_REMOVE_OVERLAPPING.get())
self.comboBox_detectorType.setCurrentText(ConfigEntryKey.DETECTOR_TYPE.get())
except Exception:
logging.exception("Failed to load the ui state from config!")
Expand Down Expand Up @@ -146,7 +145,6 @@ def _save_ui_to_config(self):

ConfigEntryKey.DETECTION_CONFIDENCE.set(self.doubleSpinBox_confidence.value())
ConfigEntryKey.DETECTION_IOU.set(self.doubleSpinBox_iouScore.value())
ConfigEntryKey.DETECTION_REMOVE_OVERLAPPING.set(self.checkBox_removeOverlappingDetections.isChecked())
ConfigEntryKey.DETECTOR_TYPE.set(self.comboBox_detectorType.currentText())

self._input_channels_mapping_widget.save_ui_to_config()
Expand All @@ -158,6 +156,8 @@ def _rlayer_updated(self):
def _setup_misc_ui(self):
""" Setup some misceleounous ui forms
"""
from deepness.processing.models.model_types import ModelDefinition # import here to avoid pulling external dependencies to early

self._show_debug_warning()
combobox = self.comboBox_processedAreaSelection
for name in ProcessedAreaType.get_all_names():
Expand All @@ -168,6 +168,8 @@ def _setup_misc_ui(self):

self.mMapLayerComboBox_inputLayer.setFilters(QgsMapLayerProxyModel.RasterLayer)
self.mMapLayerComboBox_areaMaskLayer.setFilters(QgsMapLayerProxyModel.VectorLayer)

self.mGroupBox_8.setCollapsed(True) # collapse the group by default
self._set_processed_area_mask_options()
self._set_processing_overlap_enabled()

Expand Down Expand Up @@ -212,6 +214,8 @@ def _create_connections(self):
self.radioButton_processingTileOverlapPixels.toggled.connect(self._set_processing_overlap_enabled)

def _model_type_changed(self):
from deepness.processing.models.model_types import ModelType # import here to avoid pulling external dependencies to early

model_type = ModelType(self.comboBox_modelType.currentText())

segmentation_enabled = False
Expand Down Expand Up @@ -251,11 +255,11 @@ def _model_output_format_changed(self):
model_output_format = ModelOutputFormat(txt)
class_number_selection_enabled = bool(model_output_format == ModelOutputFormat.ONLY_SINGLE_CLASS_AS_LAYER)
self.comboBox_outputFormatClassNumber.setEnabled(class_number_selection_enabled)

def _set_processing_overlap_enabled(self):
overlap_percentage_enabled = self.radioButton_processingTileOverlapPercentage.isChecked()
self.spinBox_processingTileOverlapPercentage.setEnabled(overlap_percentage_enabled)

overlap_pixels_enabled = self.radioButton_processingTileOverlapPixels.isChecked()
self.spinBox_processingTileOverlapPixels.setEnabled(overlap_pixels_enabled)

Expand Down Expand Up @@ -284,15 +288,15 @@ def _browse_query_image_path(self):
)
if file_path:
self.lineEdit_recognitionPath.setText(file_path)

def _load_default_model_parameters(self):
"""
Load the default parameters from model metadata
"""
value = self._model.get_metadata_resolution()
if value is not None:
self.doubleSpinBox_resolution_cm_px.setValue(value)

value = self._model.get_model_batch_size()
if value is not None:
self.spinBox_batchSize.setValue(value)
Expand Down Expand Up @@ -339,15 +343,13 @@ def _load_default_model_parameters(self):
if value is not None:
self.doubleSpinBox_iouScore.setValue(value)

value = self._model.get_metadata_detection_remove_overlapping()
if value is not None:
self.checkBox_removeOverlappingDetections.setChecked(value)

def _load_model_with_type_from_metadata(self, model_class_from_ui, file_path):
"""
If model has model_type in metadata - use this type to create proper model class.
Otherwise model_class_from_ui will be used
"""
from deepness.processing.models.model_types import ModelDefinition, ModelType # import here to avoid pulling external dependencies to early

model_class = model_class_from_ui

model_type_str_from_metadata = ModelBase.get_model_type_from_metadata(file_path)
Expand All @@ -365,6 +367,9 @@ def _load_model_and_display_info(self, abort_if_no_file_path: bool = False):
"""
Tries to load the model and display its message.
"""
from deepness.processing.models.model_types import ModelType # import here to avoid pulling external dependencies to early
import deepness.processing.models.detector as detector_module # import here to avoid pulling external dependencies to early

file_path = self.lineEdit_modelPath.text()

if not file_path and abort_if_no_file_path:
Expand All @@ -387,13 +392,13 @@ def _load_model_and_display_info(self, abort_if_no_file_path: bool = False):
# TODO idk how variable input will be handled
self.spinBox_tileSize_px.setValue(input_size_px)
self.spinBox_tileSize_px.setEnabled(False)

if batch_size is not None:
self.spinBox_batchSize.setValue(batch_size)
self.spinBox_batchSize.setEnabled(False)
else:
self.spinBox_batchSize.setEnabled(True)

self._input_channels_mapping_widget.set_model(self._model)

# super resolution
Expand All @@ -418,7 +423,7 @@ def _load_model_and_display_info(self, abort_if_no_file_path: bool = False):

self.label_modelInfo.setText(txt)

if isinstance(self._model, Detector):
if isinstance(self._model, detector_module.Detector):
detector_type = DetectorType(self.comboBox_detectorType.currentText())
self._model.set_model_type_param(detector_type)

Expand Down Expand Up @@ -470,10 +475,12 @@ def _get_pixel_classification_threshold(self):
return 0
return self.doubleSpinBox_probabilityThreshold.value()

def get_selected_model_class_definition(self) -> ModelDefinition:
def get_selected_model_class_definition(self): # -> ModelDefinition: # we cannot import it here yet
"""
Get the currently selected model class (in UI)
"""
from deepness.processing.models.model_types import ModelDefinition, ModelType # import here to avoid pulling external dependencies to early

model_type_txt = self.comboBox_modelType.currentText()
model_type = ModelType(model_type_txt)
model_definition = ModelDefinition.get_definition_for_type(model_type)
Expand All @@ -483,6 +490,8 @@ def get_inference_parameters(self) -> MapProcessingParameters:
""" Get the parameters for the model interface.
The returned type is derived from `MapProcessingParameters` class, depending on the selected model type.
"""
from deepness.processing.models.model_types import ModelType # import here to avoid pulling external dependencies to early

map_processing_parameters = self._get_map_processing_parameters()

if self._model is None:
Expand Down Expand Up @@ -541,14 +550,13 @@ def get_recognition_parameters(self, map_processing_parameters: MapProcessingPar
query_image_path=self.lineEdit_recognitionPath.text(),
)
return params

def get_detection_parameters(self, map_processing_parameters: MapProcessingParameters) -> DetectionParameters:

params = DetectionParameters(
**map_processing_parameters.__dict__,
confidence=self.doubleSpinBox_confidence.value(),
iou_threshold=self.doubleSpinBox_iouScore.value(),
remove_overlapping_detections=self.checkBox_removeOverlappingDetections.isChecked(),
model=self._model,
detector_type=DetectorType(self.comboBox_detectorType.currentText()),
)
Expand Down
Loading
Loading