Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
deformvis
insarviz
Commits
7c206817
Commit
7c206817
authored
May 03, 2021
by
blanch
Browse files
splitted test_opengl with a model
parent
03023f1b
Changes
1
Hide whitespace changes
Inline
Side-by-side
testing/test_opengl.py
View file @
7c206817
...
...
@@ -7,10 +7,11 @@ import os
import
time
import
rasterio
from
rasterio.enums
import
Resampling
import
numpy
as
np
import
scipy.ndimage
as
nd
if
True
:
if
True
and
False
:
import
OpenGL
OpenGL
.
ERROR_CHECKING
=
False
OpenGL
.
ERROR_LOGGING
=
False
...
...
@@ -20,18 +21,17 @@ from OpenGL.GL import *
from
PyQt5.QtCore
import
(
Qt
,
QCoreApplication
,
Q
R
ect
,
Q
Obj
ect
,
pyqtSignal
,
pyqtSlot
,
)
from
PyQt5.QtGui
import
(
QSurfaceFormat
,
QPainter
,
QBrush
,
QColor
,
QPen
,
QPainter
,
QColor
,
)
from
PyQt5.QtWidgets
import
(
QApplication
,
QMainWindow
,
QWidget
,
QPushButton
,
QOpenGLWidget
,
Q
H
BoxLayout
,
Q
V
BoxLayout
,
)
from
gl_utils
import
*
...
...
@@ -45,63 +45,160 @@ DATA_SET = 'GDM_DTs_geo_20190517_20190926_8rlks_crop_cmp.tiff'
#DATA_PATH = "/Users/Shared/datasets/insarviz"
#DATA_SET = "data_cube_tibet_flatsim/CNES_DTs_geo_20141103_20201002_8rlks.tiff"
dataset
=
rasterio
.
open
(
os
.
path
.
join
(
DATA_PATH
,
DATA_SET
))
print
(
"opened"
,
dataset
)
for
attr
in
dataset
.
profile
:
print
(
attr
,
dataset
.
profile
[
attr
])
def
load
(
i
=
0
):
# load image i
index
=
dataset
.
indexes
[
i
]
t0
=
time
.
time
()
band
=
dataset
.
read
(
index
)
t1
=
time
.
time
()
print
(
'loaded band'
,
i
,
'in'
,
t1
-
t0
,
's'
)
return
band
,
dataset
.
dtypes
[
i
]
# gl ########################################################################
def
load_texture
(
i
=
0
):
band
,
dtype
=
load
(
i
)
assert
dtype
==
'float32'
assert
band
.
nbytes
==
dataset
.
width
*
dataset
.
height
*
4
# data
if
'nodata'
in
dataset
.
profile
:
bg
=
(
band
==
dataset
.
profile
[
'nodata'
])
else
:
bg
=
np
.
zeros_like
(
band
)
v_i
,
v_a
=
np
.
percentile
(
band
[
~
bg
],
[
0
,
100
])
v
=
(
band
-
v_i
)
/
(
v_a
-
v_i
)
w
,
h
=
band
.
shape
z
=
np
.
ones
((
w
,
h
,
2
),
dtype
=
'float32'
)
z
[:,:,
0
]
=
v
z
[:,:,
1
][
bg
]
=
0.
# texture
glEnable
(
GL_TEXTURE_2D
)
texture_id
=
glGenTextures
(
1
)
glBindTexture
(
GL_TEXTURE_2D
,
texture_id
)
glTexParameter
(
GL_TEXTURE_2D
,
GL_TEXTURE_MAG_FILTER
,
GL_NEAREST
)
glTexParameter
(
GL_TEXTURE_2D
,
GL_TEXTURE_MIN_FILTER
,
GL_LINEAR_MIPMAP_LINEAR
)
glTexImage2D
(
GL_TEXTURE_2D
,
0
,
GL_LUMINANCE_ALPHA
,
dataset
.
width
,
dataset
.
height
,
0
,
GL_LUMINANCE_ALPHA
,
GL_FLOAT
,
z
)
glGenerateMipmap
(
GL_TEXTURE_2D
)
glBindTexture
(
GL_TEXTURE_2D
,
0
)
glDisable
(
GL_TEXTURE_2D
)
return
(
dataset
.
width
,
dataset
.
height
),
(
v_i
,
v_a
),
texture_id
class
Loader
(
QObject
):
def
open
(
self
,
filename
=
os
.
path
.
join
(
DATA_PATH
,
DATA_SET
)):
self
.
dataset
=
rasterio
.
open
(
filename
)
print
(
"opened"
,
self
.
dataset
)
profile
=
self
.
dataset
.
profile
for
attr
in
profile
:
print
(
attr
,
profile
[
attr
])
def
__len__
(
self
):
return
len
(
self
.
dataset
.
indexes
)
def
load_band
(
self
,
i
=
0
):
"""load image i"""
dataset
=
self
.
dataset
index
=
dataset
.
indexes
[
i
]
t0
=
time
.
time
()
band
=
dataset
.
read
(
index
,
out_shape
=
(
dataset
.
height
//
1
,
dataset
.
width
//
1
),
resampling
=
Resampling
.
nearest
,
)
t1
=
time
.
time
()
print
(
'loaded band'
,
i
,
'in'
,
t1
-
t0
,
's'
)
return
band
,
dataset
.
profile
.
get
(
'nodata'
,
None
),
dataset
.
dtypes
[
i
]
# Model #####################################################################
class
MapModel
(
QObject
):
texture_changed
=
pyqtSignal
()
tex_id
=
0
tex_width
=
512
tex_height
=
512
tex_vi
=
0.
tex_va
=
1.
bounds_changed
=
pyqtSignal
()
cx
=
tex_width
//
2
cy
=
tex_height
//
2
z
=
1.
def
__init__
(
self
,
loader
):
super
().
__init__
()
self
.
loader
=
loader
self
.
textures
=
{}
def
show_band
(
self
,
i
):
try
:
(
self
.
tex_id
,
self
.
tex_width
,
self
.
tex_height
,
self
.
tex_vi
,
self
.
tex_va
,
)
=
self
.
textures
[
i
]
except
KeyError
:
band
,
nd
,
dtype
=
self
.
loader
.
load_band
(
i
)
assert
dtype
==
'float32'
# data
if
nd
is
None
:
bg
=
np
.
zeros_like
(
band
)
else
:
bg
=
(
band
==
nd
)
v_i
,
v_01
,
v_99
,
v_a
=
np
.
percentile
(
band
[
~
bg
],
[
0
,
1
,
99
,
100
])
v
=
(
band
-
v_i
)
/
(
v_a
-
v_i
)
h
,
w
=
band
.
shape
z
=
np
.
ones
((
h
,
w
,
2
),
dtype
=
'float32'
)
z
[:,:,
0
]
=
v
z
[:,:,
1
][
bg
]
=
0.
# texture
glEnable
(
GL_TEXTURE_2D
)
texture_id
=
glGenTextures
(
1
)
glBindTexture
(
GL_TEXTURE_2D
,
texture_id
)
glTexParameter
(
GL_TEXTURE_2D
,
GL_TEXTURE_MAG_FILTER
,
GL_NEAREST
)
glTexParameter
(
GL_TEXTURE_2D
,
GL_TEXTURE_MIN_FILTER
,
GL_LINEAR_MIPMAP_LINEAR
)
glTexImage2D
(
GL_TEXTURE_2D
,
0
,
GL_LUMINANCE_ALPHA
,
w
,
h
,
0
,
GL_LUMINANCE_ALPHA
,
GL_FLOAT
,
z
)
glGenerateMipmap
(
GL_TEXTURE_2D
)
glBindTexture
(
GL_TEXTURE_2D
,
0
)
glDisable
(
GL_TEXTURE_2D
)
self
.
textures
[
i
]
=
(
self
.
tex_id
,
self
.
tex_width
,
self
.
tex_height
,
self
.
tex_vi
,
self
.
tex_va
,
)
=
(
texture_id
,
w
,
h
,
v_i
,
v_a
,
)
self
.
texture_changed
.
emit
()
if
len
(
self
.
textures
)
==
1
:
self
.
cx
=
self
.
tex_width
//
2
self
.
cy
=
self
.
tex_height
//
2
self
.
z
=
1.
self
.
bounds_changed
.
emit
()
def
resized
(
self
,
width
,
height
):
"""to be called when main map is resized"""
self
.
map_width
=
width
self
.
map_height
=
height
self
.
bounds_changed
.
emit
()
# pan/zoom
def
zoom
(
self
,
ds
,
x
=
None
,
y
=
None
):
dz
=
np
.
exp
(
ds
*
.
01
)
self
.
z
*=
dz
if
x
!=
None
:
w
,
h
=
self
.
map_width
,
self
.
map_height
self
.
cx
+=
(
x
-
w
//
2
)
/
self
.
z
*
(
dz
-
1.
)
self
.
cy
+=
(
y
-
h
//
2
)
/
self
.
z
*
(
dz
-
1.
)
self
.
bounds_changed
.
emit
()
def
pan
(
self
,
dx
,
dy
):
self
.
cx
-=
dx
/
self
.
z
self
.
cy
-=
dy
/
self
.
z
self
.
bounds_changed
.
emit
()
# tests
def
test_open
(
self
,
*
args
):
# open action for testing
self
.
loader
.
open
()
i
=
-
1
def
next_band
(
self
,
*
args
):
self
.
i
=
(
self
.
i
+
1
)
%
len
(
self
.
loader
)
self
.
show_band
(
self
.
i
)
def
prev_band
(
self
,
*
args
):
self
.
i
=
(
self
.
i
-
1
)
%
len
(
self
.
loader
)
self
.
show_band
(
self
.
i
)
# opengl view ###############################################################
COLOR_SHADER
=
r
"""
uniform sampler2D texture_2d;
...
...
@@ -148,14 +245,52 @@ COLOR_SHADER = r"""
}
"""
GRAY_SHADER
=
"""
uniform sampler2D texture_2d;
uniform float u_i;
uniform float u_a;
void main() {
// retreive original value, and color code
vec4 t = texture2D(texture_2d, gl_TexCoord[0].st);
float u = (t.x-u_i)/(u_a-u_i);
gl_FragColor = gl_Color * vec4(u, u, u, 1.);
}
"""
# opengl view ###############################################################
IDLE
,
DRAG
,
ZOOM
=
range
(
3
)
class
Map
(
QOpenGLWidget
):
def
__init__
(
self
,
model
):
super
().
__init__
()
self
.
model
=
model
self
.
model
.
bounds_changed
.
connect
(
self
.
update
)
self
.
model
.
texture_changed
.
connect
(
self
.
texture_changed
)
self
.
resized
.
connect
(
self
.
size_changed
)
@
pyqtSlot
()
def
texture_changed
(
self
):
self
.
makeCurrent
()
glUseProgram
(
self
.
program
)
set_uniform
(
self
.
program
,
'v_i'
,
self
.
model
.
tex_vi
)
set_uniform
(
self
.
program
,
'v_a'
,
self
.
model
.
tex_va
)
# text coords in texture pixels
tw
,
th
=
self
.
model
.
tex_width
,
self
.
model
.
tex_height
glMatrixMode
(
GL_TEXTURE
)
glLoadIdentity
()
glScale
(
1.
/
tw
,
1.
/
th
,
1.
)
self
.
doneCurrent
()
self
.
update
()
@
pyqtSlot
()
def
size_changed
(
self
):
self
.
model
.
resized
(
self
.
width
(),
self
.
height
())
# opengl
def
initializeGL
(
self
):
...
...
@@ -165,22 +300,9 @@ class Map(QOpenGLWidget):
)
tex_unit
=
0
glActiveTexture
(
GL_TEXTURE0
+
tex_unit
)
self
.
tex_size
,
(
v_i
,
v_a
),
self
.
tex_id
=
load_texture
()
set_uniform
(
self
.
program
,
'texture_2d'
,
tex_unit
)
set_uniform
(
self
.
program
,
'v_i'
,
v_i
)
set_uniform
(
self
.
program
,
'v_a'
,
v_a
)
# text coords in texture pixels
w
,
h
=
self
.
tex_size
glMatrixMode
(
GL_TEXTURE
)
glLoadIdentity
()
glScale
(
1.
/
w
,
1.
/
h
,
1.
)
self
.
cx
,
self
.
cy
=
w
//
2
,
h
//
2
# texture center
self
.
z
=
1.
# texture scale
glClearColor
(.
5
,
.
5
,
.
5
,
1.
)
glEnable
(
GL_TEXTURE_2D
)
def
resizeGL
(
self
,
width
,
height
):
glViewport
(
0
,
0
,
width
,
height
)
...
...
@@ -195,14 +317,18 @@ class Map(QOpenGLWidget):
def
paintGL
(
self
):
# band using OpenGL texturing
glClear
(
GL_COLOR_BUFFER_BIT
)
glBindTexture
(
GL_TEXTURE_2D
,
self
.
tex_id
)
glEnable
(
GL_TEXTURE_2D
)
glBindTexture
(
GL_TEXTURE_2D
,
self
.
model
.
tex_id
)
glUseProgram
(
self
.
program
)
cx
,
cy
=
self
.
model
.
cx
,
self
.
model
.
cy
z
=
self
.
model
.
z
w
,
h
=
self
.
width
(),
self
.
height
()
glMatrixMode
(
GL_TEXTURE
)
glPushMatrix
()
glTranslate
(
self
.
cx
,
self
.
cy
,
0.
)
glScale
(
1.
/
self
.
z
,
1.
/
self
.
z
,
1.
)
glTranslate
(
cx
,
cy
,
0.
)
glScale
(
1.
/
z
,
1.
/
z
,
1.
)
glTranslate
(
-
w
//
2
,
-
h
//
2
,
0.
)
glBegin
(
GL_TRIANGLE_STRIP
)
...
...
@@ -213,6 +339,7 @@ class Map(QOpenGLWidget):
glEnd
()
glPopMatrix
()
glUseProgram
(
0
)
glDisable
(
GL_TEXTURE_2D
)
# overlay using QPainter
painter
=
QPainter
(
self
)
...
...
@@ -221,11 +348,10 @@ class Map(QOpenGLWidget):
(
0
,
0
,
QColor
(
'white'
)),
]:
painter
.
setPen
(
color
)
painter
.
drawText
(
10
+
dx
,
20
+
dy
,
'z = %.02f'
%
(
self
.
z
,))
painter
.
drawText
(
10
+
dx
,
40
+
dy
,
'x = %.02f'
%
(
self
.
cx
,))
painter
.
drawText
(
10
+
dx
,
60
+
dy
,
'y = %.02f'
%
(
self
.
cy
,))
minimap_window
.
update
()
painter
.
drawText
(
10
+
dx
,
20
+
dy
,
'z = %.02f'
%
(
z
,))
painter
.
drawText
(
10
+
dx
,
40
+
dy
,
'x = %.02f'
%
(
cx
,))
painter
.
drawText
(
10
+
dx
,
60
+
dy
,
'y = %.02f'
%
(
cy
,))
painter
.
drawText
(
10
+
dx
,
80
+
dy
,
'i = %i'
%
(
self
.
model
.
i
,))
# interaction
...
...
@@ -248,11 +374,11 @@ class Map(QOpenGLWidget):
x1
,
y1
=
e
.
x
(),
self
.
height
()
-
e
.
y
()
dx
,
dy
=
x1
-
x0
,
y1
-
y0
if
self
.
interaction
==
DRAG
:
self
.
pan
(
dx
,
dy
)
self
.
model
.
pan
(
dx
,
dy
)
elif
self
.
interaction
==
ZOOM
:
self
.
zoom
(
dx
-
dy
,
*
self
.
p
)
self
.
model
.
zoom
(
dx
-
dy
,
*
self
.
p
)
self
.
p0
=
x1
,
y1
def
mouseReleaseEvent
(
self
,
e
):
if
self
.
interaction
==
DRAG
:
if
e
.
button
()
==
Qt
.
LeftButton
:
...
...
@@ -264,32 +390,9 @@ class Map(QOpenGLWidget):
def
wheelEvent
(
self
,
e
):
x
,
y
=
e
.
x
(),
self
.
height
()
-
e
.
y
()
ds
=
e
.
angleDelta
().
y
()
/
8
# degrees
self
.
zoom
(
ds
,
x
,
y
)
self
.
model
.
zoom
(
ds
,
x
,
y
)
# pan/zoom
def
zoom
(
self
,
ds
,
x
=
None
,
y
=
None
):
dz
=
np
.
exp
(
ds
*
.
01
)
self
.
z
*=
dz
if
x
!=
None
:
w
,
h
=
self
.
width
(),
self
.
height
()
self
.
cx
+=
(
x
-
w
//
2
)
/
self
.
z
*
(
dz
-
1.
)
self
.
cy
+=
(
y
-
h
//
2
)
/
self
.
z
*
(
dz
-
1.
)
self
.
update
()
def
pan
(
self
,
dx
,
dy
):
self
.
cx
-=
dx
/
self
.
z
self
.
cy
-=
dy
/
self
.
z
self
.
update
()
# band handling
def
next_band
(
*
args
):
print
(
args
)
# palette handling
rainbow
=
False
...
...
@@ -305,15 +408,41 @@ class Map(QOpenGLWidget):
class
MiniMap
(
QOpenGLWidget
):
def
__init__
(
self
,
model
):
super
().
__init__
()
self
.
model
=
model
self
.
model
.
bounds_changed
.
connect
(
self
.
update
)
self
.
model
.
texture_changed
.
connect
(
self
.
texture_changed
)
@
pyqtSlot
()
def
texture_changed
(
self
):
self
.
makeCurrent
()
self
.
resizeGL
(
self
.
width
(),
self
.
height
())
# TODO
# values should come from texture distribution, and be controlled interactively
glUseProgram
(
self
.
program
)
set_uniform
(
self
.
program
,
'u_i'
,
0.
)
set_uniform
(
self
.
program
,
'u_a'
,
1.
)
self
.
doneCurrent
()
self
.
update
()
# opengl
def
initializeGL
(
self
):
self
.
program
=
create_program
(
create_shader
(
GL_FRAGMENT_SHADER
,
GRAY_SHADER
),
)
tex_unit
=
0
glActiveTexture
(
GL_TEXTURE0
+
tex_unit
)
set_uniform
(
self
.
program
,
'texture_2d'
,
tex_unit
)
glClearColor
(.
5
,
.
5
,
.
5
,
1.
)
def
resizeGL
(
self
,
width
,
height
):
glViewport
(
0
,
0
,
width
,
height
)
wr
=
width
/
height
tw
,
th
=
map_window
.
tex_size
tw
,
th
=
self
.
model
.
tex_width
,
self
.
model
.
tex_height
tr
=
tw
/
th
if
tr
>
wr
:
...
...
@@ -336,8 +465,10 @@ class MiniMap(QOpenGLWidget):
def
paintGL
(
self
):
# band using OpenGL texturing
glClear
(
GL_COLOR_BUFFER_BIT
)
glUseProgram
(
self
.
program
)
glEnable
(
GL_TEXTURE_2D
)
glBindTexture
(
GL_TEXTURE_2D
,
map_window
.
tex_id
)
glBindTexture
(
GL_TEXTURE_2D
,
self
.
model
.
tex_id
)
glBegin
(
GL_TRIANGLE_STRIP
)
for
x
in
[
0
,
1
]:
...
...
@@ -346,10 +477,11 @@ class MiniMap(QOpenGLWidget):
glVertex
(
x
,
y
)
glEnd
()
glDisable
(
GL_TEXTURE_2D
)
glUseProgram
(
0
)
x
,
y
,
z
=
map_window
.
cx
,
map_window
.
cy
,
map_window
.
z
tw
,
th
=
map_window
.
tex_size
ww
,
wh
=
map_window
.
width
(),
map_window
.
height
()
x
,
y
,
z
=
self
.
model
.
cx
,
self
.
model
.
cy
,
self
.
model
.
z
tw
,
th
=
self
.
model
.
tex_width
,
self
.
model
.
tex_height
ww
,
wh
=
self
.
model
.
map_width
,
self
.
model
.
map_
height
x1
,
x2
=
x
-
ww
/
2.
/
z
,
x
+
ww
/
2.
/
z
y1
,
y2
=
y
-
wh
/
2.
/
z
,
y
+
wh
/
2.
/
z
...
...
@@ -362,6 +494,8 @@ class MiniMap(QOpenGLWidget):
glVertex
(
x2
,
y1
)
glEnd
()
glPopMatrix
()
glBindTexture
(
GL_TEXTURE_2D
,
0
)
# interaction
...
...
@@ -384,23 +518,23 @@ class MiniMap(QOpenGLWidget):
dx
,
dy
=
x1
-
x0
,
y1
-
y0
ww
,
wh
=
self
.
width
(),
self
.
height
()
tw
,
th
=
map_window
.
tex_size
wr
=
ww
/
wh
tr
=
tw
/
th
if
tr
>
wr
:
dy
*=
tr
/
wr
else
:
dx
*=
wr
/
tr
z
=
map_window
.
z
if
self
.
interaction
==
DRAG
:
ww
,
wh
=
self
.
width
(),
self
.
height
()
tw
,
th
=
self
.
model
.
tex_width
,
self
.
model
.
tex_height
wr
=
ww
/
wh
tr
=
tw
/
th
if
tr
>
wr
:
dy
*=
tr
/
wr
else
:
dx
*=
wr
/
tr
z
=
self
.
model
.
z
dx
*=
tw
/
ww
*
z
dy
*=
th
/
wh
*
z
dx
*=
tw
/
ww
*
z
dy
*=
th
/
wh
*
z
if
self
.
interaction
==
DRAG
:
map_window
.
pan
(
-
dx
,
-
dy
)
self
.
model
.
pan
(
-
dx
,
-
dy
)
elif
self
.
interaction
==
ZOOM
:
map_window
.
zoom
(
dx
-
dy
)
self
.
model
.
zoom
(
dx
-
dy
)
self
.
p0
=
x1
,
y1
def
mouseReleaseEvent
(
self
,
e
):
...
...
@@ -412,8 +546,9 @@ class MiniMap(QOpenGLWidget):
self
.
interaction
=
IDLE
def
wheelEvent
(
self
,
e
):
# TODO: should be centered on cursor
ds
=
e
.
angleDelta
().
y
()
/
8
# degrees
map_window
.
zoom
(
ds
)
self
.
model
.
zoom
(
ds
)
...
...
@@ -423,14 +558,22 @@ class MainWindow(QMainWindow):
def
__init__
(
self
):
super
().
__init__
()
layout
=
QHBoxLayout
()
layout
=
QVBoxLayout
()
load_button
=
QPushButton
(
'open'
,
clicked
=
map_model
.
test_open
)
layout
.
addWidget
(
load_button
)
band_button
=
QPushButton
(
'>'
,
clicked
=
map_model
.
next_band
)
layout
.
addWidget
(
band_button
)
next
_button
=
QPushButton
(
'
>'
)
next_button
.
clicked
.
connect
(
map_window
.
next
_band
)
layout
.
addWidget
(
next
_button
)
band
_button
=
QPushButton
(
'
<'
,
clicked
=
map_model
.
prev
_band
)
layout
.
addWidget
(
band
_button
)
rainbow_button
=
QPushButton
(
'palette'
)
rainbow_button
.
clicked
.
connect
(
map_window
.
next_palette
)
rainbow_button
=
QPushButton
(
'palette'
,
clicked
=
map_window
.
next_palette
)
layout
.
addWidget
(
rainbow_button
)
widget
=
QWidget
()
...
...
@@ -438,21 +581,24 @@ class MainWindow(QMainWindow):
self
.
setCentralWidget
(
widget
)
QCoreApplication
.
setAttribute
(
Qt
.
AA_ShareOpenGLContexts
)
app
=
QApplication
(
sys
.
argv
)
map_window
=
Map
()
loader
=
Loader
()
map_model
=
MapModel
(
loader
)
map_window
=
Map
(
map_model
)
map_window
.
setWindowTitle
(
'Map'
)
map_window
.
setMouseTracking
(
True
)
minimap_window
=
MiniMap
()
minimap_window
=
MiniMap
(
map_model
)
minimap_window
.
setWindowTitle
(
'MiniMap'
)
main_window
=
MainWindow
()
main_window
.
show
()
map_window
.
show
()
minimap_window
.
show
()
main_window
.
show
()
app
.
exec_
()
Write
Preview
Supports
Markdown
0%
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!
Cancel
Please
register
or
sign in
to comment