fix conficts with sam and polygon

This commit is contained in:
copper 2023-09-11 11:17:20 +08:00
parent 69a4733a00
commit 4af7020f5f
8 changed files with 2646 additions and 2325 deletions

281
.gitignore vendored Normal file
View File

@ -0,0 +1,281 @@
# File created using '.gitignore Generator' for Visual Studio Code: https://bit.ly/vscode-gig
# Created by https://www.toptal.com/developers/gitignore/api/windows,visualstudiocode,python,qt
# Edit at https://www.toptal.com/developers/gitignore?templates=windows,visualstudiocode,python,qt
### Python ###
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock
# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
#pdm.lock
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
# in version control.
# https://pdm.fming.dev/#use-with-ide
.pdm.toml
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
### Python Patch ###
# Poetry local configuration file - https://python-poetry.org/docs/configuration/#local-configuration
poetry.toml
# ruff
.ruff_cache/
# LSP config files
pyrightconfig.json
### Qt ###
# C++ objects and libs
*.slo
*.lo
*.o
*.a
*.la
*.lai
*.so.*
*.dll
*.dylib
# Qt-es
object_script.*.Release
object_script.*.Debug
*_plugin_import.cpp
/.qmake.cache
/.qmake.stash
*.pro.user
*.pro.user.*
*.qbs.user
*.qbs.user.*
*.moc
moc_*.cpp
moc_*.h
qrc_*.cpp
ui_*.h
*.qmlc
*.jsc
Makefile*
*build-*
*.qm
*.prl
# Qt unit tests
target_wrapper.*
# QtCreator
*.autosave
# QtCreator Qml
*.qmlproject.user
*.qmlproject.user.*
# QtCreator CMake
CMakeLists.txt.user*
# QtCreator 4.8< compilation database
compile_commands.json
# QtCreator local machine specific files for imported projects
*creator.user*
*_qmlcache.qrc
### VisualStudioCode ###
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
!.vscode/*.code-snippets
# Local History for Visual Studio Code
.history/
# Built Visual Studio Code Extensions
*.vsix
### VisualStudioCode Patch ###
# Ignore all local history of files
.history
.ionide
### Windows ###
# Windows thumbnail cache files
Thumbs.db
Thumbs.db:encryptable
ehthumbs.db
ehthumbs_vista.db
# Dump file
*.stackdump
# Folder config file
[Dd]esktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN/
# Windows Installer files
*.cab
*.msi
*.msix
*.msm
*.msp
# Windows shortcuts
*.lnk
# End of https://www.toptal.com/developers/gitignore/api/windows,visualstudiocode,python,qt
# Custom rules (everything added below won't be overriden by 'Generate .gitignore File' if you use 'Update' option)
# pytorch pth
*.pth

File diff suppressed because it is too large Load Diff

View File

@ -42,7 +42,8 @@ class SegAny:
self.model_type = "vit_h" self.model_type = "vit_h"
else: else:
raise ValueError('The checkpoint named {} is not supported.'.format(checkpoint)) raise ValueError('The checkpoint named {} is not supported.'.format(checkpoint))
else:
raise ValueError('The checkpoint named {} is not supported.'.format(checkpoint))
torch.cuda.empty_cache() torch.cuda.empty_cache()
self.device = 'cuda' if torch.cuda.is_available() else 'cpu' self.device = 'cuda' if torch.cuda.is_available() else 'cpu'

0
tools/__init__.py Normal file
View File

View File

@ -3,7 +3,7 @@
from PyQt5 import QtWidgets, QtCore, QtGui from PyQt5 import QtWidgets, QtCore, QtGui
from ui.ISAT_to_VOC_dialog import Ui_Dialog from ui.ISAT_to_VOC_dialog import Ui_Dialog
from tools.toVOC import TOVOC import tools.toVOC as toVOC
from configs import load_config from configs import load_config
import os import os
@ -16,7 +16,7 @@ class ISATtoVOCDialog(QtWidgets.QDialog, Ui_Dialog):
self.label_root = None self.label_root = None
self.save_root = None self.save_root = None
self.converter = TOVOC() self.converter = toVOC.TOVOC()
self.converter.message.connect(self.print_message) self.converter.message.connect(self.print_message)
self.setWindowModality(QtCore.Qt.WindowModality.WindowModal) self.setWindowModality(QtCore.Qt.WindowModality.WindowModal)

View File

@ -35,32 +35,25 @@ class AnnotationScene(QtWidgets.QGraphicsScene):
self.pressd = False self.pressd = False
def load_image(self, image_path:str): def load_image(self, image_path:str):
self.clear() if self.mainwindow.image_changed:
if self.mainwindow.use_segment_anything: self.clear()
self.mainwindow.segany.reset_image()
self.image_data = np.array(Image.open(image_path)) self.image_data = np.array(Image.open(image_path))
if self.mainwindow.use_segment_anything and self.mainwindow.can_be_annotated:
if self.image_data.ndim == 3 and self.image_data.shape[-1] == 3: # 三通道图
self.mainwindow.segany.set_image(self.image_data)
elif self.image_data.ndim == 2: # 单通道图
self.image_data = self.image_data[:, :, np.newaxis]
self.image_data = np.repeat(self.image_data, 3, axis=2) # 转换为三通道
self.mainwindow.segany.set_image(self.image_data)
else:
self.mainwindow.statusbar.showMessage("Segment anything don't support the image with shape {} .".format(self.image_data.shape))
self.image_item = QtWidgets.QGraphicsPixmapItem() self.image_item = QtWidgets.QGraphicsPixmapItem()
self.image_item.setZValue(0) self.image_item.setZValue(0)
self.addItem(self.image_item) self.addItem(self.image_item)
self.mask_item = QtWidgets.QGraphicsPixmapItem() self.mask_item = QtWidgets.QGraphicsPixmapItem()
self.mask_item.setZValue(1) self.mask_item.setZValue(1)
self.addItem(self.mask_item) self.addItem(self.mask_item)
self.image_item.setPixmap(QtGui.QPixmap(image_path)) self.image_item.setPixmap(QtGui.QPixmap(image_path))
self.setSceneRect(self.image_item.boundingRect()) self.setSceneRect(self.image_item.boundingRect())
self.change_mode_to_view() self.change_mode_to_view()
# for polygon in self.mainwindow.polygons:
# self.addItem(polygon)
def change_mode_to_create(self): def change_mode_to_create(self):
if self.image_item is None: if self.image_item is None:
return return
@ -145,6 +138,7 @@ class AnnotationScene(QtWidgets.QGraphicsScene):
def start_segment_anything(self): def start_segment_anything(self):
self.draw_mode = DRAWMode.SEGMENTANYTHING self.draw_mode = DRAWMode.SEGMENTANYTHING
self.start_draw() self.start_draw()
def start_draw_polygon(self): def start_draw_polygon(self):

View File

@ -25,6 +25,7 @@ import os
from PIL import Image from PIL import Image
import functools import functools
import imgviz import imgviz
import numpy as np
from segment_any.segment_any import SegAny from segment_any.segment_any import SegAny
from segment_any.gpu_resource import GPUResource_Thread, osplatform from segment_any.gpu_resource import GPUResource_Thread, osplatform
import icons_rc import icons_rc
@ -51,6 +52,8 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
self.load_finished = False self.load_finished = False
self.polygons:list = [] self.polygons:list = []
self.image_changed = False
self.png_palette = None # 图像拥有调色盘说明是单通道的标注png文件 self.png_palette = None # 图像拥有调色盘说明是单通道的标注png文件
self.instance_cmap = imgviz.label_colormap() self.instance_cmap = imgviz.label_colormap()
self.map_mode = MAPMode.LABEL self.map_mode = MAPMode.LABEL
@ -58,6 +61,8 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
self.current_label:Annotation = None self.current_label:Annotation = None
self.use_segment_anything = False self.use_segment_anything = False
self.gpu_resource_thread = None self.gpu_resource_thread = None
self.pre_segany = ''
self.segany = None
self.init_ui() self.init_ui()
self.reload_cfg() self.reload_cfg()
@ -80,8 +85,21 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
action.setChecked(model_name == name) action.setChecked(model_name == name)
self.use_segment_anything = False self.use_segment_anything = False
return return
try:
self.segany = SegAny(model_path) if self.segany is None:
self.segany = SegAny(model_path)
elif model_name != self.pre_segany:
self.segany = SegAny(model_path)
self.pre_segany = model_name
except Exception as e:
print(e)
QtWidgets.QMessageBox.warning(self, 'Warning',
'The model of [Segment anything] is not valid. If you want use quick annotate, please download from {}'.format(
'https://github.com/facebookresearch/segment-anything#model-checkpoints'))
for name, action in self.pths_actions.items():
action.setChecked(model_name == name)
self.use_segment_anything = False
return
self.use_segment_anything = True self.use_segment_anything = True
self.statusbar.showMessage('Use the checkpoint named {}.'.format(model_name), 3000) self.statusbar.showMessage('Use the checkpoint named {}.'.format(model_name), 3000)
for name, action in self.pths_actions.items(): for name, action in self.pths_actions.items():
@ -96,9 +114,26 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
self.labelGPUResource.setText('cpu') self.labelGPUResource.setText('cpu')
else: else:
self.labelGPUResource.setText('segment anything unused.') self.labelGPUResource.setText('segment anything unused.')
if self.current_index is None or ( -1> self.current_index >= len(self.files_list)):
return
file_path = os.path.join(self.image_root, self.files_list[self.current_index])
image_data = np.array(Image.open(file_path))
if image_data.ndim == 3 and image_data.shape[-1] == 3: # 三通道图
self.segany.set_image(image_data)
elif image_data.ndim == 2: # 单通道图
image_data = image_data[:, :, np.newaxis]
image_data = np.repeat(image_data, 3, axis=2) # 转换为三通道
self.segany.set_image(image_data)
elif image_data.ndim == 3 and image_data.shape[-1] > 3: # 多通道
self.segany.set_image(image_data[:,:,:3])
self.statusbar.showMessage("Segment anything only use the 3 dim with shape {} .".format(image_data.shape))
else:
self.statusbar.showMessage("Segment anything don't support the image with shape {} .".format(image_data.shape))
if self.current_index is not None: self.show_image(self.current_index)
self.show_image(self.current_index) # if self.current_index is not None:
# self.image_changed = False
# self.show_image(self.current_index)
def init_ui(self): def init_ui(self):
#q #q
@ -286,7 +321,7 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
if self.label_root is None: if self.label_root is None:
self.label_root = dir self.label_root = dir
self.actionSave_dir.setStatusTip("Label root: {}".format(self.label_root)) self.actionSave_dir.setStatusTip("Label root: {}".format(self.label_root))
self.image_changed = True
self.show_image(self.current_index) self.show_image(self.current_index)
def save_dir(self): def save_dir(self):
@ -322,10 +357,15 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
self.scene.clear() self.scene.clear()
self.scene.setSceneRect(QtCore.QRectF()) self.scene.setSceneRect(QtCore.QRectF())
return return
if not self.image_changed:
self.scene.cancel_draw()
return
try: try:
self.scene.cancel_draw()
self.polygons.clear() self.polygons.clear()
self.annos_dock_widget.listWidget.clear() self.annos_dock_widget.listWidget.clear()
self.scene.cancel_draw()
file_path = os.path.join(self.image_root, self.files_list[index]) file_path = os.path.join(self.image_root, self.files_list[index])
image_data = Image.open(file_path) image_data = Image.open(file_path)
@ -418,6 +458,7 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
self.current_index = 0 self.current_index = 0
QtWidgets.QMessageBox.warning(self, 'Warning', 'This is the first picture.') QtWidgets.QMessageBox.warning(self, 'Warning', 'This is the first picture.')
else: else:
self.image_changed = True
self.show_image(self.current_index) self.show_image(self.current_index)
def next_image(self): def next_image(self):
@ -434,7 +475,8 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
self.current_index = len(self.files_list)-1 self.current_index = len(self.files_list)-1
QtWidgets.QMessageBox.warning(self, 'Warning', 'This is the last picture.') QtWidgets.QMessageBox.warning(self, 'Warning', 'This is the last picture.')
else: else:
self.show_image(self.current_index) self.image_changed = True
self.show_image(self.current_index, True)
def jump_to(self): def jump_to(self):
index = self.files_dock_widget.lineEdit_jump.text() index = self.files_dock_widget.lineEdit_jump.text()
@ -448,6 +490,7 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
return return
index = int(index)-1 index = int(index)-1
if 0 <= index < len(self.files_list): if 0 <= index < len(self.files_list):
self.image_changed = True
self.show_image(index) self.show_image(index)
self.files_dock_widget.lineEdit_jump.clear() self.files_dock_widget.lineEdit_jump.clear()
else: else:
@ -577,6 +620,8 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
value = self.vertex_size.value() value = self.vertex_size.value()
self.cfg['vertex_size'] = value self.cfg['vertex_size'] = value
if self.current_index is not None: if self.current_index is not None:
# TODO: no clear
self.image_changed = False
self.show_image(self.current_index) self.show_image(self.current_index)
def ISAT_to_VOC(self): def ISAT_to_VOC(self):