Skip to content

Commit

Permalink
Working model
Browse files Browse the repository at this point in the history
  • Loading branch information
neurolabusc committed Jun 9, 2024
1 parent 2ff1c34 commit 77caa25
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 15 deletions.
16 changes: 14 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,20 @@
# NiiVue brainchop
### NiiVue brainchop

Provided a lesion map and an acute [Center of Cancellation](https://github.com/neurolabusc/Cancel) score, this web page will predict the chronic neglect severity. The provided lesion map should be normalized to standard space. This is an edge-based solution: the values are computed directly on the web browser, and are not shared with a cloud service. [Try the live demo](https://niivue.github.io/niivue-neglect/)

### To serve locally
### Usage

1. Open the [live demo](https://niivue.github.io/niivue-neglect/).
2. Press the `Open Lesion Map` button and select the normalized lesion. You can normalize lesions using [the clinical toolbox for SPM](https://github.com/neurolabusc/Clinical).
3. You can visually inspect the lesion (shown as red) with respect to the grayscale atlas and the core prediction voxels (shown in blue).
4. Set the [Center of Cancellation (CoC)](https://github.com/neurolabusc/Cancel) score that was measured acutely.
5. Press the `Prediction` button to see the expected outcome score.

![niivue-neglect user interface](niivue-neglect.png)

### For Developers

You can serve a hot-reloadable web page that allows you to interactively modify the source code.

```bash
git clone https://github.com/niivue/niivue-neglect
Expand Down
2 changes: 1 addition & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<header>
<button id="openBtn">Open Lesion Map</button>
<label for="cocNumber">Acute CoC Score</label>
<input style="width: 7em" type="number" id="cocNumber" min="-1" value ="0.91" max="1" />
<input style="width: 7em" type="number" id="cocNumber" min="-1" value ="0.65" max="1" />
<button id="predictBtn">Prediction</button>
<label for="maskSlider">Mask Opacity</label>
<input
Expand Down
63 changes: 51 additions & 12 deletions main.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ async function main() {
}
function norm0to1(val, mn, mx) {
// return clamped/normalized 0..1, linearly interpolated min..max
let range = mx - mn;
let ret = (val - mn)/range;
return Math.min(Math.max(ret,0),1);
let range = mx - mn
let ret = (val - mn)/range
return Math.min(Math.max(ret,0),1)
}
function neglect_predict() {
if (nv1.volumes.length !== 3) {
Expand Down Expand Up @@ -60,9 +60,46 @@ async function main() {
let acuteCoC = parseFloat(cocNumber.value)
acuteCoC = norm0to1(acuteCoC, -0.024243014, 0.951938077)
let ROI_volML = lesionVol / 1000
ROI_volML = norm0to1(ROI_volML, 0, 21.625);
const input_vector = [PC[0], PC[1], PC[2], PC[3], PC[4], acuteCoC, ROI_volML];
ROI_volML = norm0to1(ROI_volML, 0, 21.625)
const input_vector = [PC[0], PC[1], PC[2], PC[3], PC[4], acuteCoC, ROI_volML]
console.log(input_vector)
let prediction_sum = 0
for (let m = 0; m < models.length; m++) {
const model = models[m]
// Extract information from the current model
let support_vectors_i = model.SVs
let coefficients_i = model.sv_coef
let bias_i = model.bias_i
let gamma_i = model.gamma_i
// radial basis function kernel
function rbf_kernel(support_vectors_i, input_vector, gamma_i) {
// Number of support vectors
const num_support_vectors = model.dim0
// Initialize the kernel values array
let kernel_values_i = new Array(num_support_vectors)
// Calculate the kernel values using nested for loops
for (let j = 0; j < num_support_vectors; j++) {
let sum_squares = 0
for (let i = 0; i < input_vector.length; i++) {
//offset for reading 2D array as 1D vector
let offset = j + (i*model.dim0)
sum_squares += Math.pow(input_vector[i] - support_vectors_i[offset], 2)
}
kernel_values_i[j] = Math.exp(-gamma_i * sum_squares)
}
return kernel_values_i
}
let kernel_values_i = rbf_kernel(support_vectors_i, input_vector, gamma_i)
// Calculate the prediction using the regression function
let prediction = kernel_values_i.reduce((acc, kernel_value, index) => acc + coefficients_i[index] * kernel_value, 0)
prediction += bias_i
prediction_sum += prediction
// Feature weights and bias term (if needed for further use)
// let w = support_vectors_i.map((sv, index) => sv.map((value, j) => value * coefficients_i[index]))
// let b = bias_i
}
let prediction_mean = prediction_sum / models.length
return [acuteCoC , ROI_volML, prediction_mean]
}
openBtn.onclick = async function () {
let input = document.createElement('input')
Expand All @@ -77,7 +114,9 @@ async function main() {
input.click()
}
predictBtn.onclick = function () {
window.alert('Outcome prediction: 0.70289')
const [acuteCoC , ROI_volML, prediction] = neglect_predict()
const str = (`Given ${ROI_volML}ml lesion, and ${acuteCoC} acute CoC, predicted recovery is ${prediction}`)
window.alert(str)
}
aboutBtn.onclick = function () {
window.alert('Drag and drop NIfTI images. Use pulldown menu to choose brainchop model')
Expand All @@ -88,7 +127,8 @@ async function main() {
const defaults = {
backColor: [0.4, 0.4, 0.4, 1],
show3Dcrosshair: true,
onLocationChange: handleLocationChange
onLocationChange: handleLocationChange,
dragAndDropEnabled: false,
}
maskSlider.oninput = function () {
nv1.setOpacity(1, this.value /255)
Expand All @@ -102,14 +142,13 @@ async function main() {
const pca_mu = (await nv1.loadFromUrl('./pca_values_mu.nii.gz')).img
async function loadRBFmodel() {
const rbf = (await nv1.loadFromUrl('./models_5x10_diff.nii.gz')).img
let v = 0;
let v = 0
const nModels = rbf[v++]
const models = []
const fmodels = []
for (let i = 0; i < nModels; i++) {
let model = {}
model.dim0 = rbf[v++]
model.dim1 = rbf[v++]

model.bias_i = rbf[v++]
model.gamma_i = rbf[v++]
model.SVs = new Float64Array(model.dim0 * model.dim1)
Expand All @@ -118,8 +157,9 @@ async function main() {
model.sv_coef = new Float64Array(model.dim0)
for (let j = 0; j < model.dim0; j++)
model.sv_coef[j] = rbf[v++]
models.push(model)
fmodels.push(model)
}
return fmodels
}
const models = await loadRBFmodel()
nv1.opts.dragMode = nv1.dragModes.pan
Expand All @@ -134,7 +174,6 @@ async function main() {
])
maskSlider.oninput()
lesionSlider.oninput()
neglect_predict()
}

main()
Binary file added niivue-neglect.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 77caa25

Please sign in to comment.