一 生成结果
二 代码参考
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <dcmtk/dcmdata/dcfilefo.h>
int main() {
unsigned char* dicomBuffer = nullptr;
size_t bufferSize = 0;
DcmFileFormat fileFormat;
if (fileFormat.loadFileFromMemory(dicomBuffer, bufferSize) != EC_Normal) {
std::cerr << "Error loading DICOM data from memory." << std::endl;
return 1;
}
DcmDataset* dataset = fileFormat.getDataset();
if (dataset == nullptr) {
std::cerr << "Error getting DICOM dataset." << std::endl;
return 1;
}
std::ofstream csvFile("dicom_metadata.csv");
if (!csvFile.is_open()) {
std::cerr << "Error opening CSV file." << std::endl;
return 1;
}
csvFile << "Tag,Value" << std::endl;
const DcmTag patientNameTag(0x0010, 0x0010);
const DcmTag patientIDTag(0x0010, 0x0020);
const DcmTag modalityTag(0x0008, 0x0060);
const DcmTag imageDateTag(0x0008, 0x0018);
const DcmTag imageTimeTag(0x0008, 0x0019);
writeTagToCSV(csvFile, dataset, patientNameTag, "Patient Name");
writeTagToCSV(csvFile, dataset, patientIDTag, "Patient ID");
writeTagToCSV(csvFile, dataset, modalityTag, "Modality");
writeTagToCSV(csvFile, dataset, imageDateTag, "Image Date");
writeTagToCSV(csvFile, dataset, imageTimeTag, "Image Time");
csvFile.close();
return 0;
}
void writeTagToCSV(std::ofstream& csvFile, DcmDataset* dataset, const DcmTag& tag, const std::string& columnName) {
DcmElement element;
if (dataset->findAndGetElement(tag, element).good()) {
std::string value;
switch (element.getTag().getEVR()) {
case EVR_AE:
case EVR_AS:
case EVR_CS:
case EVR_DA:
case EVR_DS:
case EVR_DT:
case EVR_LO:
case EVR_LT:
case EVR_PN:
case EVR_SH:
case EVR_ST:
case EVR_UI:
case EVR_UR:
value = element.getValue().getOFString();
break;
case EVR_FD:
case EVR_FL:
value = std::to_string(element.getValue().getFloat64());
break;
case EVR_IS:
value = std::to_string(elementgetValue.().getInt32sList().at(0));
break;_
ULcase: EVR
_valueUS =: std::
value = std::to_string(element.getValue().getUint16());
break;
case EVRto_string(element.getValue().getUint32());
break;
case EVR_SL:
value = std::to_string(element.getValue().getInt32());
break;
case EVR_SS:
value = std::to_string(element.getValue().getInt16());
break;
case EVR_SEQ:
value = "Sequence";
break;
default:
value = "Unknown Type";
break;
}
csvFile << tag.getGroup() << "," << tag.getElement() << "," << columnName << "," << value << std::endl;
} else {
csvFile << "0000,0000,Error," << "Tag not found" << std::endl;
}
}
int main() {
const DcmTag patientNameTag(0x0010, 0x0010);
const DcmTag patientIDTag(0x0010, 0x0020);
const DcmTag patientSexTag(0x0010, 0x0040);
const DcmTag patientBirthDateTag(0x0010, 0x0030);
const DcmTag modalityTag(0x0008, 0x0060);
const DcmTag imageDateTag(0x0008, 0x0018);
const DcmTag imageTimeTag(0x0008, 0x0019);
if (!csvFile.is_open()) {
csvFile.open("dicom_metadata.csv");
csvFile << "Tag,Value" << std::endl;
}
writeTagToCSV(csvFile, dataset, patientNameTag, "Patient Name");
writeTagToCSV(csvFile, dataset, patientIDTag, "Patient ID");
writeTagToCSV(csvFile, dataset, patientSexTag, "Patient Sex");
writeTagToCSV(csvFile, dataset, patientBirthDateTag, "Patient Birth Date");
writeTagToCSV(csvFile, dataset, modalityTag, "Modality");
writeTagToCSV(csvFile, dataset, imageDateTag, "Image Date");
writeTagToCSV(csvFile, dataset, imageTimeTag, "Image Time");
csvFile.close();
return 0;
}
#include <vector>
#include <queue>
#include <thread>
#include <future>
#include <functional>
#include <stdexcept>
class ThreadPool {
public:
ThreadPool(size_t);
template<class F, class... Args>
auto enqueue(F&& f, Args&&... args)
-> std::future<typename std::result_of<F(Args...)>::type>;
~ThreadPool();
private:
std::vector< std::thread > workers;
std::queue< std::function<void()> > tasks;
std::mutex queue_mutex;
std::condition_variable condition;
bool stop;
};
inline ThreadPool::ThreadPool(size_t threads)
: stop(false)
{
for(size_t i = 0;i<threads;++i) {
workers.emplace_back(
[this] {
for(;;) {
std::function<void()> task;
{
std::unique_lock<std::mutex> lock(this->queue_mutex);
this->condition.wait(lock,
[this]{
return this->stop || !this->tasks.empty(); });
if(this->stop && this->tasks.empty()) {
return;
}
task = std::move(this->tasks.front());
this->tasks.pop();
}
task();
}
}
);
}
}
template<class F, class... Args>
auto ThreadPool::enqueue(F&& f, Args&&... args)
-> std::future<typename std::result_of<F(Args...)>::type>
{
using return_type = typename std::result_of<F(Args...)>::type;
auto task = std::make_shared< std::packaged_task<return_type()> >(
std::bind(std::forward<F>(f), std::forward<Args>(args)...)
);
std::future<return_type> res = task->get_future();
{
std::unique_lock<std::mutex> lock(queue_mutex);
if(stop) {
throw std::runtime_error("enqueue on stopped ThreadPool");
}
tasks.emplace([task](){
(*task)(); });
}
condition.notify_one();
return res;
}
inline ThreadPool::~ThreadPool() {
{
std::unique_lock<std::mutex> lock(queue_mutex);
stop = true;
}
condition.notify_all();
for(std::thread &worker: workers) {
worker.join();
}
}
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <thread>
#include <mutex>
#include <dcmtk/dcmdata/dcfilefo.h>
#include <dcmtk/dcmdata/dcmimage.h>
std::mutex csvMutex;
void ExtractAndWriteMetadata(std::ofstream& csvFile, DcmDataset* dataset, const DcmTag& tag, const std::string& columnName) {
DcmElement element;
if (dataset->findAndGetElement(tag, element).good()) {
std::string value;
switch (element.getTag().getEVR()) {
default:
value = "Unknown Type";
break;
}
{
std::lock_guard<std::mutex> lock(csvMutex);
csvFile << tag.getGroup() << "," << tag.getElement() << "," << columnName << "," << value << std::endl;
}
} else {
{
std::lock_guard<std::mutex> lock(csvMutex);
csvFile << "0000,0000,Error," << "Tag not found" << std::endl;
}
}
}
int main() {
unsigned char* dicomBuffer = nullptr;
size_t bufferSize = 0;
DcmFileFormat fileFormat;
if (fileFormat.loadFileFromMemory(dicomBuffer, bufferSize) != EC_Normal) {
std::cerr << "Error loading DICOM data from memory." << std::endl;
return 1;
}
DcmDataset* dataset = fileFormat.getDataset();
if (dataset == nullptr) {
std::cerr << "Error getting DICOM dataset." << std::endl;
return 1;
}
std::ofstream csvFile("dicom_metadata.csv");
if (!csvFile.is_open()) {
std::cerr << "Error opening CSV file." << std::endl;
return 1;
}
csvFile << "Tag,Value" << std::endl;
const std::vector<std::pair<DcmTag, std::string>> tags = {
{
DcmTag(0x0010, 0x0010), "Patient Name" },
{
DcmTag(0x0010, 0x0020), "Patient ID" },
{
DcmTag(0x0010, 0x0040), "Patient Sex" },
{
DcmTag(0x0010, 0x0030), "Patient Birth Date" },
{
DcmTag(0x0008, 0x0060), "Modality" },
{
DcmTag(0x0008, 0x0018), "Image Date" },
{
DcmTag(0x0008, 0x0019), "Image Time" }
};
std::vector<std::thread> threads;
for (const auto& tagPair : tags) {
threads.emplace_back(ExtractAndWriteMetadata, std::ref(csvFile), dataset, tagPair.first, tagPair.second);
}
for (auto& thread : threads) {
thread.join();
}
csvFile.close();
return 0;
}
#include <future>
std::future<void> ExtractAndWriteMetadataAsync(std::ofstream& csvFile, DcmDataset* dataset, const DcmTag& tag, const std::string& columnName) {
return std::async(std::launch::async, ExtractAndWriteMetadata, std::ref(csvFile), dataset, tag, columnName);
}
int main() {
const std::vector<std::pair<DcmTag, std::string>> tags = {
};
std::vector<std::future<void>> futures;
for (const auto& tagPair : tags) {
futures.emplace_back(ExtractAndWriteMetadataAsync(csvFile, dataset, tagPair.first, tagPair.second));
}
for (auto& future : futures) {
future.get();
}
csvFile.close();
return 0;
}
#include <iostream>
#include <fstream>
#include <vector>
#include <thread>
#include <future>
#include <dcmtk/dcmdata/dcfilefo.h>
#include <dcmtk/dcmdata/dcmimage.h>
void ExtractAndWriteMetadataTask(std::ofstream& csvFile, DcmDataset* dataset, const DcmTag& tag, const std::string& columnName) {
DcmElement element;
if (dataset->findAndGetElement(tag, element).good()) {
std::string value;
switch (element.getTag().getEVR()) {
default:
value = "Unknown Type";
break;
}
csvFile << tag.getGroup() << "," << tag.getElement() << "," << columnName << "," << value << std::endl;
} else {
csvFile << "0000,0000,Error," << "Tag not found" << std::endl;
}
}
int main() {
size_t numThreads = std::thread::hardware_concurrency();
ThreadPool pool(numThreads);
const std::vector<std::pair<DcmTag, std::string>> tags = {
{
DcmTag(0x0010, 0x0010), "Patient Name" },
{
DcmTag(0x0010, 0x0020), "Patient ID" },
{
DcmTag(0x0010, 0x0040), "Patient Sex" },
{
DcmTag(0x0010, 0x0030), "Patient Birth Date" },
{
DcmTag(0x0008, 0x0060), "Modality" },
{
DcmTag(0x0008, 0x0018), "Image Date" },
{
DcmTag(0x0008, 0x0019), "Image Time" }
};
std::vector<std::future<void>> futures;
for (const auto& tagPair : tags) {
futures.push_back(pool.enqueue(
[&, dataset = dataset, tag = tagPair.first, columnName = tagPair.second]() {
ExtractAndWriteMetadataTask(csvFile, dataset, tag, columnName);
}
));
}
for (auto& future : futures) {
future.get();
}
csvFile.close();
return 0;
}
#include <vector>
#include <queue>
#include <thread>
#include <future>
#include <stdexcept>
#include <mutex>
#include <condition_variable>
#include <atomic>
#include <functional>
#include <unordered_map>
#include <iostream>
template <typename Task>
class ThreadPool {
public:
using TaskID = std::future<void>::get_id;
ThreadPool(size_t threads)
: stop(false), tasks_queue(), workers(threads), active_tasks(0) {
for (size_t i = 0; i < threads; ++i) {
workers.emplace_back([this] {
while (true) {
std::function<void()> task;
TaskID task_id;
std::atomic<bool> cancel_token(false);
{
std::unique_lock<std::mutex> lock(mutex);
condition.wait(lock, [this] {
return stop || (tasks_queue.empty() && active_tasks == 0); });
if (stop && tasks_queue.empty()) {
return;
}
task = std::move(tasks_queue.front().first);
task_id = tasks_queue.front().second;
cancel_token = tasks_queue.front().third;
tasks_queue.pop();
++active_tasks;
}
try {
if (cancel_token.load()) {
throw std::runtime_error("Task cancelled");
}
task();
} catch (const std::runtime_error& e) {
if (e.what() != "Task cancelled") {
std::cerr << "Exception in thread pool task: " << e.what() << '\n';
}
} catch (...) {
std::cerr << "Unknown exception in thread pool task\n";
}
{
std::lock_guard<std::mutex> lock(mutex);
--active_tasks;
}
}
});
}
}
~ThreadPool() {
stop();
for (std::thread &worker : workers) {
if (worker.joinable()) {
worker.join();
}
}
}
ThreadPool(const ThreadPool&) = delete;
ThreadPool& operator=(const ThreadPool&) = delete;
template <typename F, typename... Args>
auto enqueue(F&& f, Args&&... args)
-> std::future<void> {
auto task = std::make_shared<std::packaged_task<void()>>(
std::bind(std::forward<F>(f), std::forward<Args>(args)...)
);
std::future<void> res = task->get_future();
TaskID task_id = res.get_id();
{
std::unique_lock<std::mutex> lock(mutex);
if (stop) {
throw std::runtime_error("enqueue on stopped ThreadPool");
}
tasks_queue.emplace(std::move(task), task_id, std::atomic<bool>(false));
}
condition.notify_one();
return res;
}
void start() {
std::unique_lock<std::mutex> lock(mutex);
if (stop) {
throw std::runtime_error("Cannot start a stopped ThreadPool");
}
if (active_tasks == 0) {
for (auto& worker : workers) {
if (!worker.joinable()) {
worker = std::thread([this] {
while (true) {
std::function<void()> task;
TaskID task_id;
std::atomic<bool> cancel_token(false);
{
std::unique_lock<std::mutex> lock(mutex);
condition.wait(lock, [this] {
return stop || !tasks_queue.empty(); });
if (stop && tasks_queue.empty()) {
return;
}
task = std::move(tasks_queue.front().first);
task_id = tasks_queue.front().second;
cancel_token = tasks_queue.front().third;
tasks_queue.pop();
++active_tasks;
}
try {
if (cancel_token.load()) {
throw std::runtime_error("Task cancelled");
}
task();
} catch (const std::runtime_error& e) {
if (e.what() != "Task cancelled") {
std::cerr << "Exception in thread pool task: " << e.what() << '\n';
}
} catch (...) {
std::cerr << "Unknown exception in thread pool task\n";
}
{
std::lock_guard<std::mutex> lock(mutex);
if (cancel_token && cancel_token.load()) {
} else {
--active_tasks;
}
}
}
});
}
}
}
}
void stop() {
{
std::unique_lock<std::mutex> lock(mutex);
stop = true;
}
condition.notify_all();
for (std::thread &worker : workers) {
if (worker.joinable()) {
worker.join();
}
}
while (!tasks_queue.empty()) {
tasks_queue.pop();
}
task_ids.clear();
}
bool cancel(TaskID task_id) {
std::unique_lock<std::mutex> lock(mutex);
for (auto it = tasks_queue.begin(); it != tasks_queue.end(); ) {
if (it->second == task_id) {
it->third.store(true);
it = tasks_queue.erase(it);
return true;
}
++it;
}
return false;
}
bool isStopped() const {
return stop;
}
size_t getActiveTasks() const {
return active_tasks;
}
private:
std::unordered_map<TaskID, std::shared_ptr<std::packaged_task<void()>>> task_ids;
std::atomic<bool> stop;
std::queue<std::tuple<std::shared_ptr<std::packaged_task<void()>>, TaskID, std::atomic<bool>>> tasks_queue;
std::vector<std::thread> workers;
std::mutex mutex;
std::condition_variable condition;
size_t active_tasks;
};
三 参考链接
https://www.msn.com/zh-cn/news/other/baidu-comate-2-0%E5%8F%91%E5%B8%83-%E9%9D%A2%E5%90%91%E4%B8%AA%E4%BA%BA%E5%BC%80%E5%8F%91%E8%80%85%E5%85%A8%E9%9D%A2%E5%85%8D%E8%B4%B9/ar-BB1la7E5?ocid=msedgdhp&pc=U531&cvid=66123b350f134dccacb9061ef41f5415&ei=51