Exemple #1
0
CPLErr VRTKernelFilteredSource::XMLInit( CPLXMLNode *psTree,
                                         const char *pszVRTPath,
                                         void* pUniqueHandle,
                                         std::map<CPLString, GDALDataset*>& oMapSharedSources )

{
    {
        const CPLErr eErr = VRTFilteredSource::XMLInit( psTree, pszVRTPath,
                                                        pUniqueHandle,
                                                        oMapSharedSources );
        if( eErr != CE_None )
            return eErr;
    }

    const int nNewKernelSize = atoi(CPLGetXMLValue(psTree,"Kernel.Size","0"));

    if( nNewKernelSize == 0 )
        return CE_None;

    char **papszCoefItems =
        CSLTokenizeString( CPLGetXMLValue(psTree,"Kernel.Coefs","") );

    const int nCoefs = CSLCount(papszCoefItems);

    const bool bSquare = nCoefs == nNewKernelSize * nNewKernelSize;
    const bool bSeparable = nCoefs == nNewKernelSize && nCoefs != 1;

    if( !bSquare && !bSeparable )
    {
        CSLDestroy( papszCoefItems );
        CPLError( CE_Failure, CPLE_AppDefined,
                  "Got wrong number of filter kernel coefficients (%s).  "
                  "Expected %d or %d, got %d.",
                  CPLGetXMLValue(psTree,"Kernel.Coefs",""),
                  nNewKernelSize * nNewKernelSize, nNewKernelSize, nCoefs );
        return CE_Failure;
    }

    double *padfNewCoefs = static_cast<double *>(
        CPLMalloc( sizeof(double) * nCoefs ) );

    for( int i = 0; i < nCoefs; i++ )
        padfNewCoefs[i] = CPLAtof(papszCoefItems[i]);

    const CPLErr eErr = SetKernel( nNewKernelSize, bSeparable, padfNewCoefs );

    CPLFree( padfNewCoefs );
    CSLDestroy( papszCoefItems );

    SetNormalized( atoi(CPLGetXMLValue(psTree,"Kernel.normalized","0")) );

    return eErr;
}
Exemple #2
0
CPLErr VRTKernelFilteredSource::XMLInit( CPLXMLNode *psTree, 
                                         const char *pszVRTPath )

{
    CPLErr eErr = VRTFilteredSource::XMLInit( psTree, pszVRTPath );
    int    nNewKernelSize, i, nCoefs;
    double *padfNewCoefs;

    if( eErr != CE_None )
        return eErr;

    nNewKernelSize = atoi(CPLGetXMLValue(psTree,"Kernel.Size","0"));

    if( nNewKernelSize == 0 )
        return CE_None;

    char **papszCoefItems = 
        CSLTokenizeString( CPLGetXMLValue(psTree,"Kernel.Coefs","") );

    nCoefs = CSLCount(papszCoefItems);

    if( nCoefs != nNewKernelSize * nNewKernelSize )
    {
        CSLDestroy( papszCoefItems );
        CPLError( CE_Failure, CPLE_AppDefined, 
                  "Got wrong number of filter kernel coefficients (%s).\n"
                  "Expected %d, got %d.", 
                  CPLGetXMLValue(psTree,"Kernel.Coefs",""),
                  nNewKernelSize * nNewKernelSize, nCoefs );
        return CE_Failure;
    }

    padfNewCoefs = (double *) CPLMalloc(sizeof(double) * nCoefs);

    for( i = 0; i < nCoefs; i++ )
        padfNewCoefs[i] = CPLAtof(papszCoefItems[i]);

    eErr = SetKernel( nNewKernelSize, padfNewCoefs );

    CPLFree( padfNewCoefs );
    CSLDestroy( papszCoefItems );

    SetNormalized( atoi(CPLGetXMLValue(psTree,"Kernel.normalized","0")) );

    return eErr;
}
Exemple #3
0
int main(int argc, char **argv) {
    args::ArgumentParser parser("Generates masks in stages.\n"
                                "Stage 1 - Otsu thresholding to generate binary mask\n"
                                "Stage 2 - RATs (optional)\n"
                                "Stage 3 - Hole filling (optional)\n"
                                "http://github.com/spinicist/QUIT");

    args::Positional<std::string> input_path(parser, "INPUT_FILE", "Input file");

    args::HelpFlag help(parser, "HELP", "Show this help menu", {'h', "help"});
    args::Flag     verbose(parser, "VERBOSE", "Print more information", {'v', "verbose"});
    args::ValueFlag<std::string> outarg(
        parser, "OUTPUT FILE", "Set output filename, default is input + _mask", {'o', "out"});
    args::ValueFlag<int> volume(
        parser, "VOLUME",
        "Choose volume to mask in multi-volume file. Default 1, -1 selects last volume",
        {'v', "volume"}, 0);
    args::Flag is_complex(parser, "COMPLEX", "Input data is complex, take magnitude first",
                          {'x', "complex"});
    args::ValueFlag<float> lower_threshold(
        parser, "LOWER THRESHOLD",
        "Specify lower intensity threshold for 1st stage, otherwise Otsu's method is used",
        {'l', "lower"}, 0.);
    args::ValueFlag<float> upper_threshold(
        parser, "UPPER THRESHOLD",
        "Specify upper intensity threshold for 1st stage, otherwise Otsu's method is used",
        {'u', "upper"}, std::numeric_limits<float>::infinity());
    args::ValueFlag<float> rats(
        parser, "RATS", "Perform the RATS step, argument is size threshold for connected component",
        {'r', "rats"}, 0.);
    args::ValueFlag<int> fillh_radius(
        parser, "FILL HOLES", "Fill holes in thresholded mask with radius N", {'F', "fillh"}, 0);

    QI::ParseArgs(parser, argc, argv, verbose);

    QI::SeriesF::Pointer vols = ITK_NULLPTR;
    if (is_complex) {
        vols = QI::ReadMagnitudeImage<QI::SeriesF>(QI::CheckPos(input_path), verbose);
    } else {
        vols = QI::ReadImage<QI::SeriesF>(QI::CheckPos(input_path), verbose);
    }

    std::string out_path;
    if (outarg.Get() == "") {
        out_path = QI::StripExt(input_path.Get()) + "_mask" + QI::OutExt();
    } else {
        out_path = outarg.Get();
    }

    // Extract one volume to process
    auto region = vols->GetLargestPossibleRegion();
    if (static_cast<size_t>(std::abs(volume.Get())) < region.GetSize()[3]) {
        int volume_to_get = (region.GetSize()[3] + volume.Get()) % region.GetSize()[3];
        QI::Log(verbose, "Masking volume {}...", volume_to_get);
        region.GetModifiableIndex()[3] = volume_to_get;
    } else {
        QI::Fail("Specified mask volume was invalid {} ", volume.Get());
    }
    region.GetModifiableSize()[3] = 0;
    auto vol                      = itk::ExtractImageFilter<QI::SeriesF, QI::VolumeF>::New();
    vol->SetExtractionRegion(region);
    vol->SetInput(vols);
    vol->SetDirectionCollapseToSubmatrix();
    vol->Update();
    QI::VolumeF::Pointer intensity_image = vol->GetOutput();
    intensity_image->DisconnectPipeline();

    /*
     *  Stage 1 - Otsu or Threshold
     */
    QI::VolumeI::Pointer mask_image = ITK_NULLPTR;
    if (lower_threshold || upper_threshold) {
        QI::Log(verbose, "Thresholding range: {}-{}", lower_threshold.Get(), upper_threshold.Get());
        mask_image =
            QI::ThresholdMask(intensity_image, lower_threshold.Get(), upper_threshold.Get());
    } else {
        QI::Log(verbose, "Generating Otsu mask");
        mask_image = QI::OtsuMask(intensity_image);
    }

    /*
     *  Stage 2 - RATS
     */
    if (rats) {
        typedef itk::BinaryBallStructuringElement<int, 3>                     TBall;
        typedef itk::BinaryErodeImageFilter<QI::VolumeI, QI::VolumeI, TBall>  TErode;
        typedef itk::BinaryDilateImageFilter<QI::VolumeI, QI::VolumeI, TBall> TDilate;
        float mask_volume  = std::numeric_limits<float>::infinity();
        float voxel_volume = QI::VoxelVolume(mask_image);
        QI::Log(verbose, "Voxel volume: {}", voxel_volume);
        int                  radius = 0;
        QI::VolumeI::Pointer mask_rats;
        while (mask_volume > rats.Get()) {
            radius++;
            TBall           ball;
            TBall::SizeType radii;
            radii.Fill(radius);
            ball.SetRadius(radii);
            ball.CreateStructuringElement();
            TErode::Pointer erode = TErode::New();
            erode->SetInput(mask_image);
            erode->SetForegroundValue(1);
            erode->SetBackgroundValue(0);
            erode->SetKernel(ball);
            erode->Update();
            std::vector<float> kept_sizes = QI::FindLabels(erode->GetOutput(), 0, 1, mask_rats);
            mask_volume                   = kept_sizes[0] * voxel_volume;
            auto dilate                   = TDilate::New();
            dilate->SetKernel(ball);
            dilate->SetInput(mask_rats);
            dilate->SetForegroundValue(1);
            dilate->SetBackgroundValue(0);
            dilate->Update();
            mask_rats = dilate->GetOutput();
            mask_rats->DisconnectPipeline();
            QI::Log(verbose, "Ran RATS iteration, radius = {} volume = {}", radius, mask_volume);
        }
        mask_image = mask_rats;
    }

    /*
     *  Stage 3 - Hole Filling
     */
    QI::VolumeI::Pointer finalMask = ITK_NULLPTR;
    if (fillh_radius) {
        QI::Log(verbose, "Filling holes");
        auto fillHoles = itk::VotingBinaryIterativeHoleFillingImageFilter<QI::VolumeI>::New();
        itk::VotingBinaryIterativeHoleFillingImageFilter<QI::VolumeI>::InputSizeType radius;
        radius.Fill(fillh_radius.Get());
        fillHoles->SetInput(mask_image);
        fillHoles->SetRadius(radius);
        fillHoles->SetMajorityThreshold(2); // Corresponds to (rad^3-1)/2 + 2 threshold
        fillHoles->SetBackgroundValue(0);
        fillHoles->SetForegroundValue(1);
        fillHoles->SetMaximumNumberOfIterations(3);
        fillHoles->Update();
        mask_image = fillHoles->GetOutput();
        mask_image->DisconnectPipeline();
    }

    QI::WriteImage(mask_image, out_path, verbose);
    QI::Log(verbose, "Finished.");
    return EXIT_SUCCESS;
}