Open mzur opened 6 years ago
Quick recap 2018-10-12:
glmvilib
has been initialized)glmvilib
can be found starting from this lineRecap 2018-10-24:
Rendering of a single frame of the angle distance image is done like this:
glmvilib.render
needs to be called with the IDs of the shader programs as arguments. The shader programs are executed in the given order of the arguments. This is done here in the old code. A vanilla JS call with an array of shader program IDs can look like this:
glmvilib.render.apply(null, ['angle-dist', 'other-id', 'third-id']);
You can find a working example for how to display a static canvas element in OpenLayers in this gist. It requires a simple custom source definition (ImageCanvas.js
) that extends the default ImageStatic
of OpenLayers. You can run the gist code as described in the OpenLayers introduction but it should be straight forward to integrate it in your Webpack setup, too.
An event listener for the mouse position can be defined like this:
const map = Map({/*...*/});
map.on('pointermove', function (event) {
let [x, y] = event.coordinate;
});
Note that the mouse position may be negative (if the mouse is outside the extent of the canvas). Also the OpenLayers y-coordinates start from the bottom up whereas WebGL y-coordinates start from the top down so you have to invert the coordinates like it is done here (after normalizing the x- and y-coordinates to the interval [0, 1]).
Any issues with glmvilib and constructor
which is a reserved keyword in ES6 may be resolved with a new release of glmvilib.
Recap 2018-11-07:
Smoothing for the zoom in OpenLayers can be disabled like this.
On chaining multiple shaders: Instead of rendering to the null
framebuffer, the AngleDist
shader renders to a texture. This texture is picked up by the ColorMap
shader to apply the color map.
Before the shader can render to a texture, the texture has to be created. This happens here through the setUpDistanceTexture
function. The function makes use of the glmvilib assets
object and the helpers
to create a new framebuffer and texture, and bind the two together. Whenever a shader uses the new framebuffer as target, it will render to the texture. The pointer to the framebuffer is stored in assets.framebuffers.distances
, which is used here to define the render target of the AngleDist
shader.
The color map is applied in the ColorMap
shader. Originally, this shader used the output of the ColorLens
shader as input source but right now this should be changed to use assets.textures.distanceTexture
of AngleDist
, instead.
The color map itself is loaded as Uint8Array
by the colorMap
service from the CSV file. In our case it can be hard-coded somewhere. The texture that holds the color map is created here. There is no need to dynamically update the color map with the updateColorMaps
function, it can be set directly in the setUp
function (replace null
with the Uint8Array).
Edit: The this
object should now be usable as intended in setUp
, callback
and postCallback
functions of shaders. Here is the latest release of glmvilib.
Edit: The
this
object should now be usable as intended insetUp
,callback
andpostCallback
functions of shaders. Here is the latest release of glmvilib.
Klappt, danke!
Die ColorMap auch schon (fast). ;)
Recap 2018-11-12:
Die RGB fire.csv
gibt es hier.
Infos zum "dynamic stretching" der Color Map (2. oben):
Für das Stretching werden die Werte der aktuell minimalen und maximalen Distanz benötigt. Diese müssen nach jedem Rendern mit AngleDist
aus dem WebGL Framebuffer ausgelesen werden. In der alten Version läuft das über die postCallback
Funktion nach jedem Rendern von RGBSelection
. In der neuen Version kann dies einfach nach AngleDist
passieren.
Die Werte werden mit glmvilib.getPixels
aus dem aktuell aktiven Framebuffer ausgelesen und in ein Uint8Array
geschrieben. Aus den ausgelesenen Distanzwerten wird dann ein Histogramm erstellt, in dem für jede mögliche Distanz (0 bis 255) die Zahl der mit dieser Distanz vorkommenden Pixel enthalten ist. Aus diesem Histogramm werden wiederum die Werte der aktuell minimalen und maximalen Distanz ermittelt. Der alte Code ist für mehrere gleichzeitige Marker/Farbkanäle ausgelegt. Wir brauchen aber nur einen.
Die aktuelle Color Map, das ermittelte Histogramm und die minimale/maximale Distanz werden für die Darstellung des "Color Map Indicator" im UI verwendet (colorScale
, colorScaleCanvas
, colorScaleHistogram
). Das colorScaleCanvas
ist mit WebGL implementiert. Für einen einzigen Marker kann man es aber ganz einfach wie das Histogramm mit dem Canvas 2D Context implementieren.
Die minimale/maximale Distanz wird außerdem in dem ColorLens
Shader verwendet. Dieser kümmert sich dann darum, dass die von AngleDist
ermittelten Distanzen auf [0, 1] gestreckt werden. Zum Verständnis, eine Streckung würde Formal so aussehen: f(x) = x - x_min / (x_max - x_min)
. Das ist hier etwas umständlich implementiert, um eine Division zu vermeiden, die angeblich langsamer in WebGL ist. Die Performance spielt aber an dieser Stelle gar keine so große Rolle. Trotzdem muss aber eine Division durch 0 vermieden werden.
Recap 2018-11-26:
Sonstige Features über die wir gesprochen haben:
Die Werte für den Spectrum Viewer werden mit dem SelectionInfo
Shader ermittelt. Dieser wird in dem Marker
ausgeführt, wenn immer ein Mausklick passiert. Damit erhält man einen Intensitätswert (0 - 255) für jeden Kanal des Spektrums, wobei 0 einer Intensität von 0 % und 255 einer Intensität von 100 % entspricht. Die Label der x-Achse (d.h. die Namen der Kanäle) werden aus den Dateinamen der Input-PNGs ermittelt.
Folgende Features sollte der Spectrum Viewer haben:
Folgendes sollte leicht zu implementieren sein (oder schon funktionieren):
Mir ist beim implementieren der ColorScale aufgefallen, dass eine Handvoll Pixel schwarz erscheinen, wenn man mit der Maus darüber fährt. Ist da vlt. noch ein Fehler in der ColorLens (Division durch 0 oder so)?
Ja, das habe ich auch schon bemerkt. Das ist allerdings in der alten Version auch schon so, also musst du dich da nicht drum kümmern (es sei denn du möchtest :wink:).
Wobei so ein schwarzes Pixel den interessanten Effekt hat, dass das schwarze div
unter der Color Map die Höhe 0 hat (und bei 0 auch auch ein Balken im Histrogramm sichtbar ist), die Color Map aber trotzdem gestaucht ist:
Dieser Fall sollte zwar nicht auftreten, aber vielleicht ist hier ausnahmsweise nicht 1 der höchste Wert. Funktioniert dann vielleicht das Verschieben der Color Map nach unten (mit dem weißen div
) noch nicht richtig?
Recap 2018-12-04:
Folgende Features haben wir besprochen:
The UI did not age very well with Angular 1. Some parts of the UI do not work correctly any more (the spectrum viewer) and the code is hard to maintain. We decided to do a rewrite of the UI in Vue. This can be done incrementally:
[x] Implement the image viewer. Maybe use OpenLayers instead of Leaflet? Features:
[x] The similarity image is displayed with a (fixed) color map and the angle distance. No bright field image, edge overlay or graticule.
[x] The user can choose a fixed reference point on the similarity image to update the display.
[x] The user can move the mouse in "freehand mode" over the similarity image to update the reference point in realtime.
[x] The user can zoom and pan the similarity image.
[x] Implement the color map indicator and dynamic stretching of the color map ("color lens"). Normally we have a color map of, say, 256 values. With the similarity display, the first value represents the lowest possible similarity (e.g. 0) and the last value represents the highest possible similarity (e.g. 1). But a given similarity display does not always include the lowest or highest possible similarities. If we only have similarities between 0.25 and 0.75, dynamic stretching of the color map would stretch the full color map to 0.25-0.75 instead of 0.0-1.0.
[x] The color map indicator should display the color map that is applied in the similarity display.
[x] The indicator should visualize any dynamic stretching of the color map that is done in the current similarity display.
[x] The indicator should display a histogram with the quantity of pixels of a given color of the map.
[x] Implement the spectrum viewer. Only the currently visible interval of the spectrum should be drawn so it works efficiently. Find a way to use (fake?) scroll bars that works better than the current approach.
[x] Users should be able to zoom and scroll both in x (m/z) and y (intensity) directions.
[x] The x axis should display m/z values as labels.
[x] The y axis shoud display intensity values (in percent) as labels.
[ ] On mousemove, the current m/z and intensity values of the mouse position should be shown.
[ ] Implement selectable spectrum ranges. A range is an interval of m/z values in the spectrum.
[ ] Users should be able to select one or more ranges in the spectrum viewer.
[ ] There should be a list of currently selected ranges where existing ranges can be deleted.
[ ] Ranges can be "active" (default) and "inactive". If there are active ranges, the similarity calculation should be limited to the combined m/z values of active ranges.
[ ] Users should be able to import and export the m/z intervals of ranges as CSV files.
[ ] Implement the "mean" display mode. This mode should display the mean image (with color map) of all active m/z ranges instead of the similarity display.
[ ] Implement the "direct" display mode. This mode should display the single m/z channel (with color map) that is selected on mousemove in the spectrum viewer.