Skip to content

Commit

Permalink
fix: #6
Browse files Browse the repository at this point in the history
# Problems
- When I retrieve DICOM instances that
contain ANN (label), I got the error because ANN did not have pixel
- Furthermore, thumbnail have same issues too
(may get no pixel instance in median)

# Solutions
- Exclude sop class UID that do not contain pixel in query
  • Loading branch information
Chinlinlee committed May 12, 2023
1 parent dd407c9 commit 9f1948a
Show file tree
Hide file tree
Showing 10 changed files with 162 additions and 80 deletions.
13 changes: 13 additions & 0 deletions api/controller.class.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,19 @@ class Controller {

this.postProcess();
}

/**
* @return {string}
*/
paramsToString() {
let strArr = [];
let keys = Object.keys(this.request.params);
for(let i = 0 ; i < keys.length; i++) {
let key = keys[i];
strArr.push(`${key}: ${this.request.params[key]}`);
}
return strArr.join(" ");
}
}

module.exports.Controller = Controller;
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const fs = require("fs");
const { Dcm2JpgExecutor } = require("../../../../../models/DICOM/dcm4che/wrapper/org/github/chinlinlee/dcm2jpg/Dcm2JpgExecutor");
const { Dcm2JpgExecutor$Dcm2JpgOptions } = require("../../../../../models/DICOM/dcm4che/wrapper/org/github/chinlinlee/dcm2jpg/Dcm2JpgExecutor$Dcm2JpgOptions");
const notImageSOPClass = require("../../../../../models/DICOM/dicomWEB/notImageSOPClass");
const { logger } = require("../../../../../utils/logs/log");
const dicomToJpegTask = require("../../../../../models/mongodb/models/dicomToJpegTask");
const colorette = require("colorette");
Expand Down Expand Up @@ -28,6 +29,10 @@ class DicomJpegGenerator {

async generateAllFrames() {
try {

if (notImageSOPClass.includes(this.dicomJsonModel.getSopClassUid())) {
return;
}

await this.insertStartTask_();

Expand Down
53 changes: 30 additions & 23 deletions api/dicom-web/controller/WADO-RS/rendered/instanceFrames.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const _ = require("lodash");
const renderedService = require("../service/rendered.service");
const dicomModel = require("../../../../../models/mongodb/models/dicom");
const { MultipartWriter } = require("../../../../../utils/multipartWriter");
const errorResponse = require("../../../../../utils/errorResponse/errorResponseMessage");
const { ApiLogger } = require("../../../../../utils/logs/api-logger");
Expand All @@ -11,8 +12,8 @@ class RetrieveRenderedInstanceFramesController extends Controller {
}

async mainProcess() {
let apiLogger = new ApiLogger(this.request, "WADO-RS");
apiLogger.addTokenValue();
this.apiLogger = new ApiLogger(this.request, "WADO-RS");
this.apiLogger.addTokenValue();

let {
studyUID,
Expand All @@ -21,7 +22,7 @@ class RetrieveRenderedInstanceFramesController extends Controller {
frameNumber
} = this.request.params;

apiLogger.logger.info(`Get study's series' rendered instances' frames, study UID: ${studyUID}, series UID: ${seriesUID}, instance UID: ${instanceUID}, frame: ${frameNumber}`);
this.apiLogger.logger.info(`Get study's series' rendered instances' frames, study UID: ${studyUID}, series UID: ${seriesUID}, instance UID: ${instanceUID}, frame: ${frameNumber}`);

let headerAccept = _.get(this.request.headers, "accept", "");
if (!headerAccept.includes("*/*") && !headerAccept.includes("image/jpeg")) {
Expand All @@ -33,25 +34,19 @@ class RetrieveRenderedInstanceFramesController extends Controller {
}

try {
let imagePathObj = await dicomModel.getPathOfInstance(this.request.params);

if(!imagePathObj) {
return this.responseNotFound();
}

let instanceFramesObj = await renderedService.getInstanceFrameObj(this.request.params);
if (!instanceFramesObj) {
this.response.writeHead(404, {
"Content-Type": "application/dicom+json"
});
let notFoundMessage = errorResponse.getNotFoundErrorMessage(`Not Found Instance, Instance UID: ${
instanceUID
}, Series UID: ${
seriesUID
}, Study UID: ${
studyUID
}`);

let notFoundMessageStr = JSON.stringify(notFoundMessage);

apiLogger.logger.warn(`[${notFoundMessageStr}]`);

return this.response.end(notFoundMessageStr);
if (_.isUndefined(instanceFramesObj)) {
return this.response.status(400).json(
errorResponse.getBadRequestErrorMessage(`instance: ${this.request.params.instanceUID} doesn't have pixel data`)
);
}

let dicomNumberOfFrames = _.get(instanceFramesObj, "00280008.Value.0", 1);
dicomNumberOfFrames = parseInt(dicomNumberOfFrames);

Expand All @@ -65,7 +60,7 @@ class RetrieveRenderedInstanceFramesController extends Controller {

let badRequestMessageStr = JSON.stringify(badRequestMessage);

apiLogger.logger.warn(badRequestMessageStr);
this.apiLogger.logger.warn(badRequestMessageStr);

return this.response.end(JSON.stringify(badRequestMessageStr));
}
Expand All @@ -78,7 +73,7 @@ class RetrieveRenderedInstanceFramesController extends Controller {
this.response.writeHead(200, {
"Content-Type": "image/jpeg"
});
apiLogger.logger.info(`Get instance's frame successfully, instance UID: ${instanceUID}, frame number: ${frameNumber[0]}`);
this.apiLogger.logger.info(`Get instance's frame successfully, instance UID: ${instanceUID}, frame number: ${frameNumber[0]}`);
return this.response.end(postProcessResult.magick.toBuffer(), "binary");
}
throw new Error(`Can not process this image, instanceUID: ${instanceFramesObj.instanceUID}, frameNumber: ${this.request.frameNumber[0]}`);
Expand All @@ -87,7 +82,7 @@ class RetrieveRenderedInstanceFramesController extends Controller {
await renderedService.writeSpecificFramesRenderedImages(this.request, frameNumber, instanceFramesObj, multipartWriter);
multipartWriter.writeFinalBoundary();

apiLogger.logger.info(`Get instance's frame successfully, instance UID: ${instanceUID}, frame numbers: ${frameNumber}`);
this.apiLogger.logger.info(`Get instance's frame successfully, instance UID: ${instanceUID}, frame numbers: ${frameNumber}`);

return this.response.end();
}
Expand All @@ -99,6 +94,18 @@ class RetrieveRenderedInstanceFramesController extends Controller {
this.response.end(JSON.stringify(e, Object.getOwnPropertyNames(e), 4), "utf8");
}
}

responseNotFound() {
let notFoundStr = `Not Found Instance, ${this.paramsToString()}`;

this.apiLogger.logger.warn(notFoundStr);

let notFoundMessage = errorResponse.getNotFoundErrorMessage(
notFoundStr
);

return this.response.status(404).json(notFoundMessage);
}
}
/**
*
Expand Down
5 changes: 5 additions & 0 deletions api/dicom-web/controller/WADO-RS/rendered/instances.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ class RetrieveRenderedInstancesController extends Controller {
if (imagePathObj) {
let multipartWriter = new MultipartWriter([], this.request, this.response);
let instanceFramesObj = await renderedService.getInstanceFrameObj(imagePathObj);
if (_.isUndefined(instanceFramesObj)) {
return this.response.status(400).json(
errorResponse.getBadRequestErrorMessage(`instance: ${this.request.params.instanceUID} doesn't have pixel data`)
);
}
let dicomNumberOfFrames = _.get(instanceFramesObj, "00280008.Value.0", 1);
dicomNumberOfFrames = parseInt(dicomNumberOfFrames);
await renderedService.writeRenderedImages(this.request, dicomNumberOfFrames, instanceFramesObj, multipartWriter);
Expand Down
1 change: 1 addition & 0 deletions api/dicom-web/controller/WADO-RS/rendered/series.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ class RetrieveRenderedSeriesController extends Controller {

for(let imagePathObj of instancesInSeries) {
let instanceFramesObj = await renderedService.getInstanceFrameObj(imagePathObj);
if (_.isUndefined(instanceFramesObj)) continue;
let dicomNumberOfFrames = _.get(instanceFramesObj, "00280008.Value.0", 1);
dicomNumberOfFrames = parseInt(dicomNumberOfFrames);
await renderedService.writeRenderedImages(this.request, dicomNumberOfFrames, instanceFramesObj, multipartWriter);
Expand Down
1 change: 1 addition & 0 deletions api/dicom-web/controller/WADO-RS/rendered/study.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class RetrieveRenderedStudyController extends Controller {

for(let imagePathObj of pathGroupOfInstancesInStudy) {
let instanceFramesObj = await renderedService.getInstanceFrameObj(imagePathObj);
if(_.isUndefined(instanceFramesObj)) continue;
let dicomNumberOfFrames = _.get(instanceFramesObj, "00280008.Value.0", 1);
dicomNumberOfFrames = parseInt(dicomNumberOfFrames);
await renderedService.writeRenderedImages(this.request, dicomNumberOfFrames, instanceFramesObj, multipartWriter);
Expand Down
6 changes: 5 additions & 1 deletion api/dicom-web/controller/WADO-RS/service/WADO-RS.service.js
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,11 @@ class InstanceImagePathFactory extends ImagePathFactory {

async getImagePaths() {
let imagePath = await dicomModel.getPathOfInstance(this.uids);
this.imagePaths = [imagePath];

if(imagePath)
this.imagePaths = [imagePath];
else
this.imagePaths = [];
}
}

Expand Down
7 changes: 7 additions & 0 deletions api/dicom-web/controller/WADO-RS/service/rendered.service.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ const fs = require("fs");
const sharp = require("sharp");
const { Dcm2JpgExecutor } = require("../../../../../models/DICOM/dcm4che/wrapper/org/github/chinlinlee/dcm2jpg/Dcm2JpgExecutor");
const { Dcm2JpgExecutor$Dcm2JpgOptions } = require("../../../../../models/DICOM/dcm4che/wrapper/org/github/chinlinlee/dcm2jpg/Dcm2JpgExecutor$Dcm2JpgOptions");
const notImageSOPClass = require("../../../../../models/DICOM/dicomWEB/notImageSOPClass");
const Magick = require("../../../../../models/magick");
const _ = require("lodash");

Expand Down Expand Up @@ -105,6 +106,7 @@ const { raccoonConfig } = require("../../../../../config-class");
async function getInstanceFrameObj(iParam, otherFields={}) {
let { studyUID, seriesUID, instanceUID } = iParam;
try {
/** @type { import("mongoose").FilterQuery<any> } */
let query = {
$and: [
{
Expand All @@ -115,6 +117,11 @@ async function getInstanceFrameObj(iParam, otherFields={}) {
},
{
instanceUID: instanceUID
},
{
"00080016.Value": {
$nin: notImageSOPClass
}
}
]
};
Expand Down
4 changes: 4 additions & 0 deletions models/DICOM/dicom-json-model.js
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,10 @@ class DicomJsonModel {
return _.get(this.dicomJson, "00020010.Value.0");
}

getSopClassUid() {
return _.get(this.dicomJson, "00080016.Value.0");
}

getStudyDate() {
return _.get(this.dicomJson, "00080020.Value.0");
}
Expand Down
147 changes: 91 additions & 56 deletions models/DICOM/dicomWEB/notImageSOPClass.js
Original file line number Diff line number Diff line change
@@ -1,77 +1,112 @@
/**
* ### 非影像類SOP Class
1.2.840.10008.5.1.4.1.1.104.1 Encapsulated PDF Storage
1.2.840.10008.5.1.4.1.1.11.1 Grayscale Softcopy Presentation State Storage SOP Class
1.2.840.10008.5.1.4.1.1.11.2 Color Softcopy Presentation State Storage SOP Class
1.2.840.10008.5.1.4.1.1.11.3 Pseudocolor Softcopy Presentation Stage Storage SOP Class
1.2.840.10008.5.1.4.1.1.11.4 Blending Softcopy Presentation State Storage SOP Class
1.2.840.10008.5.1.4.1.1.481.2 Radiation Therapy Dose Storage
1.2.840.10008.5.1.4.1.1.481.3 Radiation Therapy Structure Set Storage
1.2.840.10008.5.1.4.1.1.481.4 Radiation Therapy Beams Treatment Record Storage
1.2.840.10008.5.1.4.1.1.481.5 Radiation Therapy Plan Storage
1.2.840.10008.5.1.4.1.1.481.6 Radiation Therapy Brachy Treatment Record Storage
1.2.840.10008.5.1.4.1.1.481.7 Radiation Therapy Treatment Summary Record Storage
1.2.840.10008.5.1.4.1.1.481.8 Radiation Therapy Ion Plan Storage
1.2.840.10008.5.1.4.1.1.481.9 Radiation Therapy Ion Beams Treatment Record Storage
1.2.840.10008.5.1.4.1.1.66 Raw Data Storage
1.2.840.10008.5.1.4.1.1.66.1 Spatial Registration Storage
1.2.840.10008.5.1.4.1.1.66.2 Spatial Fiducials Storage
1.2.840.10008.5.1.4.1.1.66.3 Deformable Spatial Registration Storage
1.2.840.10008.5.1.4.1.1.66.4 Segmentation Storage
1.2.840.10008.5.1.4.1.1.67 Real World Value Mapping Storage
1.2.840.10008.5.1.4.1.1.88.11 Basic Text SR
1.2.840.10008.5.1.4.1.1.88.22 Enhanced SR
1.2.840.10008.5.1.4.1.1.88.33 Comprehensive SR
1.2.840.10008.5.1.4.1.1.88.40 Procedure Log Storage
1.2.840.10008.5.1.4.1.1.88.50 Mammography CAD SR
1.2.840.10008.5.1.4.1.1.88.59 Key Object Selection Document
1.2.840.10008.5.1.4.1.1.88.65 Chest CAD SR
1.2.840.10008.5.1.4.1.1.88.67 X-Ray Radiation Dose SR
1.2.840.10008.5.1.4.1.1.9.1.1 12-lead ECG Waveform Storage
1.2.840.10008.5.1.4.1.1.9.1.2 General ECG Waveform Storage
1.2.840.10008.5.1.4.1.1.9.1.3 Ambulatory ECG Waveform Storage
1.2.840.10008.5.1.4.1.1.9.2.1 Hemodynamic Waveform Storage
1.2.840.10008.5.1.4.1.1.9.3.1 Cardiac Electrophysiology Waveform Storage
1.2.840.10008.5.1.4.1.1.9.4.1 Basic Voice Audio Waveform Storage
* The list of sop class name that one's name not contains "image storage"
*/
module.exports = [
"1.2.840.10008.5.1.4.1.1.104.1",
module.exports=[
"1.2.840.10008.5.1.4.1.1.4.2",
"1.2.840.10008.5.1.4.1.1.6.2",
"1.2.840.10008.5.1.4.1.1.9.1.1",
"1.2.840.10008.5.1.4.1.1.9.1.2",
"1.2.840.10008.5.1.4.1.1.9.1.3",
"1.2.840.10008.5.1.4.1.1.9.2.1",
"1.2.840.10008.5.1.4.1.1.9.3.1",
"1.2.840.10008.5.1.4.1.1.9.4.1",
"1.2.840.10008.5.1.4.1.1.9.4.2",
"1.2.840.10008.5.1.4.1.1.9.5.1",
"1.2.840.10008.5.1.4.1.1.9.6.1",
"1.2.840.10008.5.1.4.1.1.9.6.2",
"1.2.840.10008.5.1.4.1.1.9.7.1",
"1.2.840.10008.5.1.4.1.1.9.7.2",
"1.2.840.10008.5.1.4.1.1.9.7.3",
"1.2.840.10008.5.1.4.1.1.9.7.4",
"1.2.840.10008.5.1.4.1.1.9.8.1",
"1.2.840.10008.5.1.4.1.1.11.1",
"1.2.840.10008.5.1.4.1.1.11.2",
"1.2.840.10008.5.1.4.1.1.11.3",
"1.2.840.10008.5.1.4.1.1.11.4",
"1.2.840.10008.5.1.4.1.1.481.2",
"1.2.840.10008.5.1.4.1.1.481.3",
"1.2.840.10008.5.1.4.1.1.481.4",
"1.2.840.10008.5.1.4.1.1.481.5",
"1.2.840.10008.5.1.4.1.1.481.6",
"1.2.840.10008.5.1.4.1.1.481.7",
"1.2.840.10008.5.1.4.1.1.481.8",
"1.2.840.10008.5.1.4.1.1.481.9",
"1.2.840.10008.5.1.4.1.1.11.5",
"1.2.840.10008.5.1.4.1.1.11.6",
"1.2.840.10008.5.1.4.1.1.11.7",
"1.2.840.10008.5.1.4.1.1.11.8",
"1.2.840.10008.5.1.4.1.1.11.9",
"1.2.840.10008.5.1.4.1.1.11.10",
"1.2.840.10008.5.1.4.1.1.11.11",
"1.2.840.10008.5.1.4.1.1.11.12",
"1.2.840.10008.5.1.4.1.1.30",
"1.2.840.10008.5.1.4.1.1.66",
"1.2.840.10008.5.1.4.1.1.66.1",
"1.2.840.10008.5.1.4.1.1.66.2",
"1.2.840.10008.5.1.4.1.1.66.3",
"1.2.840.10008.5.1.4.1.1.66.4",
"1.2.840.10008.5.1.4.1.1.66.5",
"1.2.840.10008.5.1.4.1.1.66.6",
"1.2.840.10008.5.1.4.1.1.67",
"1.2.840.10008.5.1.4.1.1.68.1",
"1.2.840.10008.5.1.4.1.1.68.2",
"1.2.840.10008.5.1.4.1.1.77.1.5.3",
"1.2.840.10008.5.1.4.1.1.77.1.5.8",
"1.2.840.10008.5.1.4.1.1.78.1",
"1.2.840.10008.5.1.4.1.1.78.2",
"1.2.840.10008.5.1.4.1.1.78.3",
"1.2.840.10008.5.1.4.1.1.78.4",
"1.2.840.10008.5.1.4.1.1.78.5",
"1.2.840.10008.5.1.4.1.1.78.6",
"1.2.840.10008.5.1.4.1.1.78.7",
"1.2.840.10008.5.1.4.1.1.78.8",
"1.2.840.10008.5.1.4.1.1.79.1",
"1.2.840.10008.5.1.4.1.1.80.1",
"1.2.840.10008.5.1.4.1.1.81.1",
"1.2.840.10008.5.1.4.1.1.82.1",
"1.2.840.10008.5.1.4.1.1.88.11",
"1.2.840.10008.5.1.4.1.1.88.22",
"1.2.840.10008.5.1.4.1.1.88.33",
"1.2.840.10008.5.1.4.1.1.88.34",
"1.2.840.10008.5.1.4.1.1.88.35",
"1.2.840.10008.5.1.4.1.1.88.40",
"1.2.840.10008.5.1.4.1.1.88.50",
"1.2.840.10008.5.1.4.1.1.88.59",
"1.2.840.10008.5.1.4.1.1.88.65",
"1.2.840.10008.5.1.4.1.1.88.67",
"1.2.840.10008.5.1.4.1.1.9.1.1",
"1.2.840.10008.5.1.4.1.1.9.1.2",
"1.2.840.10008.5.1.4.1.1.9.1.3",
"1.2.840.10008.5.1.4.1.1.9.2.1",
"1.2.840.10008.5.1.4.1.1.9.3.1",
"1.2.840.10008.5.1.4.1.1.9.4.1",
"1.2.840.10008.5.1.4.1.1.91.1"
"1.2.840.10008.5.1.4.1.1.88.68",
"1.2.840.10008.5.1.4.1.1.88.69",
"1.2.840.10008.5.1.4.1.1.88.70",
"1.2.840.10008.5.1.4.1.1.88.71",
"1.2.840.10008.5.1.4.1.1.88.72",
"1.2.840.10008.5.1.4.1.1.88.73",
"1.2.840.10008.5.1.4.1.1.88.74",
"1.2.840.10008.5.1.4.1.1.88.75",
"1.2.840.10008.5.1.4.1.1.88.76",
"1.2.840.10008.5.1.4.1.1.90.1",
"1.2.840.10008.5.1.4.1.1.91.1",
"1.2.840.10008.5.1.4.1.1.104.1",
"1.2.840.10008.5.1.4.1.1.104.2",
"1.2.840.10008.5.1.4.1.1.104.3",
"1.2.840.10008.5.1.4.1.1.104.4",
"1.2.840.10008.5.1.4.1.1.104.5",
"1.2.840.10008.5.1.4.1.1.131",
"1.2.840.10008.5.1.4.1.1.200.2",
"1.2.840.10008.5.1.4.1.1.200.8",
"1.2.840.10008.5.1.4.1.1.481.2",
"1.2.840.10008.5.1.4.1.1.481.3",
"1.2.840.10008.5.1.4.1.1.481.4",
"1.2.840.10008.5.1.4.1.1.481.5",
"1.2.840.10008.5.1.4.1.1.481.6",
"1.2.840.10008.5.1.4.1.1.481.7",
"1.2.840.10008.5.1.4.1.1.481.8",
"1.2.840.10008.5.1.4.1.1.481.9",
"1.2.840.10008.5.1.4.1.1.481.10",
"1.2.840.10008.5.1.4.1.1.481.11",
"1.2.840.10008.5.1.4.1.1.481.12",
"1.2.840.10008.5.1.4.1.1.481.13",
"1.2.840.10008.5.1.4.1.1.481.14",
"1.2.840.10008.5.1.4.1.1.481.15",
"1.2.840.10008.5.1.4.1.1.481.16",
"1.2.840.10008.5.1.4.1.1.481.17",
"1.2.840.10008.5.1.4.1.1.481.18",
"1.2.840.10008.5.1.4.1.1.481.19",
"1.2.840.10008.5.1.4.1.1.481.20",
"1.2.840.10008.5.1.4.1.1.481.21",
"1.2.840.10008.5.1.4.1.1.481.22",
"1.2.840.10008.5.1.4.1.1.481.25",
"1.2.840.10008.5.1.4.34.7",
"1.2.840.10008.5.1.4.34.10"
];

0 comments on commit 9f1948a

Please sign in to comment.