Skip to content

Commit

Permalink
No four bit segmentation (#2828)
Browse files Browse the repository at this point in the history
* don't request segmentation as four bit and also don't send fourBit flag when sending buckets

* adapt and add new tests for four-bit-mode

* fix linting
  • Loading branch information
philippotto authored Jul 2, 2018
1 parent 50ad600 commit 0d72d3d
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 70 deletions.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,36 +1,65 @@
// @flow

import Base64 from "base64-js";

import BucketBuilder from "oxalis/model/bucket_data_handling/bucket_builder";
import Request from "libs/request";
import Store from "oxalis/store";
import { pushSaveQueueAction } from "oxalis/model/actions/save_actions";
import { updateBucket } from "oxalis/model/sagas/update_actions";
import Utils from "libs/utils";
import { doWithToken } from "admin/admin_rest_api";
import type { BucketInfo } from "oxalis/model/bucket_data_handling/bucket_builder";
import type { DataBucket } from "oxalis/model/bucket_data_handling/bucket";
import type { Vector4 } from "oxalis/constants";
import type { Vector3, Vector4 } from "oxalis/constants";
import type { DataLayerType } from "oxalis/store";
import { getResolutions } from "oxalis/model/accessors/dataset_accessor.js";
import { getResolutions, isSegmentationLayer } from "oxalis/model/accessors/dataset_accessor.js";
import { bucketPositionToGlobalAddress } from "oxalis/model/helpers/position_converter";
import constants from "oxalis/constants";

export const REQUEST_TIMEOUT = 30000;

function buildBuckets(layerInfo: DataLayerType, batch: Array<Vector4>): Array<BucketInfo> {
return batch.map((bucketAddress: Vector4) =>
BucketBuilder.fromZoomedAddress(bucketAddress, getResolutions(Store.getState().dataset)),
);
export type SendBucketInfo = {
position: Vector3,
zoomStep: number,
cubeSize: number,
};

type RequestBucketInfo = {
...SendBucketInfo,
fourBit: boolean,
};

// Converts a zoomed address ([x, y, z, zoomStep] array) into a bucket JSON
// object as expected by the server on bucket request
const createRequestBucketInfo = (
zoomedAddress: Vector4,
resolutions: Array<Vector3>,
fourBit: boolean,
): RequestBucketInfo => ({
...createSendBucketInfo(zoomedAddress, resolutions),
fourBit,
});

function createSendBucketInfo(zoomedAddress: Vector4, resolutions: Array<Vector3>): SendBucketInfo {
return {
position: bucketPositionToGlobalAddress(zoomedAddress, resolutions),
zoomStep: zoomedAddress[3],
cubeSize: constants.BUCKET_WIDTH,
};
}

export async function requestFromStore(
layerInfo: DataLayerType,
batch: Array<Vector4>,
): Promise<Uint8Array> {
const bucketInfo = buildBuckets(layerInfo, batch);
const fourBit =
Store.getState().datasetConfiguration.fourBit &&
!isSegmentationLayer(Store.getState().dataset, layerInfo.name);
const resolutions = getResolutions(Store.getState().dataset);
const bucketInfo = batch.map(zoomedAddress =>
createRequestBucketInfo(zoomedAddress, resolutions, fourBit),
);

return doWithToken(async token => {
const state = Store.getState();
const wasFourBit = state.datasetConfiguration.fourBit;
const datasetName = state.dataset.name;
const dataStoreUrl = state.dataset.dataStore.url;

Expand All @@ -43,7 +72,7 @@ export async function requestFromStore(
);

let result = new Uint8Array(responseBuffer);
if (wasFourBit) {
if (fourBit) {
result = decodeFourBit(result);
}
return result;
Expand Down Expand Up @@ -76,7 +105,7 @@ export async function sendToStore(batch: Array<DataBucket>): Promise<void> {
// eslint-disable-next-line no-await-in-loop
if (counter % YIELD_AFTER_X_BUCKETS === 0) await Utils.sleep(1);
const bucketData = bucket.getData();
const bucketInfo = BucketBuilder.fromZoomedAddress(
const bucketInfo = createSendBucketInfo(
bucket.zoomedAddress,
getResolutions(Store.getState().dataset),
);
Expand Down
6 changes: 3 additions & 3 deletions app/assets/javascripts/oxalis/model/sagas/update_actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import type {
TreeGroupType,
} from "oxalis/store";
import type { Vector3 } from "oxalis/constants";
import type { BucketInfo } from "oxalis/model/bucket_data_handling/bucket_builder";
import type { SendBucketInfo } from "oxalis/model/bucket_data_handling/wkstore_adapter";
import { convertFrontendBoundingBoxToServer } from "oxalis/model/reducers/reducer_helpers";

export type NodeWithTreeIdType = { treeId: number } & NodeType;
Expand Down Expand Up @@ -106,7 +106,7 @@ type UpdateVolumeTracingUpdateAction = {
};
type UpdateBucketUpdateAction = {
name: "updateBucket",
value: BucketInfo & {
value: SendBucketInfo & {
base64Data: string,
},
};
Expand Down Expand Up @@ -285,7 +285,7 @@ export function updateVolumeTracing(
},
};
}
export function updateBucket(bucketInfo: BucketInfo, base64Data: string) {
export function updateBucket(bucketInfo: SendBucketInfo, base64Data: string) {
return {
name: "updateBucket",
value: Object.assign({}, bucketInfo, {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ const RequestMock = {
receiveJSON: sinon.stub(),
};
const { dataSource } = datasetServerObject;
let _fourBit = false;

function setFourBit(bool) {
_fourBit = bool;
}

const StoreMock = {
getState: () => ({
dataset: {
Expand All @@ -25,7 +31,7 @@ const StoreMock = {
},
dataSource,
},
datasetConfiguration: { fourBit: false },
datasetConfiguration: { fourBit: _fourBit },
}),
dispatch: sinon.stub(),
};
Expand All @@ -38,26 +44,21 @@ const { requestFromStore, sendToStore } = mockRequire.reRequire(
"oxalis/model/bucket_data_handling/wkstore_adapter",
);

const layerInfo = {
name: "layername",
category: "color",
elementClass: "uint16",
resolutions: [[1, 1, 1], [2, 2, 2], [4, 4, 4], [8, 8, 8], [16, 16, 16], [32, 32, 32]],
};
const tokenResponse = { token: "token" };

test.beforeEach(t => {
RequestMock.receiveJSON = sinon.stub();
RequestMock.receiveJSON.returns(Promise.resolve(tokenResponse));

t.context.layer = layerInfo;
t.context.layer = dataSource.dataLayers[0];
t.context.segmentationLayer = dataSource.dataLayers[1];
});

test.serial("Initialization should set the attributes correctly", t => {
const { layer } = t.context;
t.is(layer.name, "layername");
t.is(layer.name, "color");
t.is(layer.category, "color");
t.is(getBitDepth(layer), 16);
t.is(getBitDepth(layer), 8);
});

function prepare() {
Expand Down Expand Up @@ -95,25 +96,29 @@ test.serial("requestFromStore: Token Handling should re-request a token when it'
t.is(RequestMock.sendJSONReceiveArraybuffer.callCount, 2);

const url = RequestMock.sendJSONReceiveArraybuffer.getCall(0).args[0];
t.is(url, "url/data/datasets/dataSet/layers/layername/data?token=token");
t.is(url, "url/data/datasets/dataSet/layers/color/data?token=token");

const url2 = RequestMock.sendJSONReceiveArraybuffer.getCall(1).args[0];
t.is(url2, "url/data/datasets/dataSet/layers/layername/data?token=token2");
t.is(url2, "url/data/datasets/dataSet/layers/color/data?token=token2");
});
});

test.serial("requestFromStore: Request Handling: should pass the correct request parameters", t => {
const { layer } = t.context;
const { batch } = prepare();

const expectedUrl = "url/data/datasets/dataSet/layers/layername/data?token=token2";
const expectedOptions = {
function createExpectedOptions(fourBit: boolean = false) {
return {
data: [
{ position: [0, 0, 0], zoomStep: 0, cubeSize: 32, fourBit: false },
{ position: [64, 64, 64], zoomStep: 1, cubeSize: 32, fourBit: false },
{ position: [0, 0, 0], zoomStep: 0, cubeSize: 32, fourBit },
{ position: [64, 64, 64], zoomStep: 1, cubeSize: 32, fourBit },
],
timeout: 30000,
};
}

test.serial("requestFromStore: Request Handling: should pass the correct request parameters", t => {
const { layer } = t.context;
const { batch } = prepare();

const expectedUrl = "url/data/datasets/dataSet/layers/color/data?token=token2";
const expectedOptions = createExpectedOptions();

return requestFromStore(layer, batch).then(() => {
t.is(RequestMock.sendJSONReceiveArraybuffer.callCount, 1);
Expand All @@ -124,6 +129,50 @@ test.serial("requestFromStore: Request Handling: should pass the correct request
});
});

test.serial(
"requestFromStore: Request Handling: four bit mode should be respected for color layers",
async t => {
setFourBit(true);
// test four bit color and 8 bit seg
const { layer } = t.context;
const { batch } = prepare();

const expectedUrl = "url/data/datasets/dataSet/layers/color/data?token=token2";
const expectedOptions = createExpectedOptions(true);

await requestFromStore(layer, batch).then(() => {
t.is(RequestMock.sendJSONReceiveArraybuffer.callCount, 1);

const [url, options] = RequestMock.sendJSONReceiveArraybuffer.getCall(0).args;
t.is(url, expectedUrl);
t.deepEqual(options, expectedOptions);
});

setFourBit(false);
},
);

test.serial(
"requestFromStore: Request Handling: four bit mode should not be respected for segmentation layers",
async t => {
setFourBit(true);
const { segmentationLayer } = t.context;

const { batch } = prepare();
const expectedUrl = "url/data/datasets/dataSet/layers/segmentation/data?token=token2";
const expectedOptions = createExpectedOptions(false);

await requestFromStore(segmentationLayer, batch).then(() => {
t.is(RequestMock.sendJSONReceiveArraybuffer.callCount, 1);

const [url, options] = RequestMock.sendJSONReceiveArraybuffer.getCall(0).args;
t.is(url, expectedUrl);
t.deepEqual(options, expectedOptions);
});
setFourBit(false);
},
);

test.serial("sendToStore: Request Handling should send the correct request parameters", t => {
const data = new Uint8Array(2);
const bucket1 = new DataBucket(8, [0, 0, 0, 0], null);
Expand All @@ -144,7 +193,6 @@ test.serial("sendToStore: Request Handling should send the correct request param
position: [0, 0, 0],
zoomStep: 0,
cubeSize: 32,
fourBit: false,
base64Data: Base64.fromByteArray(data),
},
},
Expand All @@ -154,7 +202,6 @@ test.serial("sendToStore: Request Handling should send the correct request param
position: [64, 64, 64],
zoomStep: 1,
cubeSize: 32,
fourBit: false,
base64Data: Base64.fromByteArray(data),
},
},
Expand Down

0 comments on commit 0d72d3d

Please sign in to comment.