Skip to content

Dcm批量转png

需要处理序列的dcm文件,vtk的dcmread兼容性太差,利用itk读取dcm让后转成vti文件。利用imagecast可以直接转成unsigned char 保存成png。我还需要opencv操作下,干脆就把vti转成cv::mat保存了。

bool ReadDcm(const QString &input_file_name,
             const vtkSmartPointer<vtkImageData> &imagedata) {
    if (input_file_name.isEmpty()) {
        return false;
    }
    QFileInfo file_info(input_file_name);
    QString extension = file_info.path();
    using PixelType = float;
    constexpr unsigned int Dimension = 3;
    using ImageType = itk::Image< PixelType, Dimension >;
    using ReaderType = itk::ImageSeriesReader< ImageType >;
    using ImageIOType = itk::GDCMImageIO;
    using NamesGeneratorType = itk::GDCMSeriesFileNames;
    ReaderType::Pointer reader = ReaderType::New();
    ImageIOType::Pointer dicomIO = ImageIOType::New();
    reader->SetImageIO(dicomIO);
    NamesGeneratorType::Pointer nameGenerator = NamesGeneratorType::New();
    nameGenerator->SetUseSeriesDetails(true);
    nameGenerator->SetDirectory(extension.toLocal8Bit().data());
    using SeriesIdContainer = std::vector< std::string >;
    const SeriesIdContainer &seriesUID = nameGenerator->GetSeriesUIDs();
    auto seriesItr = seriesUID.begin();
    auto seriesEnd = seriesUID.end();
    using FileNamesContainer = std::vector< std::string >;
    FileNamesContainer fileNames ;
    std::string seriesIdentifier;
    while (seriesItr != seriesEnd) {
        seriesIdentifier = seriesItr->c_str();
        fileNames = nameGenerator->GetFileNames(seriesIdentifier);
        ++seriesItr;
    }
    reader->SetFileNames(fileNames);
    try {
        reader->Update();
    } catch (itk::ExceptionObject &ex) {
        std::cout << ex << std::endl;
        return false;
    }
    ImageType::Pointer input_image;
    input_image = ImageType::New();
    input_image = reader->GetOutput();
    typedef itk::ImageToVTKImageFilter< ImageType> itkTovtkFilterType;
    itkTovtkFilterType::Pointer itkTovtkImageFilter = itkTovtkFilterType::New();
    itkTovtkImageFilter->SetInput(input_image);
    itkTovtkImageFilter->Update();
    imagedata->DeepCopy(itkTovtkImageFilter->GetOutput());
    return true;
}

bool WritePng(const vtkSmartPointer<vtkImageData> &imagedata,
              const QString &output_file) {
    qint32 dims[3];
    imagedata->GetDimensions(dims);
    for(qint32 i = 0; i < dims[2]; i++) {
        cv::Mat vtk_to_cvimg(dims[0], dims[1], CV_32FC1,
                             imagedata->GetScalarPointer(0, 0, i));
        cv::imwrite((output_file + QString("%1.png").arg(
                         i, 4, 10, QLatin1Char('0')))
                    .toLocal8Bit().data(), vtk_to_cvimg);
    }
    return true;
}

int main(int, char *[]) {
    vtkSmartPointer<vtkImageData> imagedata =
        vtkSmartPointer<vtkImageData>::New();
    ReadDcm("/home/yx/Documents/arteryflow/qt/DcmsToPngs/build-DcmsToPngs-Desktop_Qt_5_11_3_GCC_64bit-Release/dcm/0.dcm", imagedata);
    WritePng(imagedata, "/home/yx/Documents/arteryflow/qt/DcmsToPngs/build-DcmsToPngs-Desktop_Qt_5_11_3_GCC_64bit-Release/tmp/");
    return 0;
}

如果不用opencv处理的话(这里用extent因为数据我切割过,不是从0,0,0开始的)

void ExportVtiToPngs(
    const vtkSmartPointer<vtkImageData> &imagedata,
    const QString &output_file) {
    int extent[6];
    imagedata->GetExtent(extent);
    vtkNew<vtkImageCast>cast;
    cast->SetInputData(imagedata);
    cast->SetOutputScalarTypeToUnsignedChar();
    cast->Update();
    vtkNew<vtkExtractVOI>  extract_voi;
    vtkNew<vtkPNGWriter> writer;
    extract_voi->SetInputData(cast->GetOutput());
    for(qint32 i = extent[4]; i < extent[5]; i++) {
        extract_voi->SetVOI(extent[0], extent[1],
                            extent[2], extent[3],
                            i, i);
        extract_voi->Update();
        writer->SetFileName(QString(output_file + "/%1.png")
                            .arg(i, 4, 10, QLatin1Char('0'))
                            .toLocal8Bit().data());
        writer->SetInputData(extract_voi->GetOutput());
        writer->Write();
    }
}