Show both unfiltered and filtered sinogram

This commit is contained in:
Peter Stockings
2025-05-18 11:49:37 +10:00
parent 9f12966b12
commit fe6c00c0fa
2 changed files with 99 additions and 23 deletions

View File

@@ -1,4 +1,4 @@
import { applyRampFilter } from "./fbp.js";
import { applyFilter } from "./fbp.js";
export async function generateSinogram(
imageUrl,
@@ -77,7 +77,7 @@ export async function reconstructImageFromSinogram(
size = 256,
onFrame = null,
renderMode = "heatmap",
useFBP = true
filterType = "ramp"
) {
const sinogramImage = await loadImage(sinogramUrl);
const canvas = Object.assign(document.createElement("canvas"), {
@@ -113,6 +113,8 @@ export async function reconstructImageFromSinogram(
const accum = new Float32Array(size * size);
const center = size / 2;
const allFilteredProjections = []; // To store filtered projections
for (let angle = 0; angle < angles; angle++) {
const theta = (angle * Math.PI) / angles;
@@ -125,9 +127,9 @@ export async function reconstructImageFromSinogram(
projection.push(sinogramData[i]);
}
if (useFBP) {
projection = applyRampFilter(projection);
}
// Apply the selected filter
projection = applyFilter(projection, filterType);
allFilteredProjections.push(projection); // Store the filtered projection
for (let y = 0; y < size; y++) {
for (let x = 0; x < size; x++) {
@@ -170,7 +172,49 @@ export async function reconstructImageFromSinogram(
}
}
return outputCanvas.toDataURL();
// Create filtered sinogram image
const filteredSinogramCanvas = Object.assign(
document.createElement("canvas"),
{
width: isVertical ? angles : width, // Same dimensions as original sinogram
height: isVertical ? width : angles,
}
);
const filteredSinCtx = filteredSinogramCanvas.getContext("2d");
const filteredImgData = filteredSinCtx.createImageData(
filteredSinogramCanvas.width,
filteredSinogramCanvas.height
);
let maxFilteredVal = 0;
for (const proj of allFilteredProjections) {
for (const val of proj) {
if (val > maxFilteredVal) maxFilteredVal = val;
}
}
// Avoid division by zero if maxFilteredVal is 0
if (maxFilteredVal === 0) maxFilteredVal = 1;
for (let angle = 0; angle < angles; angle++) {
const currentProjection = allFilteredProjections[angle];
for (let x = 0; x < width; x++) {
const val = (currentProjection[x] / maxFilteredVal) * 255; // Normalize and scale
const px = isVertical ? angle : x;
const py = isVertical ? x : angle;
const i = (py * filteredSinogramCanvas.width + px) * 4;
filteredImgData.data[i + 0] = val;
filteredImgData.data[i + 1] = val;
filteredImgData.data[i + 2] = val;
filteredImgData.data[i + 3] = 255;
}
}
filteredSinCtx.putImageData(filteredImgData, 0, 0);
const filteredSinogramUrl = filteredSinogramCanvas.toDataURL();
return {
reconstructedUrl: outputCanvas.toDataURL(),
filteredSinogramUrl: filteredSinogramUrl,
};
}
// Heatmap mapping: blue → green → yellow → red