Пример #1
0
int main(int argc, char* argv[])
{
	if (argc != 2)
	{
		std::cerr << "usage: " << argv[0] << " <url>\n";
		return -1;
	}
	try {
		boost::asio::io_service io;
		avhttp::multi_download d(io);

		avhttp::settings s;
		// s.m_download_rate_limit = 102400;

		d.start(argv[1], s);

		if (d.file_size() != -1)
			std::cout << "file \'" << d.file_name().c_str() <<
			"\' size is: " << "(" << d.file_size() << " bytes) " << add_suffix(d.file_size()).c_str() << std::endl;

		boost::thread t(boost::bind(&boost::asio::io_service::run, &io));

		if (d.file_size() != -1)
		{
			printf("\n");
			int percent = 0;
			boost::int64_t file_size = d.file_size();
			boost::int64_t bytes_download = 0;
			while (percent != 100)
			{
				bytes_download = d.bytes_download();
				percent = ((double)bytes_download / (double)file_size) * 100.0f;
				boost::this_thread::sleep(boost::posix_time::millisec(200));
				printf("\r");
				printf("%3d%% [", percent);
				int progress = percent / 2;
				for (int i = 0; i < progress; i++)
					printf("=");
				if (progress != 50)
					printf(">");
				for (int i = 0; i < 49 - progress; i++)
					printf(" ");
				printf("]  %s  %s/s", add_suffix(bytes_download).c_str(), add_suffix(d.download_rate()).c_str());
			}
			printf("\n");
		}

		t.join();

		std::cout << "\n*** download completed! ***\n";
	}
	catch (std::exception &e)
	{
		std::cerr << e.what() << std::endl;
		return -1;
	}

	return 0;
}
Пример #2
0
void    update_status(int state, int identifier)
{
    static const char * const enabled = " [On]";
    static const char * const disabled = " [Off]";

    if (state)
        add_suffix((char *)enabled, identifier);
    else
        add_suffix((char *)disabled, identifier);
}
static void server_browse_entry_expand(GqBrowserNode *e,
				       int error_context,
				       GQTreeWidget *ctree, GQTreeWidgetNode *node,
				       GqTab *tab)
{
     GList *suffixes = NULL, *next;
     GqBrowserNodeServer *entry;

     g_assert(GQ_IS_BROWSER_NODE_SERVER(e));
     entry = GQ_BROWSER_NODE_SERVER(e);

     if (!entry->once_expanded) {
/*	  printf("expanding %s\n", entry->server->name); */

	  gq_tree_remove_children (ctree, node);
	  entry->once_expanded = 1;

	  suffixes = get_suffixes(error_context, entry->server);

	  gtk_clist_freeze(GTK_CLIST(ctree));

	  for (next = suffixes ; next ; next = g_list_next(next) ) {
	       add_suffix(entry, ctree, node, next->data);
	       g_free(next->data);
	       next->data = NULL;
	  }

	  gtk_clist_thaw(GTK_CLIST(ctree));

	  g_list_free(suffixes);
     }
}
Пример #4
0
static void add_input(MarkovData* data, int (*get_word)(char* /*target buffer*/, char* /*format*/, void* /*data*/), void* input_data){
    check_data_initialised(data);
    
    const int buf_size = 100;  //TODO: handle possibility of words > 100 chars in length
    char buf[buf_size];
    
    char fmt[10];
    sprintf(fmt, "%%%ds", buf_size -1);
    
    const char* prefix[data->prefix_len];
    prepopulate_prefix(data, prefix);
    
    while (get_word(buf, fmt, input_data) != EOF) {
        char* const word = strdup(buf); //TODO: check for errors on strdup
        add_suffix(data, prefix, word);
        rotate_prefix(data, prefix, word);
    }
    add_suffix(data, prefix, strdup(data->sentinel_word));
}
Пример #5
0
void markov_add_input_from_string(MarkovData* data, char* string) {
    printf("Adding from string");
    check_data_initialised(data);
    
    const int buf_size = 100;  //TODO: handle possibility of words > 100 chars in length
    char buf[buf_size];

    char fmt[10];
    sprintf(fmt, "%%%ds", buf_size -1);
    
    const char* prefix[data->prefix_len];
    prepopulate_prefix(data, prefix);
    
    while (sscanf(string, fmt, buf) != EOF) {
        char* const word = strdup(buf); //TODO: check for errors on strdup
        add_suffix(data, prefix, word);
        rotate_prefix(data, prefix, word);
        string += strlen(word) +1;
    }
    
    add_suffix(data, prefix, strdup(data->sentinel_word));
}
Пример #6
0
//-----------------------------------------------------------------------------
JNIEXPORT jstring JNICALL Java_com_softwarrior_libtorrent_LibTorrent_GetSessionStatusText
	(JNIEnv *env, jobject obj)
{
	jstring result = NULL;
	try {
		if(gSessionState){
			std::string out;
			char str[500]; memset(str,0,500);
			libtorrent::session_status s_s = gSession.status();
			snprintf(str, sizeof(str),
					  "%25s%20d\n"
					  "%22s%20s/%s\n"
					  "%25s%20s/%s\n"
					  "%18s%20s/%s\n"
					  "%15s%20s/%s\n"
					  "%19s%20s/%s\n"
				,"conns:"
				, s_s.num_peers
				, "down/rate:"
				, add_suffix(s_s.total_download).c_str(), add_suffix(s_s.download_rate, "/s").c_str()
				, "up/rate:"
				, add_suffix(s_s.total_upload).c_str(), add_suffix(s_s.upload_rate, "/s").c_str()
				, "ip rate down/up:"
				, add_suffix(s_s.ip_overhead_download_rate, "/s").c_str(), add_suffix(s_s.ip_overhead_upload_rate, "/s").c_str()
				, "dht rate down/up:"
				, add_suffix(s_s.dht_download_rate, "/s").c_str(), add_suffix(s_s.dht_upload_rate, "/s").c_str()
				, "tr rate down/up:"
				, add_suffix(s_s.tracker_download_rate, "/s").c_str(), add_suffix(s_s.tracker_upload_rate, "/s").c_str());
			out += str;
			result = env->NewStringUTF(out.c_str());
		}
	} catch(...){
		LOG_ERR("Exception: failed to get session status");
	}
	return result;
}
Пример #7
0
void torrent_view::print_torrent(lt::torrent_status const& s, bool selected)
{
	int pos = 0;
	char str[512];

	// the active torrent is highligted in the list
	// this inverses the forground and background colors
	char const* selection = "";
	if (selected)
		selection = "\x1b[1m\x1b[44m";

	char queue_pos[16] = {0};
	if (s.queue_position == -1)
		snprintf(queue_pos, sizeof(queue_pos), "-");
	else
		snprintf(queue_pos, sizeof(queue_pos), "%d", s.queue_position);

	std::string name = s.name;
	if (name.size() > 50) name.resize(50);

	color_code progress_bar_color = col_yellow;
	if (!s.error.empty()) progress_bar_color = col_red;
	else if (s.paused) progress_bar_color = col_blue;
	else if (s.state == lt::torrent_status::downloading_metadata)
		progress_bar_color = col_magenta;
	else if (s.current_tracker.empty())
		progress_bar_color = col_green;

	pos += snprintf(str + pos, sizeof(str) - pos, "%s%c%-3s %-50s %s%s %s (%s) "
		"%s (%s) %5d:%-5d %s %s %c%s"
		, selection
		, s.is_loaded ? 'L' : ' '
		, queue_pos
		, name.c_str()
		, progress_bar(s.progress_ppm / 1000, 35, progress_bar_color, '-', '#', torrent_state(s)).c_str()
		, selection
		, color(add_suffix(s.download_rate, "/s"), col_green).c_str()
		, color(add_suffix(s.total_download), col_green).c_str()
		, color(add_suffix(s.upload_rate, "/s"), col_red).c_str()
		, color(add_suffix(s.total_upload), col_red).c_str()
		, s.num_peers - s.num_seeds, s.num_seeds
		, color(add_suffix(s.all_time_download), col_green).c_str()
		, color(add_suffix(s.all_time_upload), col_red).c_str()
		, s.need_save_resume?'S':' ', esc("0"));

	// if this is the selected torrent, restore the background color
	if (selected)
		pos += snprintf(str + pos, sizeof(str) - pos, "%s", esc("0"));

	pos += snprintf(str + pos, sizeof(str) - pos, "\x1b[K");

	if (m_width + 1 < sizeof(str))
		str[m_width + 1] = '\0';

	print(str);
}
Пример #8
0
void init_save()
{
    init_out(xyz_filename, &xyz_file, "w" );
    init_out(dcd_filename, &dcd_file, "wb" );
    if( dcd_file )
    {
        dcd_tab = (float*) malloc( sizeof(float) * size * DIMS0 ); CHMEM(dcd_tab);
        init_dcd( bdsteps / save_dcd_freq );
    }
    init_out(enr_filename, &enr_file, "w" );
    if( enr_file ) init_enr();
    init_out( pqr_filename, &pqr_file, "w" );/*pqr is closed after save*/
    if( pqr_filename )
    {
        char* buff = add_suffix( pqr_filename, PQR_SUFFIX);
        init_out( buff, &pqr_file_hi, "w" );
        free(buff);
    }
}
Пример #9
0
//-----------------------------------------------------------------------------
JNIEXPORT jstring JNICALL Java_com_softwarrior_libtorrent_LibTorrent_GetTorrentStatusText
	(JNIEnv *env, jobject obj, jstring ContentFile)
{
	jstring result = NULL;
	try {
		if(gSessionState){
			libtorrent::torrent_handle* pTorrent = GetTorrentHandle(env,ContentFile);
			if(pTorrent){
				std::string out;
				char str[500]; memset(str,0,500);

				libtorrent::torrent_status t_s = pTorrent->status();

				//------- ERROR --------
				if (!t_s.error.empty())
				{
					out += "error ";
					out += t_s.error;
					out += "\n";
					return env->NewStringUTF(out.c_str());
				}

				if (t_s.state != libtorrent::torrent_status::queued_for_checking && t_s.state != libtorrent::torrent_status::checking_files){
					snprintf(str, sizeof(str),
						  "%22s%20d/%d\n"
						  "%26s%20s\n"
						, "peers/cand:"
						, t_s.num_peers, t_s.connect_candidates
						, "speed:"
						, add_suffix(t_s.download_payload_rate, "/s").c_str());
					out += str;
				}
				result = env->NewStringUTF(out.c_str());
			}
		}
	} catch(...){
		LOG_ERR("Exception: failed to get torrent status text");
	}
	return result;
}
Пример #10
0
int main(int argc, char *argv[])
{
    int i;
    int ret = 0;
    int c;
    int verify = 0;
    int hashsize = 0;
    int nolock = 0;
    const char *suffix = ".bak";

    log_ctx.log_fn = tdb_log;

    while ((c = getopt(argc, argv, "vhs:n:l")) != -1) {
        switch (c) {
        case 'h':
            usage();
            exit(0);
        case 'v':
            verify = 1;
            break;
        case 's':
            suffix = optarg;
            break;
        case 'n':
            hashsize = atoi(optarg);
            break;
        case 'l':
            nolock = 1;
            break;
        }
    }

    argc -= optind;
    argv += optind;

    if (argc < 1) {
        usage();
        exit(1);
    }

    for (i=0; i<argc; i++) {
        const char *fname = argv[i];
        char *bak_name;

        bak_name = add_suffix(fname, suffix);

        if (verify) {
            if (verify_tdb(fname, bak_name) != 0) {
                ret = 1;
            }
        } else {
            if (file_newer(fname, bak_name) &&
                    backup_tdb(fname, bak_name, hashsize,
                               nolock) != 0) {
                ret = 1;
            }
        }

        free(bak_name);
    }

    return ret;
}
Пример #11
0
/*
  carefully backup a tdb, validating the contents and
  only doing the backup if its OK
  this function is also used for restore
*/
static int backup_tdb(const char *old_name, const char *new_name,
                      int hash_size, int nolock)
{
    TDB_CONTEXT *tdb;
    TDB_CONTEXT *tdb_new;
    char *tmp_name;
    struct stat st;
    int count1, count2;

    tmp_name = add_suffix(new_name, ".tmp");

    /* stat the old tdb to find its permissions */
    if (stat(old_name, &st) != 0) {
        perror(old_name);
        free(tmp_name);
        return 1;
    }

    /* open the old tdb */
    tdb = tdb_open_ex(old_name, 0,
                      TDB_DEFAULT | (nolock ? TDB_NOLOCK : 0),
                      O_RDWR, 0, &log_ctx, NULL);
    if (!tdb) {
        printf("Failed to open %s\n", old_name);
        free(tmp_name);
        return 1;
    }

    /* create the new tdb */
    unlink(tmp_name);
    tdb_new = tdb_open_ex(tmp_name,
                          hash_size ? hash_size : tdb_hash_size(tdb),
                          TDB_DEFAULT,
                          O_RDWR|O_CREAT|O_EXCL, st.st_mode & 0777,
                          &log_ctx, NULL);
    if (!tdb_new) {
        perror(tmp_name);
        free(tmp_name);
        return 1;
    }

    if (tdb_transaction_start(tdb) != 0) {
        printf("Failed to start transaction on old tdb\n");
        tdb_close(tdb);
        tdb_close(tdb_new);
        unlink(tmp_name);
        free(tmp_name);
        return 1;
    }

    /* lock the backup tdb so that nobody else can change it */
    if (tdb_lockall(tdb_new) != 0) {
        printf("Failed to lock backup tdb\n");
        tdb_close(tdb);
        tdb_close(tdb_new);
        unlink(tmp_name);
        free(tmp_name);
        return 1;
    }

    failed = 0;

    /* traverse and copy */
    count1 = tdb_traverse(tdb, copy_fn, (void *)tdb_new);
    if (count1 < 0 || failed) {
        fprintf(stderr,"failed to copy %s\n", old_name);
        tdb_close(tdb);
        tdb_close(tdb_new);
        unlink(tmp_name);
        free(tmp_name);
        return 1;
    }

    /* close the old tdb */
    tdb_close(tdb);

    /* copy done, unlock the backup tdb */
    tdb_unlockall(tdb_new);

#ifdef HAVE_FDATASYNC
    if (fdatasync(tdb_fd(tdb_new)) != 0) {
#else
    if (fsync(tdb_fd(tdb_new)) != 0) {
#endif
        /* not fatal */
        fprintf(stderr, "failed to fsync backup file\n");
    }

    /* close the new tdb and re-open read-only */
    tdb_close(tdb_new);
    tdb_new = tdb_open_ex(tmp_name,
                          0,
                          TDB_DEFAULT,
                          O_RDONLY, 0,
                          &log_ctx, NULL);
    if (!tdb_new) {
        fprintf(stderr,"failed to reopen %s\n", tmp_name);
        unlink(tmp_name);
        perror(tmp_name);
        free(tmp_name);
        return 1;
    }

    /* traverse the new tdb to confirm */
    count2 = tdb_traverse(tdb_new, test_fn, NULL);
    if (count2 != count1) {
        fprintf(stderr,"failed to copy %s\n", old_name);
        tdb_close(tdb_new);
        unlink(tmp_name);
        free(tmp_name);
        return 1;
    }

    /* close the new tdb and rename it to .bak */
    tdb_close(tdb_new);
    if (rename(tmp_name, new_name) != 0) {
        perror(new_name);
        free(tmp_name);
        return 1;
    }

    free(tmp_name);

    return 0;
}

/*
  verify a tdb and if it is corrupt then restore from *.bak
*/
static int verify_tdb(const char *fname, const char *bak_name)
{
    TDB_CONTEXT *tdb;
    int count = -1;

    /* open the tdb */
    tdb = tdb_open_ex(fname, 0, 0,
                      O_RDONLY, 0, &log_ctx, NULL);

    /* traverse the tdb, then close it */
    if (tdb) {
        count = tdb_traverse(tdb, test_fn, NULL);
        tdb_close(tdb);
    }

    /* count is < 0 means an error */
    if (count < 0) {
        printf("restoring %s\n", fname);
        return backup_tdb(bak_name, fname, 0, 0);
    }

    printf("%s : %d records\n", fname, count);

    return 0;
}
Пример #12
0
/*
  carefully backup a tdb, validating the contents and
  only doing the backup if its OK
  this function is also used for restore
*/
int backup_tdb(const char *old_name, const char *new_name, int hash_size)
{
	TDB_CONTEXT *tdb;
	TDB_CONTEXT *tdb_new;
	char *tmp_name;
	struct stat st;
	int count1, count2;

	tmp_name = add_suffix(new_name, ".tmp");

	/* stat the old tdb to find its permissions */
	if (stat(old_name, &st) != 0) {
		perror(old_name);
		free(tmp_name);
		return 1;
	}

	/* open the old tdb */
	tdb = tdb_open(old_name, 0, 0, O_RDWR, 0);
	if (!tdb) {
		printf("Failed to open %s\n", old_name);
		free(tmp_name);
		return 1;
	}

	/* create the new tdb */
	unlink(tmp_name);
	tdb_new = tdb_open(tmp_name,
			   hash_size ? hash_size : tdb_hash_size(tdb),
			   TDB_DEFAULT, O_RDWR|O_CREAT|O_EXCL, 
			   st.st_mode & 0777);
	if (!tdb_new) {
		perror(tmp_name);
		free(tmp_name);
		return 1;
	}

	/* lock the old tdb */
	if (tdb_lockall(tdb) != 0) {
		fprintf(stderr,"Failed to lock %s\n", old_name);
		tdb_close(tdb);
		tdb_close(tdb_new);
		unlink(tmp_name);
		free(tmp_name);
		return 1;
	}

	failed = 0;

	/* traverse and copy */
	count1 = tdb_traverse(tdb, copy_fn, (void *)tdb_new);
	if (count1 < 0 || failed) {
		fprintf(stderr,"failed to copy %s\n", old_name);
		tdb_close(tdb);
		tdb_close(tdb_new);
		unlink(tmp_name);
		free(tmp_name);
		return 1;
	}

	/* close the old tdb */
	tdb_close(tdb);

	/* close the new tdb and re-open read-only */
	tdb_close(tdb_new);
	tdb_new = tdb_open(tmp_name, 0, TDB_DEFAULT, O_RDONLY, 0);
	if (!tdb_new) {
		fprintf(stderr,"failed to reopen %s\n", tmp_name);
		unlink(tmp_name);
		perror(tmp_name);
		free(tmp_name);
		return 1;
	}
	
	/* traverse the new tdb to confirm */
	count2 = tdb_traverse(tdb_new, test_fn, 0);
	if (count2 != count1) {
		fprintf(stderr,"failed to copy %s\n", old_name);
		tdb_close(tdb_new);
		unlink(tmp_name);
		free(tmp_name);
		return 1;
	}

	/* make sure the new tdb has reached stable storage */
	fsync(tdb_fd(tdb_new));

	/* close the new tdb and rename it to .bak */
	tdb_close(tdb_new);
	unlink(new_name);
	if (rename(tmp_name, new_name) != 0) {
		perror(new_name);
		free(tmp_name);
		return 1;
	}

	free(tmp_name);

	return 0;
}
Пример #13
0
int
main(int argc,
     char ** argv)
{
/// @section csv_segmentation Chan-Sandberg-Vese segmentation
///
/// @subsection csv_theory Theory
/// Since the routine contains too many free parameters which makes it unreasonable to place it into a separate
/// function, all the code is kept in main(). Here's a rough explanation of what's Chan-Sandberg-Vese all about,
/// which is based on paper @cite Getreuer2012.
///
/// The Chan-Vese method seeks a contour @f$\mathcal{C}@f$ which minimizes the functional
/// @f[
///    \mathcal{F}[I;\,\mathcal{C},\,c_{1},\,c_{2}]=
///        \mu\mathrm{Length}(\mathcal{C})+
///        \nu\mathrm{Area}(\mathcal{C})+
///        \lambda_{1}\int_{\mathcal{C}}|I-c_{1}|^{2}\,\mathrm{d}x\mathrm{d}y+
///        \lambda_{2}\int_{\Omega\setminus\mathcal{C}}|I-c_{2}|^{2}\,\mathrm{d}x\mathrm{d}y\,,
/// @f]
/// where
///    - the single-channel image @f$I=I(x,\,y)@f$ is defined on the region @f$\Omega=[0,\,a]\times[0,\,b]@f$;
///         - regions in the integral limits, @f$\mathcal{C}@f$ and @f$\Omega\setminus\mathcal{C}@f$,
///           denote the region enclosed by the contour and the region outside the contour, respectively;
///    -  @f$\mu(=0.5)@f$, @f$\nu(=0)@f$, @f$\lambda_{1}(=1)@f$ and @f$\lambda_{2}(=1)@f$ are free parameters,
///       whereby only @f$\nu@f$ can be negative (default values in parentheses);
///    - @f$c_{1}@f$ and @f$c_{2}@f$ are constants that depend on the information of the regions enclosed by and
///      outside of the contour.
///
/// Instead of dealing with @f$\mathcal{C}@f$ explicitly, it's custom to define a level set function @f$u(x,\,y;\,t)@f$
/// so that its zero-level iso-surface (also: zero level set) coincides with the contour:
/// @f$\mathcal{C}=\{\Omega\ni(x,\,y)\,:\,u(x,\,y;\,t)=0\forall t\}@f$. This in turn leads us to a new definition
/// of the functional:
/// @f[
///      \mathcal{F}[I;\,u,\,c_{1},\,c_{2}] =
///             \mu\left(\int_{\Omega}|\nabla H(u)|\,\mathrm{d}x\mathrm{d}y\right)^{p}+
///             \nu\int_{\Omega}H(u)\,\mathrm{d}x\mathrm{d}y+
///             \lambda_{1}\int_{\Omega}|I-c_{1}|^{2}H(u)\,\mathrm{d}x\mathrm{d}y+
///             \lambda_{2}\int_{\Omega}|I-c_{2}|^{2}(1-H(u))\,\mathrm{d}x\mathrm{d}y\,.
/// @f]
/// In our implementation we've picked @f$p=1@f$, so that the first integral reduces to
/// @f[
///      \left.\mu\left(\int_{\Omega}|\nabla H(u)|\,\mathrm{d}x\mathrm{d}y\right)^{p}\right|_{p=1}=
///       \mu\int_{\Omega}\delta(u)|\nabla u|\,\mathrm{d}x\mathrm{d}y\,,
/// @f]
/// where @f$H(x)@f$ and @f$\delta(x)=H'(x)@f$ are Heaviside's step and Dirac's delta functions.
/// In this prescription @f$c_{1}@f$ and @f$c_{2}@f$ are now region averages and take the following form:
/// @f[
///      c_{1}=\frac{\int_{\Omega}IH(u)\mathrm{d}x\mathrm{d}y}{\int_{\Omega}H(u)\,\mathrm{d}x\mathrm{d}y}\,,\quad
///      c_{2}=\frac{\int_{\Omega}I(1-H(u))\mathrm{d}x\mathrm{d}y}{\int_{\Omega}(1 - H(u))\,\mathrm{d}x\mathrm{d}y}\,.
/// @f]
/// For practical reasons the functions are replaced by smooth/regularized versions (see regularized_heaviside() and
/// regularized_delta()):
/// @f[
///      H_{\epsilon}(x)=\frac{1}{2}\left[1+\frac{2}{\pi}\arctan\left(\frac{x}{\epsilon}\right)\right]\,,\quad
///      \delta_{\epsilon}(x)=\frac{\epsilon}{\pi\left(\epsilon^{2}+x^{2}\right)}\,,
/// @f]
/// with @f$\epsilon=1@f$ by default.
/// The interpretation of the functional @f$\mathcal{F}@f$ is the following:
///     - the first term penalizes the length of @f$\mathcal{C}@f$;
///     - the second term penalizes the area enclosed by the curve;
///     - the 3rd and 4th term penalize region averages inside and outside of the contour; in other words
///       it keeps track of the discrepancy between the two regions.
///
/// A stationary solution to @f$\mathcal{F}@f$, or equivalently the equation of motion (e.o.m) for the contour,
/// can be found by solving it with Euler-Lagrange equation, which results in
/// @f[
///    u_{t} = \delta_{\epsilon}(u)\left[\mu\kappa-\nu-\lambda_{1}(I-c_{1})^{2}+\lambda_{2}(I-c_{2})^{2}\right]\,,
/// @f]
/// where @f$\kappa=\nabla\cdot\left(\frac{\nabla u}{|\nabla u|}\right)@f$ is curvature of @f$u@f$.
///
/// If the (still 2D) image has @f$I@f$ has @f$N@f$ channels @f$\{I_{i}(x,\,y)\}_{i=1}^{N}@f$, there should still
/// be a single level set @f$u@f$, which leads us the following functional:
/// @f[
///    \mathcal{F}[I;\,u,\,\mathbf{c_{1}},\,\mathbf{c}_{2}]=
///      \mu\int_{\Omega}|\nabla H(u)|\mathrm{d}x\mathrm{d}y+
///      \nu\int_{\Omega}H(u)\mathrm{d}x\mathrm{d}y+
///      \int_{\Omega}\frac{1}{N}\sum_{i=1}^{N}\lambda_{1}^{(i)}|I_{i}-c_{1}^{(i)}|^{2}H(u)\mathrm{d}x\mathrm{d}y+
///      \int_{\Omega}\frac{1}{N}\sum_{i=1}^{N}\lambda_{2}^{(i)}|I_{i}-c_{2}^{(i)}|^{2}(1-H(u))\mathrm{d}x\mathrm{d}y\,.
/// @f]
/// Variables @f$\{c_{1}^{(i)},\,c_{2}^{(i)}\}_{i=1}^{N}@f$ retain their original meaning,
/// @f[
///     c_{1}^{(i)}=\frac{\int_{\Omega}I_{i}H(u)\mathrm{d}x\mathrm{d}y}{\int_{\Omega}H(u)\mathrm{d}x\mathrm{d}y}\,,\quad
///     c_{2}^{(i)}=\frac{\int_{\Omega}I_{i}(1-H(u))\mathrm{d}x\mathrm{d}y}{\int_{\Omega}(1-H(u))\mathrm{d}x\mathrm{d}y}
///     \quad\forall i=\{1,\,\ldots,\,N\}\,;
/// @f]
/// the constants @f$\{\lambda_{1}^{(i)},\,\lambda_{2}^{(i)}\}_{i=1}^{N}@f$ are defined for each channel separately.
/// This implementation consider only grayscale (@f$N=1@f$) and RGB (@f$N=3@f$) images, for which @f$\lambda_{i}=1@f$
/// by default for any @f$i@f$-th channel.
/// The corresponding e.o.m reads
/// @f[
///      u_{t}=\delta_{\epsilon}(u)\left[\mu\kappa-\nu-
///            \frac{1}{N}\sum_{i=1}^{N}\lambda_{1}^{(i)}\left(I_{i}-c_{1}^{(i)}\right)^{2}+
///            \frac{1}{N}\sum_{i=1}^{N}\lambda_{2}^{(i)}\left(I_{i}-c_{2}^{(i)}\right)^{2}\right]\,.
/// @f]
///
/// @subsection csv_numsch Numerical scheme
///
/// Finite difference expression for the curvature @f$\kappa@f$ is explained in curvature(). The advantage of this scheme
/// is that we only need nearest neighbouring points at current point while keeping the derivative centered at current point,
/// whereas naive implementation would use more distant points. Since we're dealing with a finite domain and therefore
/// boundaries, we don't have to "extend" the region by two pixels each direction. Instead, we just duplicate border pixels.
///
/// Rest of the calculation is actually quite straightforward -- the zero level set is iteratively updated with
/// @f[
///      u_{i,j}^{n+1}=u_{i,j}^{n}+\mathrm{d}t\;\delta_{\epsilon}(u_{i,j}^{n})\left[\kappa_{i,j}^{n}-\nu-
///      \frac{1}{N}\sum_{k=1}^N\lambda_{1}^{(k)}\left(I_{i,j}-c_{1}^{n,(k)}\right)+
///      \frac{1}{N}\sum_{k=1}^N\lambda_{2}^{(k)}\left(I_{i,j}-c_{2}^{n,(k)}\right)\right]\,.
/// @f]
/// The method is inherently implicit and is implemented with ordinary matrix operations. The first term in the brackets
/// has already been discussed; the second term is trivial; the final two terms are explained in region_variance() and
/// variance_penalty().
///
/// There are various ways to initialize the level set, and since we're solving a differential equation, different initial
/// conditions lead to different outcome. The simplest way is to let the user draw either rectangular or circular contour.
/// The level set will be evaluated with @f$+1@f$'s inside the contour and with @f$-1@f$'s outside of it.
/// A more optimal (here the default) contour would be checkerboard
/// @f[
///      u(i,\,j;\,0)=\sin\left(\frac{\pi}{5}i\right)\sin\left(\frac{\pi}{5}j\right)\,,
/// @f]
/// because it converges faster to a solution (see levelset_checkerboard()). The solution is reached when the maximum number
/// of iterations, @f$T_\max@f$, is reached or when @f$||u_{i,j}^{n+1}-u_{i,j}^{n}||_{2}\leqslant\delta ||\bar{I}||_{2}@f$,
/// where the subscript denotes @f$L_{2}@f$-norm, @f$\delta=(10^{-3})@f$ is tolerance parameter and @f$\bar{I}@f$ is
/// the intensity average in the image (averaged across the channels).
///
/// @subsection csv_summary Summary
///
/// The main logic described above starts with a timestep loop (look for the comment below); everything else preciding
/// that is actually sugar coating just to make the program usable for anyone.
///
/// If it isn't clear from above text or the code below, here is the list of variables which the user can pass as an argument
/// (the default values in the parentheses): @f$\mu(=0.5)@f$, @f$\nu(=0)@f$, @f$\mathrm{d}t(=1)@f$,
/// @f$\lambda_{1}^{(i)}(=1)@f$ and @f$\lambda_{1}^{(i)}(=1)@f$ @f$\forall i=1\ldots N@f$, @f$\epsilon(=1)@f$,
/// @f$\delta(=10^{-3})@f$, @f$T_\max@f$(=INT_MAX), @f$N(=1\;\mbox{or}\;3)@f$ (number of channels).
///
/// Other general options include:
///    - object selection (-s) -- the region enclosed by the contour will be cut out and placed onto white canvas and saved;
///    - region inversion (-I) -- sometimes the ROI is inverted; there's an option to circumvent that (goes with -s option);
///    - video output (-V) -- see contour evolution in a video (*.avi, the same filename as the image; see VideoWriterManager);
///    - overlay text (-O) -- puts overlay text (timesteps) on the video (goes with the previous option);
///    - frame rate (-f) -- frame rate of the video;
///    - line color (-l) -- color of the contour line (see Colors);
///    - rectangular (-R) or circular (-C) contour -- lets the user draw it on the image (see InteractiveData and its subclasses);
///    - grayscale image (-g) -- sometimes we just want do perform it on a black-white image, but the original source is RGB.
///
/// For Perona-Malik-specific parameters @f$K@f$, @f$L@f$, @f$T@f$, see perona_malik().
///
/// @sa curvature, region_variance, variance_penalty, levelset_checkerboard, VideoWriterManager, InteractiveData, Colors, perona_malik

  double mu, nu, eps, tol, dt, fps, K, L, T;
  int max_steps;
  std::vector<double> lambda1,
                      lambda2;
  std::string input_filename,
              text_position,
              line_color_str;
  bool grayscale         = false,
       write_video       = false,
       overlay_text      = false,
       object_selection  = false,
       invert            = false,
       segment           = false,
       rectangle_contour = false,
       circle_contour    = false;
  ChanVese::TextPosition pos = ChanVese::TextPosition::TopLeft;
  cv::Scalar contour_color = ChanVese::Colors::blue;

//-- Parse command line arguments
//   Negative values in multitoken are not an issue, b/c it doesn't make much sense
//   to use negative values for lambda1 and lambda2
  try
  {
    namespace po = boost::program_options;
    po::options_description desc("Allowed options", get_terminal_width());
    desc.add_options()
      ("help,h",                                                                               "this message")
      ("input,i",            po::value<std::string>(&input_filename),                          "input image")
      ("mu",                 po::value<double>(&mu) -> default_value(0.5),                     "length penalty parameter (must be positive or zero)")
      ("nu",                 po::value<double>(&nu) -> default_value(0),                       "area penalty parameter")
      ("dt",                 po::value<double>(&dt) -> default_value(1),                       "timestep")
      ("lambda1",            po::value<std::vector<double>>(&lambda1) -> multitoken(),         "penalty of variance inside the contour (default: 1's)")
      ("lambda2",            po::value<std::vector<double>>(&lambda2) -> multitoken(),         "penalty of variance outside the contour (default: 1's)")
      ("epsilon,e",          po::value<double>(&eps) -> default_value(1),                      "smoothing parameter in Heaviside/delta")
      ("tolerance,t",        po::value<double>(&tol) -> default_value(0.001),                  "tolerance in stopping condition")
      ("max-steps,N",        po::value<int>(&max_steps) -> default_value(-1),                  "maximum nof iterations (negative means unlimited)")
      ("fps,f",              po::value<double>(&fps) -> default_value(10),                     "video fps")
      ("overlay-pos,P",      po::value<std::string>(&text_position) -> default_value("TL"),    "overlay tex position; allowed only: TL, BL, TR, BR")
      ("line-color,l",       po::value<std::string>(&line_color_str) -> default_value("blue"), "contour color (allowed only: black, white, R, G, B, Y, M, C")
      ("edge-coef,K",        po::value<double>(&K) -> default_value(10),                       "coefficient for enhancing edge detection in Perona-Malik")
      ("laplacian-coef,L",   po::value<double>(&L) -> default_value(0.25),                     "coefficient in the gradient FD scheme of Perona-Malik (must be [0, 1/4])")
      ("segment-time,T",     po::value<double>(&T) -> default_value(20),                       "number of smoothing steps in Perona-Malik")
      ("segment,S",          po::bool_switch(&segment),                                        "segment the image with Perona-Malik beforehand")
      ("grayscale,g",        po::bool_switch(&grayscale),                                      "read in as grayscale")
      ("video,V",            po::bool_switch(&write_video),                                    "enable video output (changes the extension to '.avi')")
      ("overlay-text,O",     po::bool_switch(&overlay_text),                                   "add overlay text")
      ("invert-selection,I", po::bool_switch(&invert),                                         "invert selected region (see: select)")
      ("select,s",           po::bool_switch(&object_selection),                               "separate the region encolosed by the contour (adds suffix '_selection')")
      ("rectangle,R",        po::bool_switch(&rectangle_contour),                              "select rectangular contour interactively")
      ("circle,C",           po::bool_switch(&circle_contour),                                 "select circular contour interactively")
    ;
    po::variables_map vm;
    po::store(po::command_line_parser(argc, argv).options(desc).run(), vm);
    po::notify(vm);

    if(vm.count("help"))
    {
      std::cout << desc << "\n";
      return EXIT_SUCCESS;
    }
    if(! vm.count("input"))
      msg_exit("Error: you have to specify input file name!");
    else if(vm.count("input") && ! boost::filesystem::exists(input_filename))
      msg_exit("Error: file \"" + input_filename + "\" does not exists!");
    if(vm.count("dt") && dt <= 0)
      msg_exit("Cannot have negative or zero timestep: " + std::to_string(dt) + ".");
    if(vm.count("mu") && mu < 0)
      msg_exit("Length penalty parameter cannot be negative: " + std::to_string(mu) + ".");
    if(vm.count("lambda1"))
    {
      if(grayscale && lambda1.size() != 1)
        msg_exit("Too many lambda1 values for a grayscale image.");
      else if(! grayscale && lambda1.size() != 3)
        msg_exit("Number of lambda1 values must be 3 for a colored input image.");
      else if(grayscale && lambda1[0] < 0)
        msg_exit("The value of lambda1 cannot be negative.");
      else if(! grayscale && (lambda1[0] < 0 || lambda1[1] < 0 || lambda1[2] < 0))
        msg_exit("Any value of lambda1 cannot be negative.");
    }
    else if(! vm.count("lambda1"))
    {
      if(grayscale) lambda1 = {1};
      else          lambda1 = {1, 1, 1};
    }
    if(vm.count("lambda2"))
    {
      if(grayscale && lambda2.size() != 1)
        msg_exit("Too many lambda2 values for a grayscale image.");
      else if(! grayscale && lambda2.size() != 3)
        msg_exit("Number of lambda2 values must be 3 for a colored input image.");
      else if(grayscale && lambda2[0] < 0)
        msg_exit("The value of lambda2 cannot be negative.");
      else if(! grayscale && (lambda2[0] < 0 || lambda2[1] < 0 || lambda2[2] < 0))
        msg_exit("Any value of lambda2 cannot be negative.");
    }
    else if(! vm.count("lambda2"))
    {
      if(grayscale) lambda2 = {1};
      else          lambda2 = {1, 1, 1};
    }
    if(vm.count("eps") && eps < 0)
      msg_exit("Cannot have negative smoothing parameter: " + std::to_string(eps) + ".");
    if(vm.count("tol") && tol < 0)
      msg_exit("Cannot have negative tolerance: " + std::to_string(tol) + ".");
    if(vm.count("overlay-pos"))
    {
      if     (boost::iequals(text_position, "TL")) pos = ChanVese::TextPosition::TopLeft;
      else if(boost::iequals(text_position, "BL")) pos = ChanVese::TextPosition::BottomLeft;
      else if(boost::iequals(text_position, "TR")) pos = ChanVese::TextPosition::TopRight;
      else if(boost::iequals(text_position, "BR")) pos = ChanVese::TextPosition::BottomRight;
      else
        msg_exit("Invalid text position requested.\n"\
                 "Correct values are: TL -- top left\n"\
                 "                    BL -- bottom left\n"\
                 "                    TR -- top right\n"\
                 "                    BR -- bottom right"\
                );
    }
    if(vm.count("line-color"))
    {
      if     (boost::iequals(line_color_str, "red"))     contour_color = ChanVese::Colors::red;
      else if(boost::iequals(line_color_str, "green"))   contour_color = ChanVese::Colors::green;
      else if(boost::iequals(line_color_str, "blue"))    contour_color = ChanVese::Colors::blue;
      else if(boost::iequals(line_color_str, "black"))   contour_color = ChanVese::Colors::black;
      else if(boost::iequals(line_color_str, "white"))   contour_color = ChanVese::Colors::white;
      else if(boost::iequals(line_color_str, "magenta")) contour_color = ChanVese::Colors::magenta;
      else if(boost::iequals(line_color_str, "yellow"))  contour_color = ChanVese::Colors::yellow;
      else if(boost::iequals(line_color_str, "cyan"))    contour_color = ChanVese::Colors::cyan;
      else
        msg_exit("Invalid contour color requested.\n"\
                 "Correct values are: red, green, blue, black, white, magenta, yellow, cyan.");
    }
    if(vm.count("laplacian-coef") && (L > 0.25 || L < 0))
      msg_exit("The Laplacian coefficient in Perona-Malik segmentation must be between 0 and 0.25.");
    if(vm.count("segment-time") && (T < L))
      msg_exit("The segmentation duration must exceed the value of Laplacian coefficient, " +
               std::to_string(L) + ".");
    if(rectangle_contour && circle_contour)
      msg_exit("Cannot initialize with both rectangular and circular contour");
  }
  catch(std::exception & e)
  {
    msg_exit("error: " + std::string(e.what()));
  }

//-- Read the image (grayscale or BGR? RGB? BGR? help)
  cv::Mat _img;
  if(grayscale) _img = cv::imread(input_filename, CV_LOAD_IMAGE_GRAYSCALE);
  else          _img = cv::imread(input_filename, CV_LOAD_IMAGE_COLOR);
  if(! _img.data)
    msg_exit("Error on opening \"" + input_filename + "\" (probably not an image)!");

//-- Second conversion needed since we want to display a colored contour on a grayscale image
  cv::Mat img;
  if(grayscale) cv::cvtColor(_img, img, CV_GRAY2RGB);
  else          img = _img;
  _img.release();

//-- Determine the constants and define functionals
  max_steps = max_steps < 0 ? std::numeric_limits<int>::max() : max_steps;
  const int h = img.rows;
  const int w = img.cols;
  const int nof_channels = grayscale ? 1 : img.channels();
  const auto heaviside = std::bind(regularized_heaviside, std::placeholders::_1, eps);
  const auto delta = std::bind(regularized_delta, std::placeholders::_1, eps);

//-- Construct the level set
  cv::Mat u;
  if(rectangle_contour || circle_contour)
  {
    std::unique_ptr<InteractiveData> id;
    cv::startWindowThread();
    cv::namedWindow(WINDOW_TITLE, cv::WINDOW_NORMAL);

    if     (rectangle_contour)
      id = std::unique_ptr<InteractiveDataRect>(new InteractiveDataRect(&img, contour_color));
    else if(circle_contour)
      id = std::unique_ptr<InteractiveDataCirc>(new InteractiveDataCirc(&img, contour_color));

    if(id) cv::setMouseCallback(WINDOW_TITLE, on_mouse, id.get());
    cv::imshow(WINDOW_TITLE, img);
    cv::waitKey();
    cv::destroyWindow(WINDOW_TITLE);

    if(id)
    {
      if(! id -> is_ok())
        msg_exit("You must specify the contour with non-zero dimensions");
      u = id -> get_levelset(h, w);
    }
  }
  else
    u = levelset_checkerboard(h, w);

//-- Set up the video writer (and save the first frame)
  VideoWriterManager vwm;
  if(write_video)
  {
    vwm = VideoWriterManager(input_filename, img, contour_color, fps, pos, overlay_text);
    vwm.write_frame(u, overlay_text ? "t = 0" : "");
  }

//-- Split the channels
  std::vector<cv::Mat> channels;
  channels.reserve(nof_channels);
  cv::split(img, channels);
  if(grayscale) channels.erase(channels.begin() + 1, channels.end());

//-- Smooth the image with Perona-Malik
  cv::Mat smoothed_img;
  if(segment)
  {
    smoothed_img = perona_malik(channels, h, w, K, L, T);
    channels.clear();
    cv::split(smoothed_img, channels);
    cv::imwrite(add_suffix(input_filename, "pm"), smoothed_img);
  }

//-- Find intensity sum and derive the stopping condition
  cv::Mat intensity_avg = cv::Mat(h, w, CV_64FC1);
#pragma omp parallel for num_threads(nof_channels)
  for(int k = 0; k < nof_channels; ++k)
  {
    cv::Mat channel(h, w, intensity_avg.type());
    channels[k].convertTo(channel, channel.type());
    intensity_avg += channel;
  }
  intensity_avg /= nof_channels;
  double stop_cond = tol * cv::norm(intensity_avg, cv::NORM_L2);
  intensity_avg.release();

//-- Timestep loop
  for(int t = 1; t <= max_steps; ++t)
  {
    cv::Mat u_diff(cv::Mat::zeros(h, w, CV_64FC1));

//-- Channel loop
#pragma omp parallel for num_threads(nof_channels)
    for(int k = 0; k < nof_channels; ++k)
    {
      cv::Mat channel = channels[k];
//-- Find the average regional variances
      const double c1 = region_variance(channel, u, h, w, ChanVese::Region::Inside, heaviside);
      const double c2 = region_variance(channel, u, h, w, ChanVese::Region::Outside, heaviside);

//-- Calculate the contribution of one channel to the level set
      const cv::Mat variance_inside = variance_penalty(channel, h, w, c1, lambda1[k]);
      const cv::Mat variance_outside = variance_penalty(channel, h, w, c2, lambda2[k]);
      u_diff += -variance_inside + variance_outside;
    }
//-- Calculate the curvature (divergence of normalized gradient)
    const cv::Mat kappa = curvature(u, h, w);

//-- Mash the terms together
    u_diff = dt * (mu * kappa - nu + u_diff / nof_channels);

//-- Run delta function on the level set
    cv::Mat u_cp = u.clone();
    cv::parallel_for_(cv::Range(0, h * w), ParallelPixelFunction(u_cp, w, delta));

//-- Shift the level set
    cv::multiply(u_diff, u_cp, u_diff);
    const double u_diff_norm = cv::norm(u_diff, cv::NORM_L2);
    u += u_diff;

//-- Save the frame
    if(write_video) vwm.write_frame(u, overlay_text ? "t = " + std::to_string(t) : "");

//-- Check if we have achieved the desired precision
    if(u_diff_norm <= stop_cond) break;
  }

//-- Select the region enclosed by the contour and save it to the disk
  if(object_selection)
    cv::imwrite(add_suffix(input_filename, "selection"), separate(img, u, h, w, invert));

  return EXIT_SUCCESS;
}
Пример #14
0
static void file_action(char *filename) {
  struct stat buf;
  int st;
  int link = 0;
  char *outfile;
  char *infile;
  char *buffer = NULL;

  infile = filename;  /* but it may be changed below */

  st = lstat(infile, &buf);

  if (st) {
    int save_errno = errno;
    
    /* if file didn't exist and decrypting, try if suffixed file exists */
    if (errno==ENOENT 
	&& (cmd.mode==DECRYPT || cmd.mode==CAT || cmd.mode==KEYCHANGE 
	    || cmd.mode==UNIXCRYPT) 
	&& cmd.suffix[0]!=0) {
      buffer = xalloc(strlen(filename)+strlen(cmd.suffix)+1, cmd.name);

      strcpy(buffer, infile);
      strcat(buffer, cmd.suffix);
      infile=buffer;
      st = lstat(infile, &buf);
    }
    if (st) {
      fprintf(stderr, "%s: %s: %s\n", cmd.name, filename, strerror(save_errno));
      io_errors++;
      goto done;
    }
  }
  
  /* if link following is enabled, follow links */
  if (cmd.symlinks && S_ISLNK(buf.st_mode)) {
    link = 1;
    st = stat(infile, &buf);
    if (st) {
      fprintf(stderr, "%s: %s: %s\n", cmd.name, infile, strerror(errno));
      io_errors++;
      goto done;
    }
  }

  /* assert st==0 */

  /* if file is not a regular file, skip */
  if (S_ISLNK(buf.st_mode)) {
    if (cmd.verbose>=0) {
      fprintf(stderr, "%s: %s: is a symbolic link -- ignored\n", cmd.name, infile);
      symlink_warnings++;
    }
    goto done;
  }
  if (!S_ISREG(buf.st_mode)) {
    if (cmd.verbose>=0) {
      fprintf(stderr, "%s: %s: is not a regular file -- ignored\n", cmd.name, 
	      infile);
      isreg_warnings++;
    }
    goto done;
  }
  
  /* now we have a regular file, and we have followed a link if
     appropriate. */

  if (cmd.mode==ENCRYPT || cmd.mode==DECRYPT || cmd.mode==KEYCHANGE) {
    /* determine outfile name */
    switch (cmd.mode) {
    case ENCRYPT: default:
      if (cmd.strictsuffix && cmd.suffix[0] != 0 && has_suffix(infile, cmd.suffix)) {
	if (cmd.verbose>=0) {
	  fprintf(stderr, "%s: %s already has %s suffix -- ignored\n", cmd.name, infile, cmd.suffix); 
	  strict_warnings++;
	}
	goto done;
      }
      outfile = add_suffix(infile, cmd.suffix);
      break;
    case DECRYPT:
      outfile = remove_suffix(infile, cmd.suffix);
      break;
    case KEYCHANGE:
      outfile = infile;
      break;
    }
    
    /* if outfile exists and cmd.force is not set, prompt whether to
       overwrite */
    if (!cmd.force && strcmp(infile, outfile) && 
	file_exists(outfile)) {
      fprintf(stderr, "%s: %s already exists; overwrite (y or n)? ", cmd.name, 
	      outfile);
      fflush(stderr);
      if (prompt()==0) {
	fprintf(stderr, "Not overwritten.\n");
	goto done;
      }
    }
    if (cmd.tmpfiles) {
      action_tmpfiles(infile, outfile);
    } else {
      action_overwrite(infile, outfile);
    }
  } else {
    action_cat(infile);
  }
 done:
  free(buffer);
  return;
}