27std::vector<core::dicom_dataset>
29 std::vector<core::dicom_dataset> result;
39 std::set<std::string> series_uids;
43 series_uids.insert(
uid);
46 return series_uids.size();
54 static std::atomic<uint64_t> counter{0};
55 auto now = std::chrono::system_clock::now();
56 auto timestamp = std::chrono::duration_cast<std::chrono::milliseconds>(
57 now.time_since_epoch()).count();
59 return root +
"." + std::to_string(timestamp) +
"." + std::to_string(++counter);
63 auto now = std::chrono::system_clock::now();
64 auto time_t_now = std::chrono::system_clock::to_time_t(now);
67 localtime_s(&tm_now, &time_t_now);
69 localtime_r(&time_t_now, &tm_now);
72 std::ostringstream oss;
73 oss << std::put_time(&tm_now,
"%Y%m%d");
78 auto now = std::chrono::system_clock::now();
79 auto time_t_now = std::chrono::system_clock::to_time_t(now);
82 localtime_s(&tm_now, &time_t_now);
84 localtime_r(&time_t_now, &tm_now);
87 std::ostringstream oss;
88 oss << std::put_time(&tm_now,
"%H%M%S");
98 const std::string& patient_name,
99 const std::string& patient_id,
100 const std::string& birth_date,
101 const std::string& sex) {
111 const std::string& study_uid,
112 const std::string& accession_number,
113 const std::string& study_id,
114 const std::string& description) {
127 const std::string& series_uid,
128 const std::string& modality,
129 const std::string& series_number,
130 const std::string& description) {
143 uint16_t bits_allocated,
144 uint16_t bits_stored,
145 uint16_t samples_per_pixel,
146 const std::string& photometric) {
153 static_cast<uint16_t
>(bits_stored - 1));
163 uint16_t bits_allocated,
164 uint16_t samples_per_pixel,
165 uint16_t fill_value) {
167 size_t pixel_count =
static_cast<size_t>(rows) * columns * samples_per_pixel;
169 if (bits_allocated == 8) {
170 std::vector<uint8_t> pixel_data(pixel_count,
static_cast<uint8_t
>(fill_value & 0xFF));
172 pixel_elem.
set_value(std::span<const uint8_t>(pixel_data.data(), pixel_data.size()));
173 ds.
insert(std::move(pixel_elem));
175 std::vector<uint16_t> pixel_data(pixel_count, fill_value);
177 pixel_elem.
set_value(std::span<const uint8_t>(
178 reinterpret_cast<const uint8_t*
>(pixel_data.data()),
179 pixel_data.size() *
sizeof(uint16_t)));
180 ds.
insert(std::move(pixel_elem));
188 uint16_t bits_allocated,
190 uint16_t samples_per_pixel) {
196 size_t frame_size =
static_cast<size_t>(rows) * columns * samples_per_pixel;
197 size_t total_pixels = frame_size * num_frames;
200 std::mt19937 gen(42);
202 if (bits_allocated == 8) {
203 std::uniform_int_distribution<uint16_t> dist(0, 255);
204 std::vector<uint8_t> pixel_data(total_pixels);
205 for (
size_t i = 0; i < total_pixels; ++i) {
206 pixel_data[i] =
static_cast<uint8_t
>(dist(gen));
209 pixel_elem.
set_value(std::span<const uint8_t>(pixel_data.data(), pixel_data.size()));
210 ds.
insert(std::move(pixel_elem));
212 std::uniform_int_distribution<uint16_t> dist(0, 4095);
213 std::vector<uint16_t> pixel_data(total_pixels);
214 for (
size_t i = 0; i < total_pixels; ++i) {
215 pixel_data[i] = dist(gen);
218 pixel_elem.
set_value(std::span<const uint8_t>(
219 reinterpret_cast<const uint8_t*
>(pixel_data.data()),
220 pixel_data.size() *
sizeof(uint16_t)));
221 ds.
insert(std::move(pixel_elem));
233 add_study_module(ds, study_uid,
"ACCCT001",
"STUDYCT001",
"CT Integration Test");
238 "1.2.840.10008.5.1.4.1.1.2");
252 add_study_module(ds, study_uid,
"ACCMR001",
"STUDYMR001",
"MR Integration Test");
257 "1.2.840.10008.5.1.4.1.1.4");
271 add_study_module(ds, study_uid,
"ACCXA001",
"STUDYXA001",
"XA Integration Test");
304 add_study_module(ds, study_uid,
"ACCUS001",
"STUDYUS001",
"US Integration Test");
327 add_study_module(ds, study_uid,
"ACCXACINE001",
"STUDYXACINE001",
"XA Cine Test");
358 add_study_module(ds, study_uid,
"ACCUSCINE001",
"STUDYUSCINE001",
"US Cine Test");
382 add_study_module(ds, study_uid,
"ACCENHCT001",
"STUDYENHCT001",
"Enhanced CT Test");
387 "1.2.840.10008.5.1.4.1.1.2.1");
395 "ORIGINAL\\PRIMARY\\VOLUME\\NONE");
406 add_study_module(ds, study_uid,
"ACCENHMR001",
"STUDYENHMR001",
"Enhanced MR Test");
411 "1.2.840.10008.5.1.4.1.1.4.1");
419 "ORIGINAL\\PRIMARY\\VOLUME\\NONE");
431 const std::string& patient_id,
432 const std::vector<std::string>& modalities) {
435 study.patient_id = patient_id.empty() ?
"PATJOURNEY001" : patient_id;
436 study.patient_name =
"TEST^MULTIMODAL^PATIENT";
439 for (
const auto& modality : modalities) {
444 "Multi-Modal Patient Journey");
446 std::string series_desc = modality +
" Series";
447 add_series_module(ds,
"", modality, std::to_string(study.datasets.size() + 1), series_desc);
450 std::string sop_class_uid;
451 uint16_t rows = 64, columns = 64, bits = 16;
453 if (modality ==
"CT") {
454 sop_class_uid =
"1.2.840.10008.5.1.4.1.1.2";
455 }
else if (modality ==
"MR") {
456 sop_class_uid =
"1.2.840.10008.5.1.4.1.1.4";
457 }
else if (modality ==
"XA") {
461 }
else if (modality ==
"US") {
468 sop_class_uid =
"1.2.840.10008.5.1.4.1.1.7";
477 study.datasets.push_back(std::move(ds));
484 const std::string& patient_id,
485 const std::string& modality) {
489 std::string pid = patient_id.empty() ?
"TESTWL001" : patient_id;
499 modality +
"_SCANNER");
501 modality +
" Examination");
519 add_study_module(ds,
"",
"ACCLARGE001",
"STUDYLARGE001",
"Large Dataset Test");
524 "1.2.840.10008.5.1.4.1.1.7");
529 size_t total_bytes = target_size_mb * 1024 * 1024;
530 size_t total_pixels = total_bytes / 2;
533 uint16_t dimension =
static_cast<uint16_t
>(std::sqrt(
static_cast<double>(total_pixels)));
534 dimension = (std::min)(dimension,
static_cast<uint16_t
>(4096));
551 "Unicode Test Study - 유니코드 테스트");
556 "1.2.840.10008.5.1.4.1.1.7");
569 add_study_module(ds,
"",
"ACCPRIVATE001",
"STUDYPRIVATE001",
"Private Tags Test");
574 "1.2.840.10008.5.1.4.1.1.7");
601 add_study_module(ds,
"",
"ACCINVALID001",
"STUDYINVALID001",
"Invalid Dataset Test");
606 "1.2.840.10008.5.1.4.1.1.7");
638 std::vector<uint8_t> corrupted(100, 0xFF);
640 pixel_elem.
set_value(std::span<const uint8_t>(corrupted.data(), corrupted.size()));
641 ds.
insert(std::move(pixel_elem));
648 "THIS_ACCESSION_NUMBER_IS_WAY_TOO_LONG_FOR_SH_VR");
void set_numeric(dicom_tag tag, encoding::vr_type vr, T value)
Set a numeric value for the given tag.
auto remove(dicom_tag tag) -> bool
Remove an element from the dataset.
void insert(dicom_element element)
Insert or replace an element in the dataset.
void set_string(dicom_tag tag, encoding::vr_type vr, std::string_view value)
Set a string value for the given tag.
void set_value(std::span< const uint8_t > data)
Set the raw value data.
static void add_series_module(core::dicom_dataset &ds, const std::string &series_uid, const std::string &modality, const std::string &series_number, const std::string &description)
Add common series module attributes.
static core::dicom_dataset us_cine(uint32_t frames=60, const std::string &study_uid="")
Generate a multi-frame US cine dataset.
static core::dicom_dataset invalid(invalid_dataset_type type)
Generate an intentionally invalid dataset.
static std::string generate_uid(const std::string &root="1.2.826.0.1.3680043.9.9999")
Generate a unique UID for testing.
static void add_multiframe_pixel_data(core::dicom_dataset &ds, uint16_t rows, uint16_t columns, uint16_t bits_allocated, uint32_t num_frames, uint16_t samples_per_pixel=1)
Generate pixel data for multi-frame image.
static core::dicom_dataset large(size_t target_size_mb)
Generate a large dataset for stress testing.
static void add_study_module(core::dicom_dataset &ds, const std::string &study_uid, const std::string &accession_number, const std::string &study_id, const std::string &description)
Add common study module attributes.
static core::dicom_dataset worklist(const std::string &patient_id="", const std::string &modality="CT")
Generate a worklist item dataset.
static core::dicom_dataset mr(const std::string &study_uid="")
Generate an MR Image dataset.
static core::dicom_dataset enhanced_ct(uint32_t frames=100, const std::string &study_uid="")
Generate an Enhanced CT multi-frame dataset.
static multi_modal_study patient_journey(const std::string &patient_id, const std::vector< std::string > &modalities={"CT", "MR", "XA"})
Generate a complete multi-modal patient study.
static void add_pixel_data(core::dicom_dataset &ds, uint16_t rows, uint16_t columns, uint16_t bits_allocated, uint16_t samples_per_pixel=1, uint16_t fill_value=512)
Generate pixel data for single-frame image.
static core::dicom_dataset unicode()
Generate a dataset with Unicode patient names.
static core::dicom_dataset ct(const std::string &study_uid="")
Generate a CT Image dataset.
static void add_image_pixel_module(core::dicom_dataset &ds, uint16_t rows, uint16_t columns, uint16_t bits_allocated, uint16_t bits_stored, uint16_t samples_per_pixel=1, const std::string &photometric="MONOCHROME2")
Add common image pixel module attributes.
static core::dicom_dataset enhanced_mr(uint32_t frames=50, const std::string &study_uid="")
Generate an Enhanced MR multi-frame dataset.
static core::dicom_dataset us(const std::string &study_uid="")
Generate a single-frame US Image dataset.
static core::dicom_dataset xa(const std::string &study_uid="")
Generate a single-frame XA Image dataset.
static core::dicom_dataset with_private_tags(const std::string &creator_id="TEST PRIVATE CREATOR")
Generate a dataset with private tags.
static void add_patient_module(core::dicom_dataset &ds, const std::string &patient_name, const std::string &patient_id, const std::string &birth_date="19800101", const std::string &sex="M")
Add common patient module attributes.
static std::string current_time()
Get current time in DICOM TM format (HHMMSS)
static std::string current_date()
Get current date in DICOM DA format (YYYYMMDD)
static core::dicom_dataset xa_cine(uint32_t frames=30, const std::string &study_uid="")
Generate a multi-frame XA cine dataset.
DICOM Data Element representation (Tag, VR, Value)
@ OB
Other Byte (variable length)
@ DA
Date (8 chars, format: YYYYMMDD)
@ IS
Integer String (12 chars max)
@ LO
Long String (64 chars max)
@ DS
Decimal String (16 chars max)
@ UI
Unique Identifier (64 chars max)
@ US
Unsigned Short (2 bytes)
@ PN
Person Name (64 chars max per component group)
@ CS
Code String (16 chars max, uppercase + digits + space + underscore)
@ OW
Other Word (variable length)
@ TM
Time (14 chars max, format: HHMMSS.FFFFFF)
@ AE
Application Entity (16 chars max)
@ SH
Short String (16 chars max)
invalid_dataset_type
Types of invalid datasets for error testing.
@ missing_patient_id
Missing Patient ID.
@ missing_sop_class_uid
Missing SOP Class UID.
@ oversized_value
Value exceeds VR length limit.
@ missing_study_instance_uid
Missing Study Instance UID.
@ invalid_vr
Invalid Value Representation.
@ missing_sop_instance_uid
Missing SOP Instance UID.
@ corrupted_pixel_data
Corrupted pixel data.
constexpr std::string_view us_image_storage_uid
US Image Storage SOP Class UID (single-frame)
constexpr std::string_view xa_image_storage_uid
XA Image Storage SOP Class UID (single/multi-frame)
constexpr std::string_view us_multiframe_image_storage_uid
US Multi-frame Image Storage SOP Class UID (cine loops)
Represents a complete patient study with multiple modalities.
std::vector< core::dicom_dataset > get_by_modality(const std::string &modality) const
Get datasets filtered by modality.
std::vector< core::dicom_dataset > datasets
All datasets in study.
size_t series_count() const
Get total number of series in study.
Comprehensive DICOM test data generators for integration testing.
constexpr dicom_tag number_of_frames