ההבנה של תוכן קובץ DICOM היא חיונית לפיתוח תמונה רפואית, פתרון בעיות, וביטחון איכות.המדריך הזה מראה לך איך לבנות צופה מקיף של נתונים מטאוגרפיים DIKOM ב- C# אשר מוציא ומציג מידע על המטופל, פרטים של המחקר, ואת הפרמטרים הטכניים של התמונה.

מה זה DICOM Metadata?

קבצי DICOM מכילים שני מרכיבים עיקריים: נתוני פיקסל (תמונה אמיתית) ונתונים מטאוגרפיים (מידע על התמונה).

    • דמוגרפיה של המטופל: שם, זיהוי, תאריך לידה, מין
  • מידע מחקר: תאריך, זמן, תיאור, הרופא המתייחס
  • פרטים סדרה: מודל, חלק גוף, פרוטוקול תמונה
  • פרמטרים תמונה: גודל, שטח פיקסל, הגדרות חלון / רמה
  • מידע על ציוד: יצרן, מודל, גרסה תוכנה

צופה מטא-נתונים מסייע למפתחים לבדוק את התכונות הללו לדיבוג, אימות וניתוח נתונים.

גידול נתונים בסיסיים

התחל עם הוצאת תכונות DICOM נפוצות:

using Aspose.Medical.Dicom;

public class DicomMetadataViewer
{
    public DicomMetadata ExtractMetadata(string filePath)
    {
        DicomFile dicomFile = DicomFile.Open(filePath);
        var dataset = dicomFile.Dataset;
        
        return new DicomMetadata
        {
            // Patient Information
            PatientName = dataset.GetString(DicomTag.PatientName),
            PatientID = dataset.GetString(DicomTag.PatientID),
            PatientBirthDate = dataset.GetString(DicomTag.PatientBirthDate),
            PatientSex = dataset.GetString(DicomTag.PatientSex),
            PatientAge = dataset.GetString(DicomTag.PatientAge),
            
            // Study Information
            StudyInstanceUID = dataset.GetString(DicomTag.StudyInstanceUID),
            StudyDate = dataset.GetString(DicomTag.StudyDate),
            StudyTime = dataset.GetString(DicomTag.StudyTime),
            StudyDescription = dataset.GetString(DicomTag.StudyDescription),
            AccessionNumber = dataset.GetString(DicomTag.AccessionNumber),
            ReferringPhysician = dataset.GetString(DicomTag.ReferringPhysicianName),
            
            // Series Information
            SeriesInstanceUID = dataset.GetString(DicomTag.SeriesInstanceUID),
            Modality = dataset.GetString(DicomTag.Modality),
            SeriesDescription = dataset.GetString(DicomTag.SeriesDescription),
            SeriesNumber = dataset.GetString(DicomTag.SeriesNumber),
            BodyPartExamined = dataset.GetString(DicomTag.BodyPartExamined),
            
            // Image Information
            SOPInstanceUID = dataset.GetString(DicomTag.SOPInstanceUID),
            SOPClassUID = dataset.GetString(DicomTag.SOPClassUID),
            InstanceNumber = dataset.GetString(DicomTag.InstanceNumber),
            ImageType = dataset.GetString(DicomTag.ImageType),
            
            // Technical Parameters
            Rows = dataset.GetString(DicomTag.Rows),
            Columns = dataset.GetString(DicomTag.Columns),
            BitsAllocated = dataset.GetString(DicomTag.BitsAllocated),
            BitsStored = dataset.GetString(DicomTag.BitsStored),
            PixelSpacing = dataset.GetString(DicomTag.PixelSpacing),
            SliceThickness = dataset.GetString(DicomTag.SliceThickness),
            
            // Equipment Information
            Manufacturer = dataset.GetString(DicomTag.Manufacturer),
            ManufacturerModelName = dataset.GetString(DicomTag.ManufacturerModelName),
            StationName = dataset.GetString(DicomTag.StationName),
            InstitutionName = dataset.GetString(DicomTag.InstitutionName),
            SoftwareVersions = dataset.GetString(DicomTag.SoftwareVersions)
        };
    }
}

public class DicomMetadata
{
    // Patient
    public string PatientName { get; set; }
    public string PatientID { get; set; }
    public string PatientBirthDate { get; set; }
    public string PatientSex { get; set; }
    public string PatientAge { get; set; }
    
    // Study
    public string StudyInstanceUID { get; set; }
    public string StudyDate { get; set; }
    public string StudyTime { get; set; }
    public string StudyDescription { get; set; }
    public string AccessionNumber { get; set; }
    public string ReferringPhysician { get; set; }
    
    // Series
    public string SeriesInstanceUID { get; set; }
    public string Modality { get; set; }
    public string SeriesDescription { get; set; }
    public string SeriesNumber { get; set; }
    public string BodyPartExamined { get; set; }
    
    // Image
    public string SOPInstanceUID { get; set; }
    public string SOPClassUID { get; set; }
    public string InstanceNumber { get; set; }
    public string ImageType { get; set; }
    
    // Technical
    public string Rows { get; set; }
    public string Columns { get; set; }
    public string BitsAllocated { get; set; }
    public string BitsStored { get; set; }
    public string PixelSpacing { get; set; }
    public string SliceThickness { get; set; }
    
    // Equipment
    public string Manufacturer { get; set; }
    public string ManufacturerModelName { get; set; }
    public string StationName { get; set; }
    public string InstitutionName { get; set; }
    public string SoftwareVersions { get; set; }
}

עקבו אחרי all dicom tag

לרשום את כל התגיות בקובץ DICOM לבדיקה מלאה:

public class DicomTagBrowser
{
    public List<DicomTagInfo> GetAllTags(string filePath)
    {
        DicomFile dicomFile = DicomFile.Open(filePath);
        var tags = new List<DicomTagInfo>();
        
        foreach (var element in dicomFile.Dataset)
        {
            var tagInfo = new DicomTagInfo
            {
                Tag = element.Tag.ToString(),
                TagHex = $"({element.Tag.Group:X4},{element.Tag.Element:X4})",
                Keyword = element.Tag.DictionaryEntry?.Keyword ?? "Unknown",
                Name = element.Tag.DictionaryEntry?.Name ?? "Private Tag",
                VR = element.ValueRepresentation.Code,
                Length = element.Length,
                Value = GetDisplayValue(element)
            };
            
            tags.Add(tagInfo);
        }
        
        return tags;
    }

    private string GetDisplayValue(DicomElement element)
    {
        try
        {
            // Handle different value representations
            if (element.Length == 0)
                return "(empty)";
            
            if (element.Length > 256)
                return $"(binary data, {element.Length} bytes)";
            
            // Try to get string value
            var values = element.Get<string[]>();
            if (values != null && values.Length > 0)
            {
                return string.Join(" \\ ", values);
            }
            
            return "(unable to display)";
        }
        catch
        {
            return $"(binary data, {element.Length} bytes)";
        }
    }
}

public class DicomTagInfo
{
    public string Tag { get; set; }
    public string TagHex { get; set; }
    public string Keyword { get; set; }
    public string Name { get; set; }
    public string VR { get; set; }
    public long Length { get; set; }
    public string Value { get; set; }
}

הוצאת נתונים ספציפיים

שיטות תמונה שונות יש תכונות ייחודיות:

public class ModalityMetadataExtractor
{
    public object ExtractModalitySpecificData(string filePath)
    {
        DicomFile dicomFile = DicomFile.Open(filePath);
        var dataset = dicomFile.Dataset;
        
        string modality = dataset.GetString(DicomTag.Modality);
        
        return modality switch
        {
            "CT" => ExtractCtMetadata(dataset),
            "MR" => ExtractMrMetadata(dataset),
            "CR" or "DX" => ExtractRadiographyMetadata(dataset),
            "US" => ExtractUltrasoundMetadata(dataset),
            "MG" => ExtractMammographyMetadata(dataset),
            _ => ExtractGenericMetadata(dataset)
        };
    }

    private CtMetadata ExtractCtMetadata(DicomDataset dataset)
    {
        return new CtMetadata
        {
            KVP = dataset.GetString(DicomTag.KVP),
            XRayTubeCurrent = dataset.GetString(DicomTag.XRayTubeCurrent),
            ExposureTime = dataset.GetString(DicomTag.ExposureTime),
            SliceThickness = dataset.GetString(DicomTag.SliceThickness),
            SpacingBetweenSlices = dataset.GetString(DicomTag.SpacingBetweenSlices),
            ConvolutionKernel = dataset.GetString(DicomTag.ConvolutionKernel),
            GantryTilt = dataset.GetString(DicomTag.GantryDetectorTilt),
            TableHeight = dataset.GetString(DicomTag.TableHeight),
            RotationDirection = dataset.GetString(DicomTag.RotationDirection),
            CTDIvol = dataset.GetString(DicomTag.CTDIvol),
            WindowCenter = dataset.GetString(DicomTag.WindowCenter),
            WindowWidth = dataset.GetString(DicomTag.WindowWidth)
        };
    }

    private MrMetadata ExtractMrMetadata(DicomDataset dataset)
    {
        return new MrMetadata
        {
            MagneticFieldStrength = dataset.GetString(DicomTag.MagneticFieldStrength),
            SequenceName = dataset.GetString(DicomTag.SequenceName),
            ScanningSequence = dataset.GetString(DicomTag.ScanningSequence),
            SequenceVariant = dataset.GetString(DicomTag.SequenceVariant),
            RepetitionTime = dataset.GetString(DicomTag.RepetitionTime),
            EchoTime = dataset.GetString(DicomTag.EchoTime),
            InversionTime = dataset.GetString(DicomTag.InversionTime),
            FlipAngle = dataset.GetString(DicomTag.FlipAngle),
            SliceThickness = dataset.GetString(DicomTag.SliceThickness),
            EchoTrainLength = dataset.GetString(DicomTag.EchoTrainLength),
            PixelBandwidth = dataset.GetString(DicomTag.PixelBandwidth),
            ImagingFrequency = dataset.GetString(DicomTag.ImagingFrequency)
        };
    }

    private RadiographyMetadata ExtractRadiographyMetadata(DicomDataset dataset)
    {
        return new RadiographyMetadata
        {
            KVP = dataset.GetString(DicomTag.KVP),
            ExposureTime = dataset.GetString(DicomTag.ExposureTime),
            XRayTubeCurrent = dataset.GetString(DicomTag.XRayTubeCurrent),
            Exposure = dataset.GetString(DicomTag.Exposure),
            ExposureIndex = dataset.GetString(DicomTag.ExposureIndex),
            TargetExposureIndex = dataset.GetString(DicomTag.TargetExposureIndex),
            DeviationIndex = dataset.GetString(DicomTag.DeviationIndex),
            DistanceSourceToDetector = dataset.GetString(DicomTag.DistanceSourceToDetector),
            DistanceSourceToPatient = dataset.GetString(DicomTag.DistanceSourceToPatient),
            Grid = dataset.GetString(DicomTag.Grid),
            ViewPosition = dataset.GetString(DicomTag.ViewPosition)
        };
    }

    private UltrasoundMetadata ExtractUltrasoundMetadata(DicomDataset dataset)
    {
        return new UltrasoundMetadata
        {
            TransducerType = dataset.GetString(DicomTag.TransducerType),
            TransducerFrequency = dataset.GetString(DicomTag.TransducerFrequency),
            DepthOfScanField = dataset.GetString(DicomTag.DepthOfScanField),
            MechanicalIndex = dataset.GetString(DicomTag.MechanicalIndex),
            ThermalIndex = dataset.GetString(DicomTag.SoftTissueThermalIndex),
            FrameTime = dataset.GetString(DicomTag.FrameTime),
            NumberOfFrames = dataset.GetString(DicomTag.NumberOfFrames)
        };
    }

    private MammographyMetadata ExtractMammographyMetadata(DicomDataset dataset)
    {
        return new MammographyMetadata
        {
            ViewPosition = dataset.GetString(DicomTag.ViewPosition),
            ImageLaterality = dataset.GetString(DicomTag.ImageLaterality),
            BreastImplantPresent = dataset.GetString(DicomTag.BreastImplantPresent),
            CompressionForce = dataset.GetString(DicomTag.CompressionForce),
            BodyPartThickness = dataset.GetString(DicomTag.BodyPartThickness),
            AnodeTargetMaterial = dataset.GetString(DicomTag.AnodeTargetMaterial),
            FilterMaterial = dataset.GetString(DicomTag.FilterMaterial),
            KVP = dataset.GetString(DicomTag.KVP),
            ExposureTime = dataset.GetString(DicomTag.ExposureTime),
            OrganDose = dataset.GetString(DicomTag.OrganDose)
        };
    }

    private GenericMetadata ExtractGenericMetadata(DicomDataset dataset)
    {
        return new GenericMetadata
        {
            Modality = dataset.GetString(DicomTag.Modality),
            StudyDescription = dataset.GetString(DicomTag.StudyDescription),
            SeriesDescription = dataset.GetString(DicomTag.SeriesDescription)
        };
    }
}

// Modality-specific metadata classes
public class CtMetadata
{
    public string KVP { get; set; }
    public string XRayTubeCurrent { get; set; }
    public string ExposureTime { get; set; }
    public string SliceThickness { get; set; }
    public string SpacingBetweenSlices { get; set; }
    public string ConvolutionKernel { get; set; }
    public string GantryTilt { get; set; }
    public string TableHeight { get; set; }
    public string RotationDirection { get; set; }
    public string CTDIvol { get; set; }
    public string WindowCenter { get; set; }
    public string WindowWidth { get; set; }
}

public class MrMetadata
{
    public string MagneticFieldStrength { get; set; }
    public string SequenceName { get; set; }
    public string ScanningSequence { get; set; }
    public string SequenceVariant { get; set; }
    public string RepetitionTime { get; set; }
    public string EchoTime { get; set; }
    public string InversionTime { get; set; }
    public string FlipAngle { get; set; }
    public string SliceThickness { get; set; }
    public string EchoTrainLength { get; set; }
    public string PixelBandwidth { get; set; }
    public string ImagingFrequency { get; set; }
}

public class RadiographyMetadata
{
    public string KVP { get; set; }
    public string ExposureTime { get; set; }
    public string XRayTubeCurrent { get; set; }
    public string Exposure { get; set; }
    public string ExposureIndex { get; set; }
    public string TargetExposureIndex { get; set; }
    public string DeviationIndex { get; set; }
    public string DistanceSourceToDetector { get; set; }
    public string DistanceSourceToPatient { get; set; }
    public string Grid { get; set; }
    public string ViewPosition { get; set; }
}

public class UltrasoundMetadata
{
    public string TransducerType { get; set; }
    public string TransducerFrequency { get; set; }
    public string DepthOfScanField { get; set; }
    public string MechanicalIndex { get; set; }
    public string ThermalIndex { get; set; }
    public string FrameTime { get; set; }
    public string NumberOfFrames { get; set; }
}

public class MammographyMetadata
{
    public string ViewPosition { get; set; }
    public string ImageLaterality { get; set; }
    public string BreastImplantPresent { get; set; }
    public string CompressionForce { get; set; }
    public string BodyPartThickness { get; set; }
    public string AnodeTargetMaterial { get; set; }
    public string FilterMaterial { get; set; }
    public string KVP { get; set; }
    public string ExposureTime { get; set; }
    public string OrganDose { get; set; }
}

public class GenericMetadata
{
    public string Modality { get; set; }
    public string StudyDescription { get; set; }
    public string SeriesDescription { get; set; }
}

תגית: Console-Based Viewer

יצירת כלי קו הפקודה לבדיקה מהירה של DICOM:

public class DicomViewerConsole
{
    public void DisplayMetadata(string filePath)
    {
        var viewer = new DicomMetadataViewer();
        var metadata = viewer.ExtractMetadata(filePath);
        
        Console.WriteLine("═══════════════════════════════════════════════════════════");
        Console.WriteLine("                    DICOM METADATA VIEWER                    ");
        Console.WriteLine("═══════════════════════════════════════════════════════════");
        Console.WriteLine($"File: {Path.GetFileName(filePath)}");
        Console.WriteLine();
        
        PrintSection("PATIENT INFORMATION");
        PrintField("Patient Name", metadata.PatientName);
        PrintField("Patient ID", metadata.PatientID);
        PrintField("Birth Date", FormatDate(metadata.PatientBirthDate));
        PrintField("Sex", metadata.PatientSex);
        PrintField("Age", metadata.PatientAge);
        
        PrintSection("STUDY INFORMATION");
        PrintField("Study Date", FormatDate(metadata.StudyDate));
        PrintField("Study Time", FormatTime(metadata.StudyTime));
        PrintField("Description", metadata.StudyDescription);
        PrintField("Accession #", metadata.AccessionNumber);
        PrintField("Referring MD", metadata.ReferringPhysician);
        PrintField("Study UID", metadata.StudyInstanceUID);
        
        PrintSection("SERIES INFORMATION");
        PrintField("Modality", metadata.Modality);
        PrintField("Description", metadata.SeriesDescription);
        PrintField("Series #", metadata.SeriesNumber);
        PrintField("Body Part", metadata.BodyPartExamined);
        PrintField("Series UID", metadata.SeriesInstanceUID);
        
        PrintSection("IMAGE INFORMATION");
        PrintField("Instance #", metadata.InstanceNumber);
        PrintField("Image Type", metadata.ImageType);
        PrintField("Dimensions", $"{metadata.Columns} x {metadata.Rows}");
        PrintField("Bits Stored", metadata.BitsStored);
        PrintField("Pixel Spacing", metadata.PixelSpacing);
        PrintField("SOP Instance", metadata.SOPInstanceUID);
        
        PrintSection("EQUIPMENT");
        PrintField("Manufacturer", metadata.Manufacturer);
        PrintField("Model", metadata.ManufacturerModelName);
        PrintField("Station", metadata.StationName);
        PrintField("Institution", metadata.InstitutionName);
        PrintField("Software", metadata.SoftwareVersions);
        
        Console.WriteLine("═══════════════════════════════════════════════════════════");
    }

    private void PrintSection(string title)
    {
        Console.WriteLine();
        Console.WriteLine($"─── {title} ───");
    }

    private void PrintField(string label, string value)
    {
        string displayValue = string.IsNullOrEmpty(value) ? "(not specified)" : value;
        Console.WriteLine($"  {label,-15}: {displayValue}");
    }

    private string FormatDate(string dicomDate)
    {
        if (string.IsNullOrEmpty(dicomDate) || dicomDate.Length != 8)
            return dicomDate;
        
        return $"{dicomDate.Substring(0, 4)}-{dicomDate.Substring(4, 2)}-{dicomDate.Substring(6, 2)}";
    }

    private string FormatTime(string dicomTime)
    {
        if (string.IsNullOrEmpty(dicomTime) || dicomTime.Length < 6)
            return dicomTime;
        
        return $"{dicomTime.Substring(0, 2)}:{dicomTime.Substring(2, 2)}:{dicomTime.Substring(4, 2)}";
    }
}

Web API עבור Metadata Retrieval

לבנות נקודות סיום REST עבור גישה למטא-נתונים:

[ApiController]
[Route("api/[controller]")]
public class DicomMetadataController : ControllerBase
{
    private readonly string _uploadPath = Path.Combine(Path.GetTempPath(), "dicom_uploads");

    public DicomMetadataController()
    {
        Directory.CreateDirectory(_uploadPath);
    }

    [HttpPost("upload")]
    public async Task<IActionResult> UploadAndExtract(IFormFile file)
    {
        if (file == null || file.Length == 0)
            return BadRequest("No file provided");

        var filePath = Path.Combine(_uploadPath, $"{Guid.NewGuid()}.dcm");
        
        try
        {
            using (var stream = new FileStream(filePath, FileMode.Create))
            {
                await file.CopyToAsync(stream);
            }

            var viewer = new DicomMetadataViewer();
            var metadata = viewer.ExtractMetadata(filePath);
            
            return Ok(metadata);
        }
        finally
        {
            if (System.IO.File.Exists(filePath))
                System.IO.File.Delete(filePath);
        }
    }

    [HttpPost("tags")]
    public async Task<IActionResult> GetAllTags(IFormFile file)
    {
        if (file == null || file.Length == 0)
            return BadRequest("No file provided");

        var filePath = Path.Combine(_uploadPath, $"{Guid.NewGuid()}.dcm");
        
        try
        {
            using (var stream = new FileStream(filePath, FileMode.Create))
            {
                await file.CopyToAsync(stream);
            }

            var browser = new DicomTagBrowser();
            var tags = browser.GetAllTags(filePath);
            
            return Ok(tags);
        }
        finally
        {
            if (System.IO.File.Exists(filePath))
                System.IO.File.Delete(filePath);
        }
    }

    [HttpPost("modality-specific")]
    public async Task<IActionResult> GetModalityMetadata(IFormFile file)
    {
        if (file == null || file.Length == 0)
            return BadRequest("No file provided");

        var filePath = Path.Combine(_uploadPath, $"{Guid.NewGuid()}.dcm");
        
        try
        {
            using (var stream = new FileStream(filePath, FileMode.Create))
            {
                await file.CopyToAsync(stream);
            }

            var extractor = new ModalityMetadataExtractor();
            var data = extractor.ExtractModalitySpecificData(filePath);
            
            return Ok(data);
        }
        finally
        {
            if (System.IO.File.Exists(filePath))
                System.IO.File.Delete(filePath);
        }
    }
}

דיווחים על Metadata

ליצור דיווחים metadata בפורמטים שונים:

public class MetadataReportGenerator
{
    public void GenerateCsvReport(string dicomDirectory, string outputPath)
    {
        var viewer = new DicomMetadataViewer();
        var records = new List<string>();
        
        // Header
        records.Add("FileName,PatientID,PatientName,StudyDate,Modality,SeriesDescription,Rows,Columns");
        
        var files = Directory.GetFiles(dicomDirectory, "*.dcm", SearchOption.AllDirectories);
        
        foreach (var file in files)
        {
            try
            {
                var metadata = viewer.ExtractMetadata(file);
                
                var record = string.Join(",",
                    EscapeCsv(Path.GetFileName(file)),
                    EscapeCsv(metadata.PatientID),
                    EscapeCsv(metadata.PatientName),
                    EscapeCsv(metadata.StudyDate),
                    EscapeCsv(metadata.Modality),
                    EscapeCsv(metadata.SeriesDescription),
                    metadata.Rows ?? "",
                    metadata.Columns ?? "");
                
                records.Add(record);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error processing {file}: {ex.Message}");
            }
        }
        
        File.WriteAllLines(outputPath, records);
    }

    public void GenerateJsonReport(string dicomDirectory, string outputPath)
    {
        var viewer = new DicomMetadataViewer();
        var metadataList = new List<object>();
        
        var files = Directory.GetFiles(dicomDirectory, "*.dcm", SearchOption.AllDirectories);
        
        foreach (var file in files)
        {
            try
            {
                var metadata = viewer.ExtractMetadata(file);
                metadataList.Add(new
                {
                    FileName = Path.GetFileName(file),
                    Metadata = metadata
                });
            }
            catch (Exception ex)
            {
                metadataList.Add(new
                {
                    FileName = Path.GetFileName(file),
                    Error = ex.Message
                });
            }
        }
        
        var json = JsonSerializer.Serialize(metadataList, new JsonSerializerOptions 
        { 
            WriteIndented = true 
        });
        
        File.WriteAllText(outputPath, json);
    }

    private string EscapeCsv(string value)
    {
        if (string.IsNullOrEmpty(value))
            return "";
        
        if (value.Contains(",") || value.Contains("\"") || value.Contains("\n"))
        {
            return $"\"{value.Replace("\"", "\"\"")}\"";
        }
        
        return value;
    }
}

שימוש בדוגמה

class Program
{
    static void Main(string[] args)
    {
        // Activate license
        Metered metered = new Metered();
        metered.SetMeteredKey("your-public-key", "your-private-key");

        string dicomFile = @"C:\DICOM\sample.dcm";
        
        // Console viewer
        var consoleViewer = new DicomViewerConsole();
        consoleViewer.DisplayMetadata(dicomFile);
        
        // Browse all tags
        var browser = new DicomTagBrowser();
        var tags = browser.GetAllTags(dicomFile);
        
        Console.WriteLine($"\nTotal tags: {tags.Count}");
        
        // Generate report for directory
        var reportGenerator = new MetadataReportGenerator();
        reportGenerator.GenerateCsvReport(@"C:\DICOM\Studies", @"C:\Reports\metadata.csv");
    }
}

מסקנה

בניית צופה נתונים DICOM נותן לך יכולות חיוניות לפיתוח תמונה רפואית. בין אם אתה זקוק למפקח קו פקודה מהיר, API אינטרנט לאינטגרציה, או כלי דיווח חבילה, Aspose.Medical for .NET מספק את הבסיס לחלץ ולנתח את המאפיינים של DIKOM.

לקבלת מידע נוסף על העבודה עם קבצי DICOM, בקר ב תגית: מסמכים רפואיים.

More in this category