Mercurial > hg > orthanc
view OrthancFramework/Sources/DicomParsing/DicomPixelMasker.cpp @ 6033:6ad530603d23 pixel-anon
wip: pixel-anon: now modifying pixels into specific instances only
author | Alain Mazy <am@orthanc.team> |
---|---|
date | Fri, 07 Mar 2025 17:25:34 +0100 |
parents | c76b1b2ee57e |
children | 4742b4fe824b |
line wrap: on
line source
/** * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium * Copyright (C) 2017-2023 Osimis S.A., Belgium * Copyright (C) 2024-2025 Orthanc Team SRL, Belgium * Copyright (C) 2021-2025 Sebastien Jodogne, ICTEAM UCLouvain, Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation, either version 3 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program. If not, see * <http://www.gnu.org/licenses/>. **/ #include "../PrecompiledHeaders.h" #include "DicomPixelMasker.h" #include "../OrthancException.h" #include "../SerializationToolbox.h" #include "../Logging.h" namespace Orthanc { static const char* KEY_MASK_PIXELS = "MaskPixelData"; static const char* KEY_MASK_TYPE = "MaskType"; static const char* KEY_MASK_TYPE_FILL = "Fill"; static const char* KEY_MASK_TYPE_MEAN_FILTER = "MeanFilter"; static const char* KEY_FILTER_WIDTH = "FilterWidth"; static const char* KEY_FILL_VALUE = "FillValue"; static const char* KEY_REGIONS = "Regions"; static const char* KEY_REGION_TYPE = "RegionType"; static const char* KEY_REGION_PIXELS = "Pixels"; static const char* KEY_REGION_BOUNDING_BOX = "BoundingBox"; static const char* KEY_ORIGIN = "Origin"; static const char* KEY_END = "End"; static const char* KEY_TARGET_SERIES = "TargetSeries"; static const char* KEY_TARGET_INSTANCES = "TargetInstances"; DicomPixelMasker::DicomPixelMasker() { } void DicomPixelMasker::Apply(ParsedDicomFile& toModify) { DicomInstanceHasher hasher = toModify.GetHasher(); const std::string& seriesId = hasher.HashSeries(); const std::string& instanceId = hasher.HashInstance(); for (std::list<Region>::const_iterator r = regions_.begin(); r != regions_.end(); ++r) { // LOG(INFO) << " +++ " << seriesId << " " << instanceId; if (r->targetSeries_.size() > 0 && r->targetSeries_.find(seriesId) == r->targetSeries_.end()) { continue; } if (r->targetInstances_.size() > 0 && r->targetInstances_.find(instanceId) == r->targetInstances_.end()) { continue; } ImageAccessor imageRegion; toModify.GetRawFrame(0)->GetRegion(imageRegion, r->x_, r->y_, r->width_, r->height_); // TODO-PIXEL-ANON: handle frames if (r->mode_ == DicomPixelMaskerMode_MeanFilter) { ImageProcessing::MeanFilter(imageRegion, r->filterWidth_, r->filterWidth_); } else if (r->mode_ == DicomPixelMaskerMode_Fill) { ImageProcessing::Set(imageRegion, r->fillValue_); } } } void DicomPixelMasker::ParseRequest(const Json::Value& request) { if (request.isMember(KEY_MASK_PIXELS) && request[KEY_MASK_PIXELS].isObject()) { const Json::Value& maskPixelsJson = request[KEY_MASK_PIXELS]; if (maskPixelsJson.isMember(KEY_REGIONS) && maskPixelsJson[KEY_REGIONS].isArray()) { const Json::Value& regionsJson = maskPixelsJson[KEY_REGIONS]; for (Json::ArrayIndex i = 0; i < regionsJson.size(); ++i) { const Json::Value& regionJson = regionsJson[i]; Region region; if (regionJson.isMember(KEY_MASK_TYPE) && regionJson[KEY_MASK_TYPE].isString()) { if (regionJson[KEY_MASK_TYPE].asString() == KEY_MASK_TYPE_FILL) { region.mode_ = DicomPixelMaskerMode_Fill; if (regionJson.isMember(KEY_FILL_VALUE) && regionJson[KEY_FILL_VALUE].isInt()) { region.fillValue_ = regionJson[KEY_FILL_VALUE].asInt(); } } else if (regionJson[KEY_MASK_TYPE].asString() == KEY_MASK_TYPE_MEAN_FILTER) { region.mode_ = DicomPixelMaskerMode_MeanFilter; if (regionJson.isMember(KEY_FILTER_WIDTH) && regionJson[KEY_FILTER_WIDTH].isUInt()) { region.filterWidth_ = regionJson[KEY_FILTER_WIDTH].asUInt(); } } else { throw OrthancException(ErrorCode_BadFileFormat, std::string(KEY_MASK_TYPE) + " should be '" + KEY_MASK_TYPE_FILL +"' or '" + KEY_MASK_TYPE_MEAN_FILTER + "'."); } } if (regionJson.isMember(KEY_TARGET_SERIES) && regionJson[KEY_TARGET_SERIES].isArray()) { SerializationToolbox::ReadSetOfStrings(region.targetSeries_, regionJson, KEY_TARGET_SERIES); } if (regionJson.isMember(KEY_TARGET_INSTANCES) && regionJson[KEY_TARGET_INSTANCES].isArray()) { SerializationToolbox::ReadSetOfStrings(region.targetInstances_, regionJson, KEY_TARGET_INSTANCES); } if (regionJson.isMember(KEY_REGION_TYPE) && regionJson[KEY_REGION_TYPE].asString() == KEY_REGION_PIXELS) { if (regionJson.isMember(KEY_ORIGIN) && regionJson[KEY_ORIGIN].isArray() && regionJson[KEY_ORIGIN].size() == 2 && regionJson.isMember(KEY_END) && regionJson[KEY_END].isArray() && regionJson[KEY_END].size() == 2) { region.x_ = regionJson[KEY_ORIGIN][0].asUInt(); region.y_ = regionJson[KEY_ORIGIN][1].asUInt(); region.width_ = regionJson[KEY_END][0].asUInt() - region.x_; region.height_ = regionJson[KEY_END][1].asUInt() - region.y_; regions_.push_back(region); } } else if (regionJson.isMember(KEY_REGION_TYPE) && regionJson[KEY_REGION_TYPE].asString() == KEY_REGION_BOUNDING_BOX) { // TODO throw OrthancException(ErrorCode_NotImplemented); } } } // TODO: support multiple series + move this } } }