https://doi.org/10.5201/ipol.2012.g-tvdc
Raw File
Tip revision: 13cac45f201f2e0e4a336450abb835be0ddd9359 authored by Software Heritage on 12 June 2012, 00:00:00 UTC
ipol: Deposit 1194 in collection ipol
Tip revision: 13cac45
tvdeconv.c
/**
 * @file tvdeconv.c
 * @brief Total variation regularized deconvolution IPOL demo
 * @author Pascal Getreuer <getreuer@gmail.com>
 * 
 * 
 * Copyright (c) 2010-2012, Pascal Getreuer
 * All rights reserved.
 * 
 * This program is free software: you can use, modify and/or
 * redistribute it under the terms of the simplified BSD License. You
 * should have received a copy of this license along with this program. 
 * If not, see <http://www.opensource.org/licenses/bsd-license.html>.
 */

/**
 * @mainpage
 * @verbinclude readme.txt
 */

#include <math.h>
#include <stdio.h>
#include <string.h>
#include "tvreg.h"
#include "cliio.h"
#include "kernels.h"


/** @brief Program parameters struct */
typedef struct
{
    /** @brief Input file name */
    const char *InputFile;
    /** @brief Output file name */
    const char *OutputFile;
    /** @brief Quality for saving JPEG images (0 to 100) */
    int JpegQuality;
    
    /** @brief Noise standard deviation */
    num Lambda;
    /** @brief Blur kernel */
    image Kernel;
    /** @brief Noise model */
    const char *Noise;
} programparams;


/** @brief Print program information and usage message */
static void PrintHelpMessage()
{    
    puts("Total variation deconvolution demo, P. Getreuer 2011-2012\n\n"
    "Usage: tvdeconv [param:value ...] input output\n\n"
    "where \"input\" and \"output\" are " 
    READIMAGE_FORMATS_SUPPORTED " files.\n");
    puts("Parameters");
    puts("  K:<kernel>             blur kernel for deconvolution");
    puts("      K:disk:<radius>         filled disk kernel");
    puts("      K:gaussian:<sigma>      Gaussian kernel");
    puts("      K:<file>                read kernel from text or image file");
    puts("  lambda:<value>         fidelity weight");
    puts("  noise:<model>          noisy model");
    puts("      noise:gaussian          additive Gaussian noise (default)");
    puts("      noise:laplace           Laplace noise");
    puts("      noise:poisson           Poisson noise");
    puts("  f:<file>               input file (alternative syntax)");
    puts("  u:<file>               output file (alternative syntax)");
#ifdef USE_LIBJPEG
    puts("  jpegquality:<number>   quality for saving JPEG images (0 to 100)");
#endif
    puts("\nExample: \n"
    "   imblur noise:gaussian:5 K:disk:2 input.bmp blurry.bmp\n");
}

int TvDeconv(image u, image f, image Kernel, num Lambda, const char *Noise);
int ParseParams(programparams *Params, int argc, const char *argv[]);

int main(int argc, char **argv)
{
    programparams Params;
    image f = NullImage, u = NullImage;
    int Status = 1;
    
    if(!ParseParams(&Params, argc, (const char **)argv))
        goto Catch;    
    
    /* Read the input image */
    if(!ReadImageObj(&f, Params.InputFile))
        goto Catch;
    else if(!AllocImageObj(&u, f.Width, f.Height, f.NumChannels))
    {
        fputs("Out of memory.\n", stderr);
        goto Catch;
    }
    
    if(!TvDeconv(u, f, Params.Kernel, Params.Lambda, Params.Noise))
        goto Catch;
    
    /* Write the deconvolved image */
    if(!WriteImageObj(u, Params.OutputFile, Params.JpegQuality))    
        fprintf(stderr, "Error writing to \"%s\".\n", Params.OutputFile);
    
    Status = 0;
Catch:
    FreeImageObj(u);
    FreeImageObj(f); 
    FreeImageObj(Params.Kernel);
    return Status;
}


int TvDeconv(image u, image f, image Kernel, num Lambda, const char *Noise)
{
    tvregopt *Opt = NULL;
    int Success;
    
    if(!(Opt = TvRegNewOpt()))
    {
        fputs("Out of memory.\n", stderr);
        return 0;
    }
    else if(!(TvRegSetNoiseModel(Opt, Noise)))
    {
        fprintf(stderr, "Unknown noise model, \"%s\".\n", Noise);
        TvRegFreeOpt(Opt);
        return 0;
    }
    
    memcpy(u.Data, f.Data, sizeof(num)*((size_t)f.Width)
        *((size_t)f.Height)*f.NumChannels);
    TvRegSetKernel(Opt, Kernel.Data, Kernel.Width, Kernel.Height);
    TvRegSetLambda(Opt, Lambda);
    TvRegSetMaxIter(Opt, 140);
    
    if(!(Success = TvRestore(u.Data, f.Data, 
        f.Width, f.Height, f.NumChannels, Opt)))
        fputs("Error in computation.\n", stderr);
    
    TvRegFreeOpt(Opt);
    return Success;
}


/** @brief Parse command line arguments */
int ParseParams(programparams *Params, int argc, const char *argv[])
{
    static const char *DefaultOutputFile = (char *)"out.bmp";
    const char *Param, *Value;
    num NumValue;
    char TokenBuf[256];
    int k, kread, Skip;
    
        
    /* Set parameter defaults */
    Params->InputFile = NULL;
    Params->OutputFile = DefaultOutputFile;
    Params->JpegQuality = 85;
    
    Params->Lambda = 20;    
    Params->Kernel = NullImage;
    Params->Noise = "gaussian";
        
    if(argc < 2)
    {
        PrintHelpMessage();
        return 0;
    }    
    
    k = 1;
    
    while(k < argc)
    {
        Skip = (argv[k][0] == '-') ? 1 : 0;        
        kread = CliParseArglist(&Param, &Value, TokenBuf, sizeof(TokenBuf),
            k, &argv[k][Skip], argc, argv, ":");        
       
        if(!Param)
        {
            if(!Params->InputFile)
                Param = (char *)"f";
            else
                Param = (char *)"u";
        }
        
        if(Param[0] == '-')     /* Argument begins with two dashes "--" */
        {
            PrintHelpMessage();
            return 0;
        }

        if(!strcmp(Param, "f") || !strcmp(Param, "input"))
        {
            if(!Value)
            {
                fprintf(stderr, "Expected a value for option %s.\n", Param);
                return 0;
            }
            Params->InputFile = Value;
        }
        else if(!strcmp(Param, "u") || !strcmp(Param, "output"))
        {
            if(!Value)
            {
                fprintf(stderr, "Expected a value for option %s.\n", Param);
                return 0;
            }
            Params->OutputFile = Value;
        }
        else if(!strcmp(Param, "K"))
        {
            if(!Value)
            {
                fprintf(stderr, "Expected a value for option %s.\n", Param);
                return 0;
            }
            else if(!ReadKernel(&Params->Kernel, Value))
                return 0;
        }
        else if(!strcmp(Param, "lambda"))
        {
            if(!CliGetNum(&NumValue, Value, Param))
                return 0;
            else if(NumValue <= 0)
            {
                fputs("Parameter lambda must be positive.\n", stderr);
                return 0;
            } 
            else
                Params->Lambda = (int)NumValue;
        }
        else if(!strcmp(Param, "noise"))
        {
            if(!Value)
            {
                fprintf(stderr, "Expected a value for option %s.\n", Param);
                return 0;
            }
            else
                Params->Noise = Value;
        }
        else if(!strcmp(Param, "jpegquality"))
        {
            if(!CliGetNum(&NumValue, Value, Param))
                return 0;
            else if(NumValue < 0 || 100 < NumValue)
            {
                fputs("JPEG quality must be between 0 and 100.\n", stderr);
                return 0;
            } 
            else
                Params->JpegQuality = (int)NumValue;
        }
        else if(Skip)
        {
            fprintf(stderr, "Unknown option \"%s\".\n", Param);
            return 0;
        }
        else
        {
            if(!Params->InputFile)
                Params->InputFile = argv[k];
            else
                Params->OutputFile = argv[k];
            
            kread = k;
        }
        
        k = kread + 1;
    }
    
    if(!Params->Kernel.Data && !ReadKernel(&Params->Kernel, "disk:0"))
        return 0;
    
    if(!Params->InputFile)
    {
        PrintHelpMessage();
        return 0;
    }

    return 1;
}
back to top