How to give folder of images as input to Magick++ api? - c++

I am need of passing a folder of images as input to Magick++ api. It can be done using mogrify in commandline as shown in post "ImageMagick script to resize folder of images". Reading a single image could be done through api call as
Image image(inputimage)
But how could we do the same for a folder of images? Can anyone help me with the respective api call?

That feature is not included in the Magick++ API. You will need to iterate the directory yourself and then use the Magick++ API to read and write the image. You can find an example on how to iterate through a folder in C/C++ in the following Stack Overflow post: How can I get the list of files in a directory using C or C++?.

I believe you would be responsible of reading the directory. The C library dirent.h is the first thing I think of, but I'm sure there's better C++/system/framework techniques.
#include <iostream>
#include <vector>
#include <dirent.h>
#include <Magick++.h>
int main(int argc, const char * argv[]) {
std::vector<Magick::Image> stack; // Hold images found
DIR * dir_handler = opendir("/tmp/images"); // Open dir
struct dirent * dir_entry;
if (dir_handler != NULL)
{
// Iterate over entries in directory
while ( (dir_entry = readdir(dir_handler)) != NULL ) {
// Only act on regular files
if (dir_entry->d_type == DT_REG) {
// Concatenate path (could be better)
std::string filename("/tmp/images/");
filename += dir_entry->d_name;
// Read image at path
stack.push_back(Magick::Image(filename));
}
}
closedir(dir_handler); // House keeping
} else {
// Handle DIR error
}
// Append all images into single montage
Magick::Image output;
Magick::appendImages(&output, stack.begin(), stack.end());
output.write("/tmp/all.png");
return 0;
}
There's also ExpandFilenames(int *,char ***) in the MagickCore library.
// Patterns to scan
int pattern_count = 1;
// First pattern
char pattern[PATH_MAX] = "/tmp/images/*.png";
// Allocate memory for list of patterns
char ** dir_pattern = (char **)MagickCore::AcquireMagickMemory(sizeof(char *));
// Assign first pattern
dir_pattern[0] = pattern;
// Expand patterns
Magick::MagickBooleanType ok;
ok = MagickCore::ExpandFilenames(&pattern_count, &dir_pattern);
if (ok == Magick::MagickTrue) {
std::vector<Magick::Image> stack;
// `pattern_count' now holds results count
for ( int i = 0; i < pattern_count; ++i) {
// `dir_pattern' has been re-allocated with found results
std::string filename(dir_pattern[i]);
stack.push_back(Magick::Image(filename));
}
Magick::Image output;
Magick::appendImages(&output, stack.begin(), stack.end());
output.write("/tmp/all.png");
} else {
// Error handle
}

Related

Stuck using dirent.h to find all files in subfolders C++

I'm currently stuck using dirent.h extension. The goal is to give the function a path directory to start from. That function would then look through all the subfolders from that directory and find files in it. It all works until there are two folders in the same directory. Then the program stubbornly chooses one folder and ignores the other.
Here goes my mess of a code.
(The issue is commented at the bottom of the code)
#include <iostream>
#include "dirent.h"
#include <windows.h>
DWORD getPathType(const char *path); //checks if path leads to folder or file
const char *dirlist[20]; //contains all directories (not files, only dir's)
int dirAm = 0; //specifies amount of directories
void loadTextures(const char *loaddir) {
dirlist[dirAm] = loaddir; //specifies starting directory
dirAm++;
for(int i = 0; i<20; i++) {
DIR *dir;
struct dirent *ent;
const char *currentdir = dirlist[i]; //stores current directory
dir = opendir(currentdir); //opens current directory
if (dir != NULL) {
std::cout << "[OPENING dir]\t" << currentdir << std::endl;
while ((ent = readdir(dir)) != NULL) {
const char *filename; //stores current file/folder name
char fullDirName[100]; //stores full path name (current dir+file name, for example /images/+image1.png)
DWORD filetype; //checking path type (file/folder)
filename = ent->d_name; //gets current file name
strcpy(fullDirName, currentdir); //concats current directory and file name to get full path, for example /images/image1.png
strcat(fullDirName, filename);
filetype = getPathType(fullDirName); //gets path type
if (filetype == FILE_ATTRIBUTE_DIRECTORY) {
//if its a directory add it to the list of directories, dirlist, the naming process is the same as above
const char *filenameIn;
char fullDirNameIn[100];
filenameIn = ent->d_name;
strcpy(fullDirNameIn, currentdir);
strcat(fullDirNameIn, filenameIn);
strcat(fullDirNameIn, "/");
std::cout << "[FOUND dir]\t" << fullDirNameIn<<std::endl;
dirlist[dirAm] = fullDirNameIn;
dirAm++;
/* Here is the problem! The cout line above finds all
folders in a directory and saves them in the array, but as soon as the new for
loop iteration starts, the values in the dirlist array... change? And I have no
idea what is going on */
} else {
std::cout << "[FOUND file]\t" << fullDirName << std::endl;
}
}
}
}
And here is the getPathType() function. Pretty straight forward, I guess.
DWORD getPathType(const char *path) {
DWORD fileat;
fileat = GetFileAttributesA(path);
return fileat;
}
Finally, here is the console output:
[OPENING dir] img/ <- opens starting dir
[FOUND dir] img/lvl0/ <- finds lvl0, should store it in dirlist
[FOUND dir] img/lvl1/ <- finds lvl1
[OPENING dir] img/lvl1/
[FOUND file] img/lvl1/player2.png
[OPENING dir] img/lvl1/ <- only opens lvl1
[FOUND file] img/lvl1/player2.png
I know this is a very big question, but I would be quite thankful if someone could share ideas on this.
You are ignoring the scope of your char arrays. Effectively you are doing this
const char *dirlist[20];
while (...)
{
char fullDirNameIn[100];
....
dirlist[dirAm] = fullDirNameIn;
}
The problem is that your array is scoped to the body of while loop but you are storing a pointer to that array outside the while loop. After you exit the body of the loop (i.e. when you iterate) then contents of your array become undefined, but you still have a pointer to it.
The solution is easy and this should be a lesson well learned. Don't use pointers, do what experienced programmers do and use std::string instead.
std::string dirlist[20];
while (...)
{
std::string fullDirNameIn;
....
dirlist[dirAm] = fullDirNameIn;
}

How to decode an animated gif File in MFC2010

Deal all,
I need to decode an animated gif format picture into some bitmap files in MFC2010. Is there any library to decode a gif picture? I cannot use GDIPlus because the program has to run on windows XP. I do appreciate if someone provides me with a library, Activex, dll or anything similar.
Many Thanks,
Shervin Zargham
It's pretty simple using ImageMagick's C++ API (Magick++) :
/* list of Image to store the GIF's frames */
std::vector<Magick::Image> imageList;
/* read all the frames of the animated GIF */
Magick::readImages( &imageList, "animated.gif" );
/* optionnally coalesce the frame sequence depending on the expected result */
Magick::coalesceImages( &imageList, imageList.begin(), imageList.end());
/* store each frame in a separate BMP file */
for(unsigned int i = 0; i < imageList.size(); ++i) {
std::stringstream ss;
ss << "frame" << i << ".bmp";
imageList[i].write(ss.str());
}
WIC (included in Vista, available for XP) offers CLSID_WICGifDecoder, a COM component.
Try this using ImageMagick's C++ API (Magick++) ,tested on VS210:
#include <Magick++.h>
#include <string>
#include <iostream>
#include <list>
using namespace std;
using namespace Magick;
void kk(char * nombre, char *ext)
{
/* list of Image to store the GIF's frames */
std::list<Magick::Image> imageList;
/* read all the frames of the animated GIF */
Magick::readImages( &imageList, nombre );
/* compone las diferencias para obtener los cuadros reales */
Magick::coalesceImages(&imageList,imageList.begin( ),imageList.end( ));
/* store each frame in a separate BMP file */
list <Magick::Image>::iterator it;
int i=1;
for ( it = imageList.begin( ); it != imageList.end( ); it++ , i++)
{
std::string name = "frame" + to_string((_Longlong)(i)) + ext ;
it->write(name);
}
}
int main( int /*argc*/, char ** argv)
{
// Initialize ImageMagick install location for Windows
InitializeMagick(*argv);
try {
kk("luni0.gif", ".png"); // using ".bmp", ".jpg", ".png", OK
return 0;
}
catch( exception &error_ )
{
cout << "Caught exception: " << error_.what() << endl;
return 1;
}
}
It's been a long time, but I recall once using OleLoadPicture to open GIF and PNG files on old versions of Windows, though the documentation seems to suggest that it's only for BMP, ICO, and WMF.

Object Marking in Haar training

I am doing a project on object detection in OpenCV using haar training. I have to mark, in an image, all the places where the object is present. So, I need a code which opens each image so that I can mark the regions.
Similar to the one here:
#include <opencv/cv.h>
#include <opencv/cvaux.h>
#include <opencv/highgui.h>
// for filelisting
#include <stdio.h>
#include <sys/io.h>
// for fileoutput
#include <string>
#include <fstream>
#include <sstream>
#include <dirent.h>
#include <sys/types.h>
using namespace std;
IplImage* image=0;
IplImage* image2=0;
//int start_roi=0;
int roi_x0=0;
int roi_y0=0;
int roi_x1=0;
int roi_y1=0;
int numOfRec=0;
int startDraw = 0;
char* window_name="<SPACE>add <B>save and load next <ESC>exit";
string IntToString(int num)
{
ostringstream myStream; //creates an ostringstream object
myStream << num << flush;
/*
* outputs the number into the string stream and then flushes
* the buffer (makes sure the output is put into the stream)
*/
return(myStream.str()); //returns the string form of the stringstream object
};
void on_mouse(int event,int x,int y,int flag, void *param)
{
if(event==CV_EVENT_LBUTTONDOWN)
{
if(!startDraw)
{
roi_x0=x;
roi_y0=y;
startDraw = 1;
} else {
roi_x1=x;
roi_y1=y;
startDraw = 0;
}
}
if(event==CV_EVENT_MOUSEMOVE && startDraw)
{
//redraw ROI selection
image2=cvCloneImage(image);
cvRectangle(image2,cvPoint(roi_x0,roi_y0),cvPoint(x,y),CV_RGB(255,0,255),1);
cvShowImage(window_name,image2);
cvReleaseImage(&image2);
}
}
int main(int argc, char** argv)
{
char iKey=0;
string strPrefix;
string strPostfix;
string input_directory;
string output_file;
if(argc != 3) {
fprintf(stderr, "%s output_info.txt raw/data/directory/\n", argv[0]);
return -1;
}
input_directory = argv[2];
output_file = argv[1];
/* Get a file listing of all files with in the input directory */
DIR *dir_p = opendir (input_directory.c_str());
struct dirent *dir_entry_p;
if(dir_p == NULL) {
fprintf(stderr, "Failed to open directory %s\n", input_directory.c_str());
return -1;
}
fprintf(stderr, "Object Marker: Input Directory: %s Output File: %s\n", input_directory.c_str(), output_file.c_str());
// init highgui
cvAddSearchPath(input_directory);
cvNamedWindow(window_name,1);
cvSetMouseCallback(window_name,on_mouse, NULL);
fprintf(stderr, "Opening directory...");
// init output of rectangles to the info file
ofstream output(output_file.c_str());
fprintf(stderr, "done.\n");
while((dir_entry_p = readdir(dir_p)) != NULL)
{
numOfRec=0;
if(strcmp(dir_entry_p->d_name, ""))
fprintf(stderr, "Examining file %s\n", dir_entry_p->d_name);
/* TODO: Assign postfix/prefix info */
strPostfix="";
//strPrefix=input_directory;
strPrefix=dir_entry_p->d_name;
//strPrefix+=bmp_file.name;
fprintf(stderr, "Loading image %s\n", strPrefix.c_str());
if((image=cvLoadImage(strPrefix.c_str(),1)) != 0)
{
// work on current image
do
{
cvShowImage(window_name,image);
// used cvWaitKey returns:
// <B>=66 save added rectangles and show next image
// <ESC>=27 exit program
// <Space>=32 add rectangle to current image
// any other key clears rectangle drawing only
iKey=cvWaitKey(0);
switch(iKey)
{
case 27:
cvReleaseImage(&image);
cvDestroyWindow(window_name);
return 0;
case 32:
numOfRec++;
printf(" %d. rect x=%d\ty=%d\tx2h=%d\ty2=%d\n",numOfRec,roi_x0,roi_y0,roi_x1,roi_y1);
//printf(" %d. rect x=%d\ty=%d\twidth=%d\theight=%d\n",numOfRec,roi_x1,roi_y1,roi_x0-roi_x1,roi_y0-roi_y1);
// currently two draw directions possible:
// from top left to bottom right or vice versa
if(roi_x0<roi_x1 && roi_y0<roi_y1)
{
printf(" %d. rect x=%d\ty=%d\twidth=%d\theight=%d\n",numOfRec,roi_x0,roi_y0,roi_x1-roi_x0,roi_y1-roi_y0);
// append rectangle coord to previous line content
strPostfix+=" "+IntToString(roi_x0)+" "+IntToString(roi_y0)+" "+IntToString(roi_x1-roi_x0)+" "+IntToString(roi_y1-roi_y0);
}
else
//(roi_x0>roi_x1 && roi_y0>roi_y1)
{
printf(" hello line no 154\n");
printf(" %d. rect x=%d\ty=%d\twidth=%d\theight=%d\n",numOfRec,roi_x1,roi_y1,roi_x0-roi_x1,roi_y0-roi_y1);
// append rectangle coord to previous line content
strPostfix+=" "+IntToString(roi_x1)+" "+IntToString(roi_y1)+" "+IntToString(roi_x0-roi_x1)+" "+IntToString (roi_y0-roi_y1);
}
break;
}
}
while(iKey!=66);
{
// save to info file as later used for HaarTraining:
// <rel_path>\bmp_file.name numOfRec x0 y0 width0 height0 x1 y1 width1 height1...
if(numOfRec>0 && iKey==66)
{
//append line
/* TODO: Store output information. */
output << strPrefix << " "<< numOfRec << strPostfix <<"\n";
cvReleaseImage(&image);
}
else
{
fprintf(stderr, "Failed to load image, %s\n", strPrefix.c_str());
}
}
}}
output.close();
cvDestroyWindow(window_name);
closedir(dir_p);
return 0;
}
I ran the above code using Visual Studio 10.
When I run the above code it is opening the command window loading all the images (a new named window is also getting opened but getting but it is not staying for me to select the region) and then closing.
When I ran it using start without debugging option in VS10 it is I could see this:
Examining file img (6).jpeg
Loading image img (6).jpeg
Examining file img (6).JPG
Loading image img (6).JPG
Examining file img (7).jpeg
Loading image img (7).jpeg
Examining file img (7).jpg
Loading image img (7).jpg
Examining file img (8).jpeg
Loading image img (8).jpeg
Examining file img (8).jpg
Loading image img (8).jpg
Examining file img (9).jpeg
Loading image img (9).jpeg
Examining file img (9).jpg
Loading image img (9).jpg
Examining file img 1.jpeg
Loading image img 1.jpeg
the object marker fails and cannot load the image
I think that it is skipping the:
if((image=cvLoadImage(strPrefix.c_str(),1)) != 0){.....}
part of the code
There are few currently available object marking tools for Haar training. I use the tool in this link. Its perfectly worked for me. If you want to build your own tool please follow this tutorial. Any way I think when it comes to Haar training, it is waste of time to develop tools to capture coordinates because there are currently available tools for those and it is not the main goal of Haar training. Because Haar training takes more time to train and create cascade XML file. So its better to focus on training.

How to delete all files in a folder, but not delete the folder using NIX standard libraries?

I am trying to create a program that deletes the contents of the /tmp folder, I am using C/C++ on linux.
system("exec rm -r /tmp")
deletes everything in the folder but it deletes the folder too which I dont want.
Is there any way to do this by some sort of bash script, called via system(); or is there a direct way i can do this in C/C++?
My question is similar to this one, but im not on OS X... how to delete all files in a folder, but not the folder itself?
#include <stdio.h>
#include <dirent.h>
int main()
{
// These are data types defined in the "dirent" header
DIR *theFolder = opendir("path/of/folder");
struct dirent *next_file;
char filepath[256];
while ( (next_file = readdir(theFolder)) != NULL )
{
// build the path for each file in the folder
sprintf(filepath, "%s/%s", "path/of/folder", next_file->d_name);
remove(filepath);
}
closedir(theFolder);
return 0;
}
You don't want to spawn a new shell via system() or something like that - that's a lot of overhead to do something very simple and it makes unnecessary assumptions (and dependencies) about what's available on the system.
In C/C++, you could do:
system("exec rm -r /tmp/*")
In Bash, you could do:
rm -r /tmp/*
This will delete everything inside /tmp, but not /tmp itself.
you can do
system("exec find /tmp -mindepth 1 -exec rm {} ';'");
by using use the wildcard * character you can delete all the files with any type of extension.
system("exec rm -r /tmp/*")
In C/C++ you can use (including hidden directories):
system("rm -r /tmp/* /tmp/.*");
system("find /tmp -mindepth 1 -delete");
But what if 'rm' or 'find' utilities are not availabe to sh?, better go 'ftw' and 'remove':
#define _XOPEN_SOURCE 500
#include <ftw.h>
static int remove_cb(const char *fpath, const struct stat *sb, int typeFlag, struct FTW *ftwbuf)
{
if (ftwbuf->level)
remove(fpath);
return 0;
}
int main(void)
{
nftw("./dir", remove_cb, 10, FTW_DEPTH);
return 0;
}
I realize this is very old question, but building on Demitri's great answer I created a function that will recursively delete files in subfolders if desired
It also does some error handling, in that it passes back errno. The function header is written for parsing by doxygen. This function works in the simple example cases I used, and deletes hidden folders and hidden files.
I hope this helps someone else in the future
#include <stdio.h>
#include <dirent.h>
#include <sys/stat.h>
#define SUCCESS_STAT 0
/**
* checks if a specific directory exists
* #param dir_path the path to check
* #return if the path exists
*/
bool dirExists(std::string dir_path)
{
struct stat sb;
if (stat(dir_path.c_str(), &sb) == 0 && S_ISDIR(sb.st_mode))
return true;
else
return false;
}
/**
* deletes all the files in a folder (but not the folder itself). optionally
* this can traverse subfolders and delete all contents when recursive is true
* #param dirpath the directory to delete the contents of (can be full or
* relative path)
* #param recursive true = delete all files/folders in all subfolders
* false = delete only files in toplevel dir
* #return SUCCESS_STAT on success
* errno on failure, values can be from unlink or rmdir
* #note this does NOT delete the named directory, only its contents
*/
int DeleteFilesInDirectory(std::string dirpath, bool recursive)
{
if (dirpath.empty())
return SUCCESS_STAT;
DIR *theFolder = opendir(dirpath.c_str());
struct dirent *next_file;
char filepath[1024];
int ret_val;
if (theFolder == NULL)
return errno;
while ( (next_file = readdir(theFolder)) != NULL )
{
// build the path for each file in the folder
sprintf(filepath, "%s/%s", dirpath.c_str(), next_file->d_name);
//we don't want to process the pointer to "this" or "parent" directory
if ((strcmp(next_file->d_name,"..") == 0) ||
(strcmp(next_file->d_name,"." ) == 0) )
{
continue;
}
//dirExists will check if the "filepath" is a directory
if (dirExists(filepath))
{
if (!recursive)
//if we aren't recursively deleting in subfolders, skip this dir
continue;
ret_val = DeleteFilesInDirectory(filepath, recursive);
if (ret_val != SUCCESS_STAT)
{
closedir(theFolder);
return ret_val;
}
}
ret_val = remove(filepath);
//ENOENT occurs when i folder is empty, or is a dangling link, in
//which case we will say it was a success because the file is gone
if (ret_val != SUCCESS_STAT && ret_val != ENOENT)
{
closedir(theFolder);
return ret_val;
}
}
closedir(theFolder);
return SUCCESS_STAT;
}
You could use nftw(3). First, make a pass to collect the set of file paths to remove. Then use unlink (for non-directories) and rmdir(2) in a second pass
From C++17 onwards you can use std::filesystem. The code below will use directory_iterator to list all the files and subdirectories in a directory and call remove_all to delete them:
#include <filesystem>
namespace fs = std::filesystem;
void delete_dir_content(const fs::path& dir_path) {
for (auto& path: fs::directory_iterator(dir_path)) {
fs::remove_all(path);
}
}
Note that this will throw a filesystem_error exception on underlying OS API errors. You can avoid this with:
void delete_dir_content(const fs::path& dir_path) {
for (auto& path: fs::directory_iterator(dir_path)) {
std::error_code err;
std::uintmax_t n = fs::remove_all(path, err);
if (static_cast<std::uintmax_t>(-1) == n) {
std::cout << "Failed to remove_all(" << path << ") with error: " << err.message() << std::endl;
}
}
}

how to search the computer for files and folders

i need a way to search the computer for files like Windows Explorer. i want my program to search lets say hard drive c:. i need it to search C:\ for folders and files (just the ones you could see in c:\ then if the user clicks on a file on the list like the folder test (C:\test) it would search test and let the user see what files/folders are in it.
Since you mentioned windows, the most straight forward winapi way to do it is with FindFirstFile and FindNextFile functions.
edit: Here's an example that shows you how to enumerate all files/folders in a directory.
#include <Windows.h>
#include <iostream>
int main()
{
WIN32_FIND_DATA file;
HANDLE search_handle=FindFirstFile(L"C:\\*",&file);
if (search_handle)
{
do
{
std::wcout << file.cFileName << std::endl;
}while(FindNextFile(search_handle,&file));
FindClose(search_handle);
}
}
This will be OS dependent. The SO question
How can I get a list of files in a directory using C or C++?
handles this problem well. You can download DIRENT here.
Now that you have this, I'd recommend recursively searching for a file with a DFS/BFS algorithm. You can assume the whole directory structure is a tree where each file is a leaf node and each subdirectory is an internal node.
So all you have to do is,
Get the list of files/folders in a directory with a function such as:
void getFilesFolders(vector<string> & dir_list, const string & folder_name)
If it's a directory, go to 1 with the directory name
If it's a file, terminate if it's the file you're looking for, else move on to the next file.
boost::filesystem can be a cross-platform solution for that (check out for such functions in it).
You can use Directory class members to do this with C# or managed C++. See the following MSDN article:
http://support.microsoft.com/kb/307009
If you wish to use C++ with MFC you can use CFileFind
http://msdn.microsoft.com/en-us/library/f33e1618%28v=VS.80%29.aspx
You'll have to supply your own browse window to present the file system tree.
Or you can use one of the directory/file controls to do both for you.
#include <Windows.h>
#include <iostream>
int FindF(char* pDirectory)
{
char szFindPath[MAX_PATH] = {0};
strcpy(szFindPath, pDirectory);
strcat(szFindPath, "\\*");
WIN32_FIND_DATA file;
HANDLE search_handle=FindFirstFile(szFindPath,&file);
if (search_handle)
{
do
{
if(file.dwFileAttributes == FILE_ATTRIBUTE_DIRECTORY)
{
strcpy(szFindPath, pDirectory);
strcat(szFindPath, "\\");
strcat(szFindPath, file.cFileName);
FindF(szFindPath);
}
std::wcout << file.cFileName << std::endl;
}while(FindNextFile(search_handle,&file));
CloseHandle(search_handle);
}
}
There really is no need to use 3rd party library to accomplish this. This is a short, independent function which lists all files (with their paths) in a directory, including subdiretories' files. std::string folderName has to finish with \, and if you want to list all files on computer, just create a loop in calling function along with GetLogicalDriveStrings (It returns strings with \, so it couldn't be more convenient in this case).
void FindAllFiles(std::string folderName)
{
WIN32_FIND_DATA FileData;
std::string folderNameWithSt = folderName + "*";
HANDLE FirstFile = FindFirstFile(folderNameWithSt.c_str(), &FileData);
if (FirstFile != INVALID_HANDLE_VALUE) {
do {
if (strcmp(FileData.cFileName, ".") != 0 && strcmp(FileData.cFileName, "..") != 0)
{
if(FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
{
std::string NewPath = folderName + FileData.cFileName;
NewPath = NewPath + "\\";
FindAllFiles(NewPath);
}
else
{
std::cout /*<< folderName*/ << FileData.cFileName << std::endl;
}
}
} while(FindNextFile(FirstFile, &FileData));
}
}
This is ASCII version, remember that files and folders can be named in Unicode