Show both unfiltered and filtered sinogram
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user