Skip to content

Commit

Permalink
Merge pull request catmaid#1958 from aschampion/features/n5-import-wi…
Browse files Browse the repository at this point in the history
…zard

N5 polish
  • Loading branch information
aschampion authored Jan 7, 2020
2 parents eeac898 + 4ee358f commit 466d1f2
Show file tree
Hide file tree
Showing 15 changed files with 1,734 additions and 1,360 deletions.
3 changes: 3 additions & 0 deletions django/applications/catmaid/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
from catmaid.views.dvid import DVIDImportWizard
from catmaid.views.userimporter import UserImportWizard
from catmaid.views.dataexporter import CatmaidDataExportWizard
from catmaid.views.image_block_source_importer import ImageBlockSourceImportWizard

def add_related_field_wrapper(form, col_name, rel=None) -> None:
"""Wrap a field on a form so that a little plus sign appears right next to
Expand Down Expand Up @@ -547,3 +548,5 @@ def color(self):
view=UserImportWizard.as_view())
admin.site.register_view('catmaiddataexporter', 'CATMAID data export',
view=CatmaidDataExportWizard.as_view())
admin.site.register_view('imageblocksourceimporter', 'Import N5 source stacks',
view=ImageBlockSourceImportWizard.as_view())
4 changes: 2 additions & 2 deletions django/applications/catmaid/fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -382,8 +382,8 @@ def __init__(self, *args, **kwargs):
delimiter='|',
max_length=kwargs['max_length']),
)
del kwargs['max_length']
del kwargs['base_field']
kwargs.pop('max_length', None)
kwargs.pop('base_field', None)
super().__init__(fields, *args, **kwargs)
# Because SimpleArrayField does not strictly adhere to Django conventions,
# our widget must have access to its field so that `prepare_value` can
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@

this.blockSizeZ = 1;

// TODO need to set tile width based on block size, but that's async
this.tileSource.promiseReady.then(() => {
let blockSize = this.tileSource.blockSize(0);
blockSize = CATMAID.tools.permute(blockSize, this.dimPerm);
Expand All @@ -37,6 +36,13 @@
// If tiles have been initialized, reinitialize.
this.resize(this.stackViewer.viewWidth, this.stackViewer.viewHeight);
}
let numStackLevels = this.stack.downsample_factors.length;
let numSourceLevels = this.tileSource.numScaleLevels();
if (numStackLevels > numSourceLevels) {
// If the source has more levels than the stack, it's not worth
// warning the user since it won't break any interactions.
CATMAID.info(`Stack mirror has ${numSourceLevels} scale levels but stack specifies ${numStackLevels}`);
}
});
}

Expand Down Expand Up @@ -189,14 +195,11 @@
Promise.all(toLoad.map(([[i, j], coord]) => this
._readBlock(...coord.slice(0, 4))
.then(block => {
if (!this._tilesBuffer[i][j] ||
if (!this._tilesBuffer || !this._tilesBuffer[i] || !this._tilesBuffer[i][j] ||
!CATMAID.tools.arraysEqual(this._tilesBuffer[i][j].coord, coord)) return;

let slice = this._sliceBlock(block, blockZ);

// The array is still column major, so transpose to row-major for tex.
slice = slice.transpose(1, 0);

this._sliceToTexture(slice, this._tilesBuffer[i][j].texture);
this._tilesBuffer[i][j].coord = coord;
this._tilesBuffer[i][j].loaded = true;
Expand Down Expand Up @@ -238,7 +241,6 @@
if (slice.shape[0] < this.tileWidth ||
slice.shape[1] < this.tileHeight) {
let empty = this._makeEmptySlice();
var sub = empty.hi(slice.shape[0], slice.shape[1]);

for(let i=0; i<slice.shape[0]; ++i) {
for(let j=0; j<slice.shape[1]; ++j) {
Expand Down Expand Up @@ -300,11 +302,20 @@
let baseTex = pixiTex.baseTexture;
let texture = baseTex._glTextures[renderer.CONTEXT_UID];
let newTex = false;

// Since we assume array coordinates are [x][y], we want f-order since
// OpenGL wants x most rapidly changing.
let transpose = slice.selection.stride[0] > slice.selection.stride[1];
if (!transpose) {
slice = slice.transpose(1, 0);
}
let width = slice.shape[1];
let height = slice.shape[0];

if (!texture || texture.width !== width || texture.height !== height ||
texture.format !== format || texture.type !== type) {
// Make sure Pixi does not have the old texture bound.
renderer.unbindTexture(baseTex);
if (texture) gl.deleteTexture(texture.texture);
texture = new PIXI.glCore.GLTexture(gl, width, height, format, type);
baseTex._glTextures[renderer.CONTEXT_UID] = texture;
Expand All @@ -314,10 +325,20 @@
pixiTex._updateUvs();
}

texture.bind();
// Pixi assumes it knows which textures are bound to which units as an
// optimization. To not corrupt these assumptions, bind through Pixi
// and use its unit rather than directly with the texture.
let texUnit = renderer.bindTexture(baseTex);
gl.activeTexture(gl.TEXTURE0 + texUnit);
gl.pixelStorei(gl.UNPACK_ALIGNMENT, 1);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);

let typedArr = _flattenNdarraySliceToView(slice);
let arrayBuff = new jsArrayType(typedArr,
typedArr.byteOffset, typedArr.byteLength/jsArrayType.BYTES_PER_ELEMENT);
pixiTex._transpose = transpose;

if (newTex) {
gl.texImage2D(
gl.TEXTURE_2D,
Expand All @@ -328,7 +349,7 @@
0, // Border
texture.format,
texture.type,
new jsArrayType(slice.flatten().selection.data.buffer));
arrayBuff);
} else {
gl.texSubImage2D(
gl.TEXTURE_2D,
Expand All @@ -338,7 +359,7 @@
texture.height,
texture.format,
texture.type,
new jsArrayType(slice.flatten().selection.data.buffer));
arrayBuff);
}
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, glScaleMode);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, glScaleMode);
Expand All @@ -357,7 +378,7 @@
if (buff.coord) {
var tile = this._tiles[i][j];

if (/*force ||*/ buff.loaded) {
if (buff.loaded) {
let swap = tile.texture;
tile.texture = buff.texture;
tile.coord = buff.coord;
Expand All @@ -367,6 +388,15 @@
if (tile.texture.baseTexture.scaleMode !== this._pixiInterpolationMode) {
this._setTextureInterpolationMode(tile.texture, this._pixiInterpolationMode);
}
if (tile.texture._transpose && !tile._transpose) {
tile.scale.x = -1.0;
tile.rotation = -Math.PI / 2.0;
tile._transpose = true;
} else if (!tile.texture._transpose && tile._transpose) {
tile.scale.x = 1.0;
tile.rotation = 0.0;
tile._transpose = false;
}
tile.visible = true;
} else if (force) {
tile.visible = false;
Expand Down Expand Up @@ -397,4 +427,48 @@

CATMAID.PixiImageBlockLayer = PixiImageBlockLayer;

/** Convert a 2-d c-order ndarray into a flattened TypedArray. */
function _flattenNdarraySliceToView(slice) {
let sourceArray = slice.selection.data;
if (slice.selection.stride[1] === 1) {
if (slice.selection.stride[0] === slice.shape[1]) {
// In this case the data is already contiguous in memory in the correct order.
let sourceOffset = slice.selection.offset;
return sourceArray.subarray(sourceOffset, sourceOffset + slice.shape[0] * slice.shape[1]);
}

// In this case the rows are contiguous in memory, but the colums are
// strided non-contiguously.
let typedArr = new sourceArray.constructor(slice.shape[0] * slice.shape[1]);
let targetOffset = 0;
let sourceOffset = slice.selection.offset;
for (let i = 0; i < slice.shape[0]; ++i) {
typedArr.set(sourceArray.subarray(sourceOffset, sourceOffset + slice.shape[1]), targetOffset);
targetOffset += slice.shape[1];
sourceOffset += slice.selection.stride[0];
}

return typedArr;
} else {

// In this case no elements are contiguous so much be copied individually.
return slice.flatten().selection.data;
// Manual implementation that is somehow slower than ndarray's nested
// Array push and joining:
// let typedArr = new sourceArray.constructor(slice.shape[0] * slice.shape[1]);
// let targetOffset = 0;
// let sourceIOffset = slice.selection.offset;
// for (let i = 0; i < slice.shape[0]; ++i) {
// let sourceJOffset = sourceIOffset;
// for (let j = 0; j < slice.shape[1]; ++j) {
// typedArr[targetOffset++] = sourceArray[sourceJOffset];
// sourceJOffset += slice.selection.stride[1];
// }
// sourceIOffset += slice.selection.stride[0];
// }

// return typedArr;
}
}

})(CATMAID);
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@
var emptyTex = graphic.generateCanvasTexture();

this._tiles = [];
this._tilesBuffer = [];
this._tileFirstR = 0;
this._tileFirstC = 0;

Expand Down
2 changes: 0 additions & 2 deletions django/applications/catmaid/static/js/layers/tile-layer.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@
* @type {Number}
*/
this._tileFirstC = 0;
this._tilesBuffer = [];
this._buffering = false;
this._swapBuffersTimeout = null;

Expand Down Expand Up @@ -113,7 +112,6 @@
};

this._tiles = [];

this._tilesBuffer = [];

this._tileOrigR = 0;
Expand Down
2 changes: 1 addition & 1 deletion django/applications/catmaid/static/js/stack.js
Original file line number Diff line number Diff line change
Expand Up @@ -564,7 +564,7 @@
}
var selectedMirror = mirror;

return CATMAID.TileSources.get(
return CATMAID.TileSources.getCached(
selectedMirror.id,
selectedMirror.tile_source_type,
selectedMirror.image_base,
Expand Down
Loading

0 comments on commit 466d1f2

Please sign in to comment.