System() from c++ does not execute ImageMagick command correctly - c++

As a part of my studies I am working on a command line tool to compute distortions on images. Currently, I am facing following problem:
I want to call an ImageMagick command via system(). The output I get is following:
convert: command not found.
However, calling the exactly same function directly on the terminal works perfectly.
The command I am calling is
convert building.jpg -matte -virtual-pixel transparent \
-distort Perspective \
'7,40 4,30 4,124 4,123 85,122 100,123 85,2 100,30' \
building_pers.png
From http://www.imagemagick.org/Usage/distorts/#perspective_projection
Of course the name of the image is different, this is just an example:
My code is the following:
int main(int argc, const char * argv[]) {
enterPoints();
std::string cmd;
cmd = create_cmd_l1();
cmd += create_cmd_l2();
cmd += create_cmd_l3();
cmd += create_cmd_l4();
system(cmd.c_str());
return 0;
}
The method enterPoints() just collects the reference points, there is no problem with this part.
The create_cmd-commands create the 4 lines of the whole ImageMagick-command.
Calling all lines separately produces the same error:
system(create_cmd_l1().c_str());
system(create_cmd_l2().c_str());
system(create_cmd_l3().c_str());
system(create_cmd_l4().c_str());

Related

Bash autocomplete an option without running the application

I have found this code as a bash autocomplete. But, it looks strange to me. What if I do not like to run the code at all. If I would like to type ./a.out then space (without entering) and then by pressing tab, I would like to see only two options apple and cherry and if I type a and press tab, then it autocomplete the option apple and similarly for c. Let's say only one of the two options are acceptable:
./a.out apple
./a.out cherry
where apple and cherry are options and not the name of the files in the directory. In the first case, I would like the program types that your option is apple and in the second case your option is cherry. In any other case, the program should print an error that the option is not valid.
All examples that I find on the internet such as what follows look like that you should run the program first, then it reacts. The while loop inside the main function collides with the normal functionality of the program. Have I misunderstood the readline library? Is the above-described application possible to implement by editing the following code?
// sudo apt-get install libreadline-dev
// g++ -std=c++11 main.cpp -lreadline
#include <iostream>
#include "readline/readline.h"
#include "readline/history.h"
using namespace std;
int main(int argc, char** argv)
{
const char *line;
while ((line = readline("? ")) != nullptr) {
cout << "[" << line << "]" << endl;
if (*line) add_history(line);
free(line);
}
// if(argc!=2)
// {
// cout<<"<exe> one_parameter"<<endl;
// return 1;
// }
// string option=argv[1];
// if(option=="apple" || option=="cherry")
// cout<<"Your option is "<<option<<endl;
// else
// {
// cout<<"Error: invalid option "<<option<<endl;
// return 1;
// }
return 0;
}
// partial answer - why you may want to invoke the app while doing the autocompletion
One way of implementing the autocomplete for an application is to have the application binary configure it (by having a flag that prints the instructions for autocomplete configuration or by just parsing the --help output of the application).
Schemataically:
complete -F $(./a.out --generate-autocomplete-config) ./a.out
This is why you might see the binary actually invoked as a part of autocomplete implementation.
This has nothing to do with your executable. You need to put this in a file and source (source autocomplete_file or . autocomplete_file) it in the bash.
_a_complete_()
{
local word=${COMP_WORDS[COMP_CWORD]}
local files='apple cherry'
COMPREPLY=( $( compgen -W "${files}" -- ${word} ) )
}
complete -F _a_complete_ ./a.out
Here a nice documentation can be found.

Issue with calling ggplot using R_tryEval

I am trying to build a system allowing to execute arbitrary R code from a C++ application.
In orded to achieve that, the core of the method follows what is described here: http://www.hep.by/gnu/r-patched/r-exts/R-exts_121.html
This worked fine for any R code so far. However, I encoutered an issue with using ggplot. I try to send ggplot resulting graph to a png file. It works fine if done directly in a R console, but when I use my C++ interface, the resulting file is empty.
More precisely, the R code is organized as follows:
Load library ggplot2
Define some dummy data to be plotted.
Call png to create a graphics device.
Call ggplot.
Call dev.off() to close the graphics device.
When reduced to a minimal case, here is my code:
#include <QDebug>
#include <Rembedded.h>
#include <Rinternals.h>
#include <R_ext/Parse.h>
int main(int argc, char *argv[])
{
const char *argvrf[] = {"RConsole"};
int argcrf = sizeof(argvrf) / sizeof(argvrf[0]);
Rf_initEmbeddedR(argcrf, (char**)argvrf);
// Create some dummy data for a ggplot.
// For the purpose of this minimal example, R code is just directly defined as a QString here.
QString RScript = "library(\"ggplot2\") \n" ;
RScript += "id<-c(1,2,3,4,5) \n" ;
RScript += "names<-c(\"A\",\"B\",\"C\",\"D\",\"E\") \n" ;
RScript += "notes<-c(12,20,13,15,10) \n" ;
RScript += "df1<-data.frame(id,names,notes) \n" ;
// Define a file as graphicsDevice (adapt adress to your own filesystem)
RScript += "png(\"C:/Users/Evain/Desktop/tests/testggplot.png\", width=480, height=480, res=72) \n" ;
// Drawing the ggplot.
RScript += "ggplot(data=df1,aes(x=id,y=notes))+geom_line() \n" ;
// Closing the graphic device.
RScript += "dev.off() \n" ;
ParseStatus status;
SEXP cmdSexp, cmdexpr = R_NilValue;
int i, errorOccurred, retVal=0;
// Convert the command line to SEXP
PROTECT(cmdSexp = Rf_allocVector(STRSXP, 1));
SET_STRING_ELT(cmdSexp, 0, Rf_mkChar(RScript.toLocal8Bit().data()));
cmdexpr = PROTECT(R_ParseVector(cmdSexp, -1, &status, R_NilValue));
switch (status){
case PARSE_OK: {
// Loop is needed here as EXPSEXP might be of length > 1
for(i = 0; ((i < Rf_length(cmdexpr)) && (retVal==0)); i++){
R_tryEval(VECTOR_ELT(cmdexpr, i), R_GlobalEnv, &errorOccurred);
if (errorOccurred) {
// Interrupt process.
qDebug() << "Error occured" ;
retVal = -1;
}
}
break ;
}
default: {
qDebug() << "Incorrect R command" ;
break;
}
}
return 0;
}
Communication with R works fine if it is not a ggplot. For example, if I replace the
RScript += "ggplot(data=df1,aes(x=id,y=notes))+geom_line() \n" ;
With:
RScript += "plot(3) \n";
Then it works fine, a png file is create with the required plot.
With ggplot, this code runs without apparent issue. The qDebug() messages are not triggered. The png file is even created (meaning that the call to png() is executed correctly). But the file is empty.
It is not just an issue with the combination of png() and ggplot() or with my dummy data, since if I just launch the following R script in a R console, I get the expected result (the file is created and contains the plot):
library("ggplot2")
id<-c(1,2,3,4,5)
names<-c("A","B","C","D","E")
notes<-c(12,20,13,15,10)
df1<-data.frame(id,names,notes)
png("C:/Users/Evain/Desktop/tests/testggplot.png", width=480, height=480, res=72)
ggplot(data=df1,aes(x=id,y=notes))+geom_line()
dev.off()
Note: I'm on Windows 10, using R3.4.3.
It is worth noting that the png() method behaves slightly differently on Linux. For windows, the file is created when png() is called, even if it has to remain empty. For Linux, the file wouldn't be created if nothing is written in it.
If the png file already exist, it also gets replaced by an empty one. That's what we should expect when calling png() alone. It's just that the ggplot doesn't get added to it.
It feels like combining R_tryEval() with png() works fine. Combining png() with ggplot works fine, but combining R_tryEval() with png() and ggplot() doesn't. Any idea ?

running same script for 2 different files (input & output) ??? /ROOT/C++

I have a script that reads a tree and creates some plots.
I have two files I need to run, so I need to run the same script once for file1 and once for file2, storing results in a different output file each time.
How can I tell my program what file to run each time and where to save the results?
file1 is: flatTree_jetHT
outputfile1 is: flatTree_JetHT_output.root
file2 is: flatTree_jetHT2
outputfile2 is: flatTree_JetHT2_output.root
I need to write this down using just one void and telling which file to run from terminal (.x flatTree_jetHt_read.C)
Here is my code:
#include <iostream>
void flatTree_jetHT_read()
{
gROOT->Reset();
gROOT->SetStyle("Plain");
gStyle->SetOptStat(1);
gStyle->SetOptFit(0);
gStyle->SetPadColor(0);
gStyle->SetPalette(1);
TFile *f = TFile::Open("flatTree_JetHT.root", "READ");
TTree *tree = (TTree*)f->Get("boosted/events");
TFile *outf = TFile::Open("flatTree_JetHT_output.root", "RECREATE");
//more code....
}
Have you tried just passing the input/output as arguments of the function? (see the Getting Started section of the user guide).
void two_args(const char* input_file, const char* output_file)
{
printf("Input: '%s'\n", input_file);
printf("Output: '%s'\n", output_file);
}
then run as
$ root -l -x -q '/tmp/two_args.C+("in.root", "out.root")'

Run a command line with c++

I have read several posts about running a command line in c++, but none of them does what I want : no display of the console in an external application when I use the dllfile.
My problem : I want to use a process that picks files from a database. For example : to get a file XYZ.xyz and copy it to the directory MyDirXYZ, I would use the command line
"MyDataGenerator XYZ.xyz C:\MyDirXYZ".
I use Visual studio
Let 's take the following example to clarify the issue, I am trying to create a directory with "mkdir" in C++ , without using CreateDirectory :
First method :
std::string lDirectory("c:\\MyDummyDir")
std::string lCmd("mkdir " + lDirectory);
system((lCmd).c_str());
It will work , however it displays the console when I run it with a dllfile on Excel .
Second Method ( convertToRightFormat() convert a char to a TChar)
std::string lDirectory("c:\\MyDummyDir")
std::string lCmd("mkdir " + lDirectory);
BOOL _status = TRUE;
DWORD _reply, _code;
STARTUPINFO _si = { sizeof(_si) };
PROCESS_INFORMATION _pi;
TCHAR *_cmd = NULL;
_cmd=convertToRightFormat(lCmd.c_str())
_status &= CreateProcess(NULL, _cmd, NULL, NULL, FALSE, CREATE_NO_WINDOW, NULL, NULL, &_si, &_pi);
This method does not work(not even creating the folder) , and obviously it does not work either for the process "MyDataGenerator".
I tried to use the executable MKDIR.EXE and put it in the commandline. In that case, it works , but still does not work for MyDataGenerator.
Is there a generic to make all command lines work, without showing the console?
Thanks you.
#include <Windows.h> // FreeConsole, system
int main(int argc, char* argv[])
{
system("mkdir newdirectoryname");
FreeConsole();
}
This will result in cmd popping up for a split second though. It closes after that.
If thats not acceptable just target the windows subsystem instead of the console one and make sure to not draw the window.

rosrun via ssh doesnt start a node properly

We are working with ros and try to run a node via SSH in a shell script.
We have an controlling (master) computer on which we execute the script with the following line:
ssh user#xxx.xxx.x.x -x "/bin/bash -c 'source /etc/profile; rosrun stargazer_alter stargazer_node'"
The node is getting started (it occurs in "rosnode list" and the node is also listed as a publisher in "rostopic info") but the main method seems not to be executed (neither any print lines show up nor any messages were published).
#include "Stargazer_listener.h"
enum STATES {config, readData};
int main(int argc, char** argv) {
ROS_INFO("Test!!!! Stargazer starts!");
ros::init(argc, argv, "stargazer_node");
Stargazer_listener starG;
int iFd = 0;
char *rec_msg = (char*)malloc(BUFFSIZE * sizeof(char));
iFd = starG.portSetup();
STATES STATE = config;
while(ros::ok()) {
switch(STATE) {
case config:
starG.cmd(iFd, rec_msg, "~#CalcStop`");
printf("CalcStop\n");
starG.cmd(iFd, rec_msg, "~#CalcStart`");
printf("CalcStart\n");
STATE = readData;
break;
case readData:
starG.publish_data(iFd, rec_msg);
break;
}
}
free(rec_msg);
return 0;
}
The line "starG.portSetup()" opens the ttyUSB0 port which is not used by other processes.
The stargazer_node is getting compiled via catkin_make. According to the code, the first thing to happen should be the following print line: "ROS_INFO("Test!!!! Stargazer starts!");".
Which doesnt happen!
The same shell script command did work fine with other nodes. If we add the node to a ros ".launch" file, the same thing happens.
If I connect via ssh in a terminal (ssh user#xxx.xxx.x.x) and then run the same line (rosrun stargazer_alter stargazer_node) everything works fine!