Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
pt2d
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Iterations
Wiki
Requirements
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Locked files
Build
Pipelines
Jobs
Pipeline schedules
Test cases
Artifacts
Deploy
Releases
Package registry
Container Registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Code review analytics
Issue analytics
Insights
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
QIM
Tools
pt2d
Commits
6bcc3a83
Commit
6bcc3a83
authored
3 months ago
by
s224361
Browse files
Options
Downloads
Patches
Plain Diff
Cleaned up modules
parent
4cfed8cb
No related branches found
No related tags found
No related merge requests found
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
modules/mainWindow.py
+62
-21
62 additions, 21 deletions
modules/mainWindow.py
with
62 additions
and
21 deletions
modules/mainWindow.py
+
62
−
21
View file @
6bcc3a83
import
math
import
math
import
numpy
as
np
import
numpy
as
np
from
scipy.signal
import
savgol_filter
from
PyQt5.QtWidgets
import
(
from
PyQt5.QtWidgets
import
(
QMainWindow
,
QPushButton
,
QHBoxLayout
,
QMainWindow
,
QPushButton
,
QHBoxLayout
,
QVBoxLayout
,
QWidget
,
QFileDialog
QVBoxLayout
,
QWidget
,
QFileDialog
)
)
from
PyQt5.QtGui
import
QPixmap
,
QImage
from
PyQt5.QtGui
import
QPixmap
,
QImage
from
PyQt5.QtCore
import
QCloseEvent
from
compute_cost_image
import
compute_cost_image
from
compute_cost_image
import
compute_cost_image
from
preprocess_image
import
preprocess_image
from
preprocess_image
import
preprocess_image
from
advancedSettingsWidget
import
AdvancedSettingsWidget
from
advancedSettingsWidget
import
AdvancedSettingsWidget
...
@@ -21,28 +21,26 @@ class MainWindow(QMainWindow):
...
@@ -21,28 +21,26 @@ class MainWindow(QMainWindow):
self
.
_circle_calibrated_radius
=
6
self
.
_circle_calibrated_radius
=
6
self
.
_last_loaded_file_path
=
None
self
.
_last_loaded_file_path
=
None
#
F
or the contrast slider
#
Value f
or the contrast slider
self
.
_current_clip_limit
=
0.01
self
.
_current_clip_limit
=
0.01
# Outer widget
+
layout
# Outer widget
and
layout
self
.
_main_widget
=
QWidget
()
self
.
_main_widget
=
QWidget
()
self
.
_main_layout
=
QHBoxLayout
(
self
.
_main_widget
)
self
.
_main_layout
=
QHBoxLayout
(
self
.
_main_widget
)
#
The "left" part: c
ontainer for the image area
+
its controls
#
C
ontainer for the image area
and
its controls
self
.
_left_panel
=
QVBoxLayout
()
self
.
_left_panel
=
QVBoxLayout
()
#
We'll make a c
ontainer widget for
the left panel, so we can set stretches:
#
C
ontainer widget for
stretching the panel
self
.
_left_container
=
QWidget
()
self
.
_left_container
=
QWidget
()
self
.
_left_container
.
setLayout
(
self
.
_left_panel
)
self
.
_left_container
.
setLayout
(
self
.
_left_panel
)
# Now we add them to the main layout with 70%:30% ratio
self
.
_main_layout
.
addWidget
(
self
.
_left_container
,
7
)
# 70% ratio of the full window
self
.
_main_layout
.
addWidget
(
self
.
_left_container
,
7
)
# 70%
#
We haven't added the advanced widget yet, but we'll do so with ratio=3 => 30%
#
Advanced widget window
self
.
_advanced_widget
=
AdvancedSettingsWidget
(
self
)
self
.
_advanced_widget
=
AdvancedSettingsWidget
(
self
)
# Hide it initially
self
.
_advanced_widget
.
hide
()
self
.
_advanced_widget
.
hide
()
self
.
_main_layout
.
addWidget
(
self
.
_advanced_widget
,
3
)
self
.
_main_layout
.
addWidget
(
self
.
_advanced_widget
,
3
)
# 30% ratio of the full window
self
.
setCentralWidget
(
self
.
_main_widget
)
self
.
setCentralWidget
(
self
.
_main_widget
)
...
@@ -64,7 +62,6 @@ class MainWindow(QMainWindow):
...
@@ -64,7 +62,6 @@ class MainWindow(QMainWindow):
self
.
btn_clear_points
.
clicked
.
connect
(
self
.
clear_points
)
self
.
btn_clear_points
.
clicked
.
connect
(
self
.
clear_points
)
btn_layout
.
addWidget
(
self
.
btn_clear_points
)
btn_layout
.
addWidget
(
self
.
btn_clear_points
)
# "Advanced Settings" toggle
self
.
btn_advanced
=
QPushButton
(
"
Advanced Settings
"
)
self
.
btn_advanced
=
QPushButton
(
"
Advanced Settings
"
)
self
.
btn_advanced
.
setCheckable
(
True
)
self
.
btn_advanced
.
setCheckable
(
True
)
self
.
btn_advanced
.
clicked
.
connect
(
self
.
_toggle_advanced_settings
)
self
.
btn_advanced
.
clicked
.
connect
(
self
.
_toggle_advanced_settings
)
...
@@ -76,7 +73,10 @@ class MainWindow(QMainWindow):
...
@@ -76,7 +73,10 @@ class MainWindow(QMainWindow):
self
.
_old_central_widget
=
None
self
.
_old_central_widget
=
None
self
.
_editor
=
None
self
.
_editor
=
None
def
_toggle_advanced_settings
(
self
,
checked
):
def
_toggle_advanced_settings
(
self
,
checked
:
bool
):
"""
Toggles the visibility of the advanced settings widget.
"""
if
checked
:
if
checked
:
self
.
_advanced_widget
.
show
()
self
.
_advanced_widget
.
show
()
else
:
else
:
...
@@ -84,8 +84,11 @@ class MainWindow(QMainWindow):
...
@@ -84,8 +84,11 @@ class MainWindow(QMainWindow):
# Force re-layout
# Force re-layout
self
.
adjustSize
()
self
.
adjustSize
()
def
open_circle_editor
(
self
):
def
open_circle_editor
(
self
):
"""
Replace central widget with circle editor.
"""
"""
Replace central widget with circle editor.
"""
if
not
self
.
_last_loaded_pixmap
:
if
not
self
.
_last_loaded_pixmap
:
print
(
"
No image loaded yet! Cannot open circle editor.
"
)
print
(
"
No image loaded yet! Cannot open circle editor.
"
)
return
return
...
@@ -102,10 +105,17 @@ class MainWindow(QMainWindow):
...
@@ -102,10 +105,17 @@ class MainWindow(QMainWindow):
self
.
_editor
=
editor
self
.
_editor
=
editor
self
.
setCentralWidget
(
editor
)
self
.
setCentralWidget
(
editor
)
def
_on_circle_editor_done
(
self
,
final_radius
):
def
_on_circle_editor_done
(
self
,
final_radius
:
int
):
"""
Updates the calibrated radius, computes the cost image based on the new radius,
and updates the image view with the new cost image.
It also restores the previous central widget and cleans up the editor widget.
"""
self
.
_circle_calibrated_radius
=
final_radius
self
.
_circle_calibrated_radius
=
final_radius
print
(
f
"
Circle Editor done. Radius =
{
final_radius
}
"
)
print
(
f
"
Circle Editor done. Radius =
{
final_radius
}
"
)
# Update cost image and path using new radius
if
self
.
_last_loaded_file_path
:
if
self
.
_last_loaded_file_path
:
cost_img
=
compute_cost_image
(
cost_img
=
compute_cost_image
(
self
.
_last_loaded_file_path
,
self
.
_last_loaded_file_path
,
...
@@ -118,6 +128,7 @@ class MainWindow(QMainWindow):
...
@@ -118,6 +128,7 @@ class MainWindow(QMainWindow):
self
.
image_view
.
_rebuild_full_path
()
self
.
image_view
.
_rebuild_full_path
()
self
.
_update_advanced_images
()
self
.
_update_advanced_images
()
# Swap back to central widget
editor_widget
=
self
.
takeCentralWidget
()
editor_widget
=
self
.
takeCentralWidget
()
if
editor_widget
is
not
None
:
if
editor_widget
is
not
None
:
editor_widget
.
setParent
(
None
)
editor_widget
.
setParent
(
None
)
...
@@ -131,15 +142,23 @@ class MainWindow(QMainWindow):
...
@@ -131,15 +142,23 @@ class MainWindow(QMainWindow):
self
.
_editor
=
None
self
.
_editor
=
None
def
toggle_rainbow
(
self
):
def
toggle_rainbow
(
self
):
"""
Toggle rainbow coloring of the path.
"""
self
.
image_view
.
toggle_rainbow
()
self
.
image_view
.
toggle_rainbow
()
def
load_image
(
self
):
def
load_image
(
self
):
"""
Load an image and update the image view and cost image.
The supported image formats are: PNG, JPG, JPEG, BMP, and TIF.
"""
options
=
QFileDialog
.
Options
()
options
=
QFileDialog
.
Options
()
file_path
,
_
=
QFileDialog
.
getOpenFileName
(
file_path
,
_
=
QFileDialog
.
getOpenFileName
(
self
,
"
Open Image
"
,
""
,
self
,
"
Open Image
"
,
""
,
"
Images (*.png *.jpg *.jpeg *.bmp *.tif)
"
,
"
Images (*.png *.jpg *.jpeg *.bmp *.tif)
"
,
options
=
options
options
=
options
)
)
if
file_path
:
if
file_path
:
self
.
image_view
.
load_image
(
file_path
)
self
.
image_view
.
load_image
(
file_path
)
...
@@ -158,7 +177,10 @@ class MainWindow(QMainWindow):
...
@@ -158,7 +177,10 @@ class MainWindow(QMainWindow):
self
.
_last_loaded_file_path
=
file_path
self
.
_last_loaded_file_path
=
file_path
self
.
_update_advanced_images
()
self
.
_update_advanced_images
()
def
update_contrast
(
self
,
clip_limit
):
def
update_contrast
(
self
,
clip_limit
:
float
):
"""
Updates and applies the contrast value of the image.
"""
self
.
_current_clip_limit
=
clip_limit
self
.
_current_clip_limit
=
clip_limit
if
self
.
_last_loaded_file_path
:
if
self
.
_last_loaded_file_path
:
cost_img
=
compute_cost_image
(
cost_img
=
compute_cost_image
(
...
@@ -174,6 +196,10 @@ class MainWindow(QMainWindow):
...
@@ -174,6 +196,10 @@ class MainWindow(QMainWindow):
self
.
_update_advanced_images
()
self
.
_update_advanced_images
()
def
_update_advanced_images
(
self
):
def
_update_advanced_images
(
self
):
"""
Updates the advanced images display with the latest image.
If no image has been loaded, the method returns without making any updates.
"""
if
not
self
.
_last_loaded_pixmap
:
if
not
self
.
_last_loaded_pixmap
:
return
return
pm_np
=
self
.
_qpixmap_to_gray_float
(
self
.
_last_loaded_pixmap
)
pm_np
=
self
.
_qpixmap_to_gray_float
(
self
.
_last_loaded_pixmap
)
...
@@ -185,7 +211,16 @@ class MainWindow(QMainWindow):
...
@@ -185,7 +211,16 @@ class MainWindow(QMainWindow):
cost_img_np
=
self
.
image_view
.
cost_image
cost_img_np
=
self
.
image_view
.
cost_image
self
.
_advanced_widget
.
update_displays
(
contrasted_blurred
,
cost_img_np
)
self
.
_advanced_widget
.
update_displays
(
contrasted_blurred
,
cost_img_np
)
def
_qpixmap_to_gray_float
(
self
,
qpix
):
def
_qpixmap_to_gray_float
(
self
,
qpix
:
QPixmap
)
->
np
.
ndarray
:
"""
Convert a QPixmap to a grayscale float array.
Args:
qpix: The QPixmap to be converted.
Returns:
A 2D numpy array representing the grayscale image.
"""
img
=
qpix
.
toImage
()
img
=
qpix
.
toImage
()
img
=
img
.
convertToFormat
(
QImage
.
Format_ARGB32
)
img
=
img
.
convertToFormat
(
QImage
.
Format_ARGB32
)
ptr
=
img
.
bits
()
ptr
=
img
.
bits
()
...
@@ -205,12 +240,9 @@ class MainWindow(QMainWindow):
...
@@ -205,12 +240,9 @@ class MainWindow(QMainWindow):
print
(
"
No path to export.
"
)
print
(
"
No path to export.
"
)
return
return
# We'll consider each anchor point as "USER-PLACED".
# But unlike a distance-threshold approach, we assign each anchor
# to exactly one closest path point.
anchor_points
=
self
.
image_view
.
anchor_points
anchor_points
=
self
.
image_view
.
anchor_points
# F
or each anchor, f
ind the index of the closest path point
# Find
s
the index of the closest path point
for each anchor point
user_placed_indices
=
set
()
user_placed_indices
=
set
()
for
ax
,
ay
in
anchor_points
:
for
ax
,
ay
in
anchor_points
:
min_dist
=
float
(
'
inf
'
)
min_dist
=
float
(
'
inf
'
)
...
@@ -245,7 +277,16 @@ class MainWindow(QMainWindow):
...
@@ -245,7 +277,16 @@ class MainWindow(QMainWindow):
print
(
f
"
Exported path with
{
len
(
full_xy
)
}
points to
{
file_path
}
"
)
print
(
f
"
Exported path with
{
len
(
full_xy
)
}
points to
{
file_path
}
"
)
def
clear_points
(
self
):
def
clear_points
(
self
):
"""
Clears points from the image.
"""
self
.
image_view
.
clear_guide_points
()
self
.
image_view
.
clear_guide_points
()
def
closeEvent
(
self
,
event
):
def
closeEvent
(
self
,
event
:
QCloseEvent
):
"""
Handle the window close event.
Args:
event: The close event.
"""
super
().
closeEvent
(
event
)
super
().
closeEvent
(
event
)
\ No newline at end of file
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment