basename-and-dirname

Often the unix commands basename and dirname are useful in shell scripts, but how do you use these in c or c++?.

The C way: libgen.h

If you’re working in c, the posix header libgen.h provides dirname and basename functions, with some limitations: They only work with char *, and dirname will modify the char * you pass into it so you need to make a copy of your original path if you wish to keep it. Example code:

// libgen_example.c
// Demonstrate libgen.h usage and pitfalls
// Compile:  gcc -g -o libgen_example libgen_example.c
#include
<libgen.h> //basename and dirname
#include <string.h> //strlen and strcpy
#include <stdio.h> //printf
#include <stdlib.h> //malloc
 
int main(int argc, char* argv[]) {
    // Demonstrate how dirname changes the path you input to it
    char path[] = "default/path/to/nowhere.txt";
    printf("path='%s'\n", path);
    char * dir = dirname(path);
    printf("path='%s'  dir='%s'\n", path, dir);
    char * base = basename(path);
    printf("path='%s'  dir='%s'  base='%s'\n\n",
           path, dir, base);
    // Since dirname changed path, base is now "to"
    // instead of "nowhere.txt" as we might have expected.
    // Output:
    // path='default/path/to/nowhere.txt'
    // path='default/path/to'  dir='default/path/to'
    // path='default/path/to'  dir='default/path/to'  base='to'
 
    //========
    // Demonstrate c string copying
    const char * another_path = "another/path";
    char * modifiable_copy = (char *)malloc(strlen(another_path) + 1);
    strcpy(modifiable_copy, another_path);
    char * another_dir = dirname(modifiable_copy);
    printf("another_path='%s'\n", another_path);
    printf("modifiable_copy='%s'\n", modifiable_copy);
    printf("another_dir='%s'\n\n", another_dir);
    // note that after this free, another_dir is now also
    // invalid since it pointed to the modifiable_copy's memory
    free(modifiable_copy);
    // Output:
    // another_path='another/path'
    // modifiable_copy='another'
    // another_dir='another'
 
    //========
    // const strings declared as char * can cause segfaults
    char * char_pointer_path = "char/pointer/path";
    printf("char_pointer_path='%s'\n", char_pointer_path);
 
    char * char_pointer_dir = dirname(char_pointer_path);
    printf("char_pointer_path='%s' char_pointer_dir='%s'\n",
           char_pointer_path, char_pointer_dir);
    // Output:
    // char_pointer_path='char/pointer/path'
    // Segmentation fault
}

The C++ way: boost::filesystem

If you’re looking for a better c++ solution, see the c++ boost filesystem library. boost::filesystem::path.parent_path() can be used like dirname and boost::filesystem::path.filename() acts like basename.

The boost::filesystem library also has many other useful functions for dealing with files and paths (e.g. fs::complete(path) for obtaining an absolute path, fs::exists(path) will check if the path exists, fs::create_directories(path), fs::remove(path), fs::copy_file(from,to) name a few). Note that some of these are functions are boost::filesystem::path methods and some are in boost::filesystem. According to the faq, operations done by the operating system are provided in boost::filesystem functions, but functions just performed on the lexical path (just path string manipulations) are provided as boost::filesystem::path methods.

// filesystem_example.cpp
// Demonstrate using boost::filesystem
// Compile:  g++ -I /usr/local/include/boost-1_38/ -L /usr/local/lib -lboost_filesystem-gcc41-mt-1_38 -o filesystem_example filesystem_example.cpp
#include <boost/filesystem.hpp>
#include <iostream>
namespace fs = boost::filesystem;
 
int main(int argc, char* argv[])
{
    fs::path pathname("default/path/to/nowhere.txt");
    std::string dirname  = pathname.parent_path().string();
    std::string basename = pathname.filename();
 
    std::cout << "pathname = " << pathname << std::endl;
    std::cout << "dirname = " << dirname << std::endl;
    std::cout << "basename = " << basename << std::endl;
    // Output:
    // pathname = default/path/to/nowhere.txt
    // dirname = default/path/to
    // basename = nowhere.txt
 
    std::cout << std::endl;
    std::cout << "extension = " << pathname.extension() << std::endl;
    std::cout << "complete = " << fs::complete(pathname) << std::endl;
    std::cout << "exists = " << ((fs::exists(pathname)) ? "true" : "false") << std::endl;
    // Output:
    // extension = .txt
    // complete = /home/moose/default/path/to/nowhere.txt
    // exists = false
}
using-gcc-c-hash-classes-with-strings

So even though hash_map and hash_set aren’t a part of the C++ standard, there are still implementations included with the gcc compiler. You have to include or and a little magic to get them to work properly with std::string keys.

// Example code using a hash_set with std::string keys on gcc
// Example based on hash_set code from "6.7 Using Hashed Containers"
// in O'Reilly C++ Cookbook by Stephens, Diggins, Turkanis & Cogswell  (2006)
// and gcc fix from post http://gcc.gnu.org/ml/libstdc++/2002-04/msg00107.html
// Tested with g++ 4.1.2
// Compile with:
// g++ -o hash hash.cpp
// Kristi Tsukida <kristi.tsukida at gmail dot com> 30-10-2008
 
#include <iostream>
#include <string>
#include <ext/hash_set>
 
using namespace std;
// The __gnu_cxx namespace contains the hash_set since it's not standard c++
using namespace __gnu_cxx;
 
// This is the magic that will allow the usage of string keys in the hash
namespace __gnu_cxx
{
        template<> struct hash< std::string >
        {
                size_t operator()( const std::string& x ) const
                {
                        return hash< const char* >()( x.c_str() );
                }
        };
}
 
// must specify the hash<string> hash function
typedef hash_set<string, hash<string> > string_hash_set;
 
int main()
{
	string_hash_set hs;
 
	string s = "bravo";
	hs.insert(s);
	s = "alpha";
	hs.insert(s);
	s = "charlie";
	hs.insert(s);
 
	for(string_hash_set::const_iterator p = hs.begin(); p!= hs.end(); ++p)
	{
		cout << *p << endl;
	}
 
}
opencv-corner-detection-using-cvgoodfeaturestotrack

Here’s an example opencv application which uses cvGoodFeaturesToTrack to detect corners in a webcam video feed.

download good_features.cpp source

//
// This code displays corners found by the opencv function
// GoodFeaturesToTrack (cvGoodFeaturesToTrack)
//
// Sample webcam code taken from
//   http://www.cs.iit.edu/~agam/cs512/lect-notes/
//   opencv-intro/opencv-intro.html#SECTION00070000000000000000
//
// compile with:
// gcc `pkg-config --cflags opencv` `pkg-config --libs opencv`
// -o good_features good_features.cpp
//
// Kristi Tsukida  <kristi.tsukida@gmail.com> Aug 20, 2008
//
// Note: I commented out the corner detection using the Harris
// algorithm because my computer isn't fast enough to process
// both the Harris and the eigenvalue corners in real time.
// You can uncomment it and test for yourself.
//
 
#include <cv.h>
#include <highgui.h>
 
#include <stdio.h>
#include <sys/time.h>
 
#define VIDEO_WINDOW   "Webcam"
#define CORNER_EIG     "Eigenvalue Corner Detection"
// Disable harris processing
//#define CORNER_HARRIS  "Corner Detection (Harris)"
 
#define USEC_PER_SEC 1000000L
 
CvScalar target_color[4] = { // in BGR order
		{{   0,   0, 255,   0 }},  // red
		{{   0, 255,   0,   0 }},  // green
		{{ 255,   0,   0,   0 }},  // blue
		{{   0, 255, 255,   0 }}   // yellow
};
 
// returns the number of usecs of (t2 - t1)
long time_elapsed (struct timeval &t1, struct timeval &t2) {
 
	long sec, usec;
 
	sec = t2.tv_sec - t1.tv_sec;
	usec = t2.tv_usec - t1.tv_usec;
	if (usec < 0) {
		--sec;
		usec = usec + USEC_PER_SEC;
	}
	return sec*USEC_PER_SEC + usec;
}
 
struct timeval start_time;
struct timeval end_time;
void start_timer() {
	struct timezone tz;
	gettimeofday (&start_time, &tz);
}
long end_timer() {
	struct timezone tz;
	gettimeofday (&end_time, &tz);
	return time_elapsed(start_time, end_time);
}
 
// A Simple Camera Capture Framework
int main(int argc, char *argv[]) {
	long harris_time;
	long eig_time;
 
	CvCapture* capture = 0;
	IplImage* curr_frame = 0; // current video frame
	IplImage* gray_frame = 0; // grayscale version of current frame
	int w, h; // video frame size
	IplImage* eig_image = 0;
	IplImage* temp_image = 0;
	// Disable harris processing
	//IplImage* harris_eig_image = 0;
	//IplImage* harris_temp_image = 0;
 
	// Pick one of these capture methods:
	// You must have compiled opencv with ffmpeg enabled
	// to use a web stream!
	//capture = cvCaptureFromFile(
	//		"http://user:pw@192.168.1.101:81/img/video.mjpeg");
	//capture = cvCaptureFromAVI(
	//		"http://user:pw@192.168.1.101:81/img/video.mjpeg");
 
	// Capture from a webcam
	capture = cvCaptureFromCAM(CV_CAP_ANY);
	//capture = cvCaptureFromCAM(0); // capture from video device #0
	if ( !capture) {
		fprintf(stderr, "ERROR: capture is NULL... Exiting\n");
		//getchar();
		return -1;
	}
 
	// Create a window in which the captured images will be presented
	cvNamedWindow(VIDEO_WINDOW, 0); // allow the window to be resized
 
	cvNamedWindow(CORNER_EIG, 0); // allow the window to be resized
	cvMoveWindow(CORNER_EIG, 330, 0);
 
	// Disable harris processing
	//cvNamedWindow(CORNER_HARRIS, 0); // allow the window to be resized
	//cvMoveWindow(CORNER_HARRIS, 660, 0);
 
	// Show the image captured from the camera in the window and repeat
	while (true) {
 
		// Get one frame
		curr_frame = cvQueryFrame(capture);
		if ( !curr_frame) {
			fprintf(stderr, "ERROR: frame is null... Exiting\n");
			//getchar();
			break;
		}
		// Do not release the frame!
 
		// Get frame size
		w = curr_frame->width;
		h = curr_frame->height;
 
		// Convert the frame image to grayscale
		if( ! gray_frame ) {
			//fprintf(stderr, "Allocate gray_frame\n");
			int channels = 1;
			gray_frame = cvCreateImage(
					cvGetSize(curr_frame),
					IPL_DEPTH_8U, channels);
		}
		cvCvtColor(curr_frame, gray_frame, CV_BGR2GRAY);
 
		// ==== Allocate memory for corner arrays ====
		if ( !eig_image) {
			//fprintf(stderr, "Allocate eig_image\n");
			eig_image = cvCreateImage(cvSize(w, h),
					IPL_DEPTH_32F, 1);
		}
		if ( !temp_image) {
			//fprintf(stderr, "Allocate temp_image\n");
			temp_image = cvCreateImage(cvSize(w, h),
					IPL_DEPTH_32F, 1);
		}
// Disable harris processing
//		if ( !harris_eig_image) {
//			//fprintf(stderr, "Allocate harris_eig_image\n");
//			harris_eig_image = cvCreateImage(cvSize(w, h),
//					IPL_DEPTH_32F, 1);
//		}
//		if ( !harris_temp_image) {
//			//fprintf(stderr, "Allocate harris_temp_image\n");
//			harris_temp_image = cvCreateImage(cvSize(w, h),
//					IPL_DEPTH_32F, 1);
//		}
 
		// ==== Corner Detection: MinEigenVal method ====
		start_timer();
		const int MAX_CORNERS = 100;
		CvPoint2D32f corners[MAX_CORNERS] = {0};
		int corner_count = MAX_CORNERS;
		double quality_level = 0.1;
		double min_distance = 5;
		int eig_block_size = 3;
		int use_harris = false;
 
		cvGoodFeaturesToTrack(gray_frame,
				eig_image,                    // output
				temp_image,
				corners,
				&corner_count,
				quality_level,
				min_distance,
				NULL,
				eig_block_size,
				use_harris);
		cvScale(eig_image, eig_image, 100, 0.00);
		eig_time = end_timer();
		cvShowImage(CORNER_EIG, eig_image);
 
// Disable harris processing
//		// ==== Corner Detection: Harris method ====
//		start_timer();
////		const int MAX_CORNERS = 100;
//		CvPoint2D32f harris_corners[MAX_CORNERS] = {0};
//		int harris_corner_count = MAX_CORNERS;
//		double harris_quality_level = 0.1;
//		double harris_min_distance = 1;
//		int harris_eig_block_size = 3;
//		int harris_use_harris = true;
//
//		cvGoodFeaturesToTrack(gray_frame,
//				harris_eig_image,                    // output
//				harris_temp_image,
//				harris_corners,
//				&harris_corner_count,
//				harris_quality_level,
//				harris_min_distance,
//				NULL,
//				harris_eig_block_size,
//				harris_use_harris);
//		cvScale(harris_eig_image, harris_eig_image, 200, 0.50);
//		harris_time = end_timer();
//		cvShowImage(CORNER_HARRIS, harris_eig_image);
//
//		fprintf(stderr, "harris time: %i  eig time: %i\n", harris_time, eig_time);
 
		// ==== Draw circles around detected corners in original image
		//fprintf(stderr, "corner[0] = (%f, %f)\n", corners[0].x, corners[0].y);
		for( int i = 0; i < corner_count; i++) {
			int radius = h/25;
			cvCircle(curr_frame,
					cvPoint((int)(corners[i].x + 0.5f),(int)(corners[i].y + 0.5f)),
					radius,
					target_color[0]);
		}
		cvShowImage(VIDEO_WINDOW, curr_frame);
 
		// If ESC key pressed, Key=0x10001B under OpenCV 0.9.7(linux version),
		// remove higher bits using AND operator
		if ( (cvWaitKey(10) & 255) == 27)
			break;
	}
 
	// Release the capture device housekeeping
	cvReleaseCapture( &capture);
	cvDestroyWindow(VIDEO_WINDOW);
	cvDestroyWindow(CORNER_EIG);
// Disable harris processing
//	cvDestroyWindow(CORNER_HARRIS);
	return 0;
}