Create GUI with "Select file" dialog in cpp, OpenCV - c++

is there any way to enable user to select file manually using GUI in my cpp console application with OpenCV? I've made some research but found no solution for such trivial task so far...
Thanks in advance,
JP

For this, you have to add any available gui library and handle the gui part with that keeping the image processing part to opnecv. ( For example, you can try Qt )

If you want to a simple file open dialog in Ubuntu, you can do this:
FILE *in;
if (!(in = popen(
"zenity --title=\"Select an image\" --file-selection",
"r"))) {
return 1;
}
char buff[512];
string selectFile = "";
while (fgets(buff, sizeof(buff), in) != NULL) {
selectFile += buff;
}
pclose(in);
//remove the "\n"
selectFile.erase(std::remove(selectFile.begin(), selectFile.end(), '\n'),
selectFile.end());
// path + filename + format
Mat image = imread(selectFile);

Related

fopen / ofstream::open fail when creating a BMP file

Years ago I created a C++ function using FILE to create bitmap files. Recently (not sure when or why) this code is now failing when opening the file. The problem is with the open call ...
file_ptr = fopen("ScreenShots/Screenshot1.bmp", "wb");
Currently this results in an error 13, permission denied error. Change the filename extension to something else and the fopen works fine. For example,
file_ptr = fopen("ScreenShots/Screenshot1.bm2", "wb");
The file saves correctly and when changing the extension back to BMP I can display the file correctly in Paintshop.
Did a quick check using ofstream and same problem.
Any ideas why I get a permission denied error when trying to open BMP files to write data? For information I am using Visual Studio Community 2017 on Windows 10.
To give the complete section of code ...
BITMAPFILEHEADER bitmap_header;
BITMAPINFOHEADER bitmap_info;
FILE *file_ptr;
unsigned int count;
unsigned char tempRGB;
char filename[256];
bool finished;
// CREATE A UNIQUE FILENAME
count = 1;
finished = false;
do
{
// CREATE NAME
sprintf(filename, "ScreenShots/Screenshot%d.bmp", count);
// CHECK IF FILE EXISTS
errno = 0;
file_ptr = fopen(filename, "rb");
if (file_ptr)
{
// FILE EXISTS
fclose(file_ptr);
count = count + 1;
}
else
{
// UNIQUE FILENAME
file_ptr = fopen(filename, "wb");
if (file_ptr == NULL)
{
// UNABLE TO OPEN FOR WRITING - GIVE UP
// (USING OWN LOGGING CLASS)
jalog.log("\nERROR on Screenshot >");
jalog.log(filename);
jalog.log("< >");
jalog.log((short)errno);
return;
}
finished = true;
}
}
while (finished == false);
I've managed to find the issue ... Avast antivirus. I noticed that trying to do an open action for a BMP file took a few seconds while opening any other file type (successfully or unsuccessfully) was instantaneous. As something similar happens when running new programs I tried disabling all the Avast shields and I could successfully create a BMP file using the existing code.
For my own personal use I can whitelist my own programs, but annoying if I get to distributing the program to other people.
Thanks for the help ... and sorry for raising a C++ issue that in the end had nothing to do with C++!

wofstream only creates an empty file c++

I have a for loop (below) that should output several strings to several files using wofstream. Unfortunately, it creates the file but does not output the string to the file. The files are always empty. I've looked through a lot of similar questions with no luck. Any help would be greatly appreciated. I'm on a Windows 10 machine using Visual Studio 2015 to write a UWP app.
for (size_t k=0;k < vctSchedulesToReturn.size();k++)
{
auto platformPath = Windows::Storage::ApplicationData::Current->RoamingFolder->Path;
std::wstring wstrplatformPath = platformPath->Data();
std::wstring wstrPlatformPathAndFilename = wstrplatformPath + L"\\" + availabilityData.month + L"_" + std::to_wstring(availabilityData.year) + L"_" + std::to_wstring(k) + L"_" + L"AlertScheduleOut.csv";
std::string convertedPlatformPathandFilename(wstrPlatformPathAndFilename.begin(), wstrPlatformPathAndFilename.end());
std::wofstream outFile(convertedPlatformPathandFilename);
outFile.open(convertedPlatformPathandFilename);
std::vector<std::pair<wstring, wstring>>::iterator pairItr;
std::wstring strScheduleOutputString = L"";
for (pairItr = vctSchedulesToReturn[k].second.begin(); pairItr!=vctSchedulesToReturn[k].second.end(); pairItr++)
{
strScheduleOutputString += pairItr->first + L",";
}
strScheduleOutputString += L"\r\n";
for (pairItr = vctSchedulesToReturn[k].second.begin(); pairItr != vctSchedulesToReturn[k].second.end(); pairItr++)
{
strScheduleOutputString += pairItr->second + L",";
}
outFile << strScheduleOutputString;
outFile.flush();
outFile.close();
}
std::wofstream outFile(convertedPlatformPathandFilename);
This creates a new file, and opens it for writing.
outFile.open(convertedPlatformPathandFilename);
This attempts to open the same file stream for writing a second time. Because the file stream is already open, this is an error. The error sets the stream into a failed state, and all attempts to write to the stream will now fail.
This is how you end up with an empty output file. It gets created, and a duplicate, second attempt to open the same file stream object puts it into error state.

Get Gnuplot version from pipe in C++

In my C++ program (in linux), I can open a pipe for writing and set values for Gnuplot program.
FILE *pipe = NULL;
#ifdef WIN32
pipe = _popen("pgnuplot -persist", "w");
#else
pipe = popen("gnuplot", "w");
#endif
if(pipe == NULL)
error("Could not open pipe for write!");
// set title name
fprintf(pipe, "set title 'Sample Points' \n");
Now I need to get the Gnuplot version. The show version command does this but how I can send this command and then read the value. Opening a pipe for reading seems to not work for me and the code stuck in the while loop without getting any data.
FILE* pipe = popen(command, "r");
if (!pipe)
{
std::cout << "failed! (can not open pipe)" << endl;
return;
}
char buffer[128];
std::string result = "";
while(!feof(pipe))
{
if(fgets(buffer, 128, pipe) != NULL)
result += buffer;
}
pclose(pipe);
Since on my Debian/Linux/Sid/x86-64 the command gnuplot --version is outputting to stdout the following line:
gnuplot 5.0 patchlevel 1
I would simply recommend
FILE* pipversion = popen("gnuplot --version", "r");
if (!pipversion) { perror("popen gnuplot"); exit(EXIT_FAILURE); };
char lineversion[128];
memset (lineversion, 0, sizeof(lineversion));
if (!fgets(lineversion, sizeof(lineversion), pipversion) {
perror("fgets"); exit(EXIT_FAILURE);
}
/// lineversion is like: gnuplot 5.0 patchlevel 1
int majvers=0, minvers=0, pos= -1;
char* restvers = NULL;
if (sscanf(lineversion, "gnuplot %d.%d %n", &majvers, &minvers, &pos) >= 2) {
assert (pos>=0);
restvers = lineversion+pos;
};
pclose(pipversion);
pipversion = NULL;
After that, majvers contains the major version of gnuplot (e.g. 5 in my case) and minvers contains the minor version (e.g. 0), with restvers being a suffix string (e.g. "patchlevel 1" without the quotes).
There might be a potential race condition in the unusual and unlikely case that gnuplot is updated between this popen and the next one pipe = popen("gnuplot", "w");. BTW, naming a variable pipe is poor taste, since POSIX and Linux have the pipe(2) system call. But I don't think it is worth caring about that race condition.
BTW, you very probably want to replace your second pipe = popen("gnuplot", "w"); with an explicit double invocation of pipe(2) (followed by appropriate fork(2) & execvp(3) ...) to have both input and output pipes to gnuplot, and manage them in your own event loop (probably around poll(2) ... see this & that answers).
(if you application has or uses its own event loop, in particular if it is a GUI application above Qt or GTK, you want to use the same event loop for the pipes; details are specific to the library providing that event loop: g_spawn_async_with_pipes & g_source_add_unix_fd for GTK, QProcess for Qt ... )
I don't have time to explain how to do that (double piping into command + event loop) in details, but the Advanced Linux Programming book (available online) has several chapters on that. Be aware that you need some event loop.

Call HPDF_SaveToFile() with japanese filename

Im trying to save one pdf in path that contains japanese username. In this case, HPDF_SaveToFile is doing crash my app on windows. Any options to compile or other thing? Any idea to support Unicode filenames with libhaur? I not want to create pdf with japanese encode, I want to write pdf with japanese filename.
A solution in Qt. If you use C++, you can use fstream/ofstream(::write). If you use C, you can use fwrite.
QFile file(path);
if (file.open(QIODevice::WriteOnly))
{
HPDF_SaveToStream(m_pdf);
/* get the data from the stream and write it to file. */
for (;;)
{
HPDF_BYTE buf[4096];
HPDF_UINT32 siz = 4096;
HPDF_STATUS ret = HPDF_ReadFromStream(m_pdf, buf, &siz);
if (siz == 0)
{
break;
}
if (-1 == file.write(reinterpret_cast<const char *>(buf), siz))
{
qDebug() << "Write PDF error";
break;
}
}
}
HPDF_Free(m_pdf);
Refrence: Libharu Usage examples

Move files to Trash/Recycle Bin in Qt

Is there a Qt function to move files to Recycle Bin instead of truly deleting them, for OSes that support it, or do I need to use OS-specific code?
Since Qt 5.15.0 Alpha, this method has been added, which should be what you were looking for.
bool QFile::moveToTrash()
The corresponding code changes can be found here.
(This issue is old and the corresponding Bugreport at https://bugreports.qt.io/browse/QTBUG-47703 has already been posted, but I currently lack the reputation to comment, and found this to be a useful information.)
Qt doesnt provide a MoveToTrash. Here's a part of my code
for Windows
#ifdef Q_OS_WIN32
#include "windows.h"
void MoveToTrashImpl( QString file ){
QFileInfo fileinfo( file );
if( !fileinfo.exists() )
throw OdtCore::Exception( "File doesnt exists, cant move to trash" );
WCHAR from[ MAX_PATH ];
memset( from, 0, sizeof( from ));
int l = fileinfo.absoluteFilePath().toWCharArray( from );
Q_ASSERT( 0 <= l && l < MAX_PATH );
from[ l ] = '\0';
SHFILEOPSTRUCT fileop;
memset( &fileop, 0, sizeof( fileop ) );
fileop.wFunc = FO_DELETE;
fileop.pFrom = from;
fileop.fFlags = FOF_ALLOWUNDO | FOF_NOCONFIRMATION | FOF_NOERRORUI | FOF_SILENT;
int rv = SHFileOperation( &fileop );
if( 0 != rv ){
qDebug() << rv << QString::number( rv ).toInt( 0, 8 );
throw OdtCore::Exception( "move to trash failed" );
}
}
#endif
and for Linux
#ifdef Q_OS_LINUX
bool TrashInitialized = false;
QString TrashPath;
QString TrashPathInfo;
QString TrashPathFiles;
void MoveToTrashImpl( QString file ){
#ifdef QT_GUI_LIB
if( !TrashInitialized ){
QStringList paths;
const char* xdg_data_home = getenv( "XDG_DATA_HOME" );
if( xdg_data_home ){
qDebug() << "XDG_DATA_HOME not yet tested";
QString xdgTrash( xdg_data_home );
paths.append( xdgTrash + "/Trash" );
}
QString home = QStandardPaths::writableLocation( QStandardPaths::HomeLocation );
paths.append( home + "/.local/share/Trash" );
paths.append( home + "/.trash" );
foreach( QString path, paths ){
if( TrashPath.isEmpty() ){
QDir dir( path );
if( dir.exists() ){
TrashPath = path;
}
}
}
if( TrashPath.isEmpty() )
throw Exception( "Cant detect trash folder" );
TrashPathInfo = TrashPath + "/info";
TrashPathFiles = TrashPath + "/files";
if( !QDir( TrashPathInfo ).exists() || !QDir( TrashPathFiles ).exists() )
throw Exception( "Trash doesnt looks like FreeDesktop.org Trash specification" );
TrashInitialized = true;
}
QFileInfo original( file );
if( !original.exists() )
throw Exception( "File doesnt exists, cant move to trash" );
QString info;
info += "[Trash Info]\nPath=";
info += original.absoluteFilePath();
info += "\nDeletionDate=";
info += QDateTime::currentDateTime().toString("yyyy-MM-ddThh:mm:ss.zzzZ");
info += "\n";
QString trashname = original.fileName();
QString infopath = TrashPathInfo + "/" + trashname + ".trashinfo";
QString filepath = TrashPathFiles + "/" + trashname;
int nr = 1;
while( QFileInfo( infopath ).exists() || QFileInfo( filepath ).exists() ){
nr++;
trashname = original.baseName() + "." + QString::number( nr );
if( !original.completeSuffix().isEmpty() ){
trashname += QString( "." ) + original.completeSuffix();
}
infopath = TrashPathInfo + "/" + trashname + ".trashinfo";
filepath = TrashPathFiles + "/" + trashname;
}
QDir dir;
if( !dir.rename( original.absoluteFilePath(), filepath ) ){
throw Exception( "move to trash failed" );
}
File infofile;
infofile.createUtf8( infopath, info );
#else
Q_UNUSED( file );
throw Exception( "Trash in server-mode not supported" );
#endif
}
#endif
There is no API yet.
https://bugreports.qt.io/browse/QTBUG-181
The issue is closed and the fix version is: Some future release
Edit: A new issue has been opened at https://bugreports.qt.io/browse/QTBUG-47703.
Edit Apparently it is now done in 5.15.0 Alpha bool QFile::moveToTrash()
I think that there is no cross-platform way. Simple moving files to "trash" location will not give effect, because user may switch off this possibility.
Maybe, this url will help: http://www.hardcoded.net/articles/send-files-to-trash-on-all-platforms.htm
I'm relatively certain that there is no Qt API that wraps this for all supported platforms. That means, unfortunately, that you will have to write platform-specific code.
I don't know anything about where/how Linux distributions store deleted files, and I imagine that it probably varies depending on which file manager you're using. I believe that moving files to a ~/.Trash folder is the standard way of doing it, but I'm not sure if this is reliable. For example, in the case of files stored on external volumes.
Things are a bit easier on Mac OS X, where there is a supported API to do this: FSMoveObjectToTrashSync, provided by Core Services. At least, that's how I remember you're supposed to do it. The documentation claims that this method is now deprecated in OS X 10.8. I have no idea what the recommended alternative is.
As a Windows programmer, I think that platform is much easier. :-) The basic solution is to call the SHFileOperation function:
#include <Windows.h> // general Windows header file
#include <ShellAPI.h> // for shell functions, like SHFileOperation
#include <string> // (or use QString)
void RecycleFileOnWindows()
{
std::wstring path = L"C:\\Users\\Administrator\\Documents\\deleteme.txt";
path.append(1, L'\0'); // path string must be double nul-terminated
SHFILEOPSTRUCT shfos = {};
shfos.hwnd = nullptr; // handle to window that will own generated windows, if applicable
shfos.wFunc = FO_DELETE;
shfos.pFrom = path.c_str();
shfos.pTo = nullptr; // not used for deletion operations
shfos.fFlags = FOF_ALLOWUNDO; // use the recycle bin
const int retVal = SHFileOperation(&shfos);
if (retVal != 0)
{
// The operation failed...
if (shfos.fAnyOperationsAborted)
{
// ...but that's because the user canceled.
MessageBox(nullptr, L"Operation was canceled", nullptr, MB_OK | MB_ICONINFORMATION);
}
else
{
// ...for one of the other reasons given in the documentation.
MessageBox(nullptr, L"Operation failed", nullptr, MB_OK | MB_ICONERROR);
}
}
}
There are also flags that you can set to customize confirmation, error reporting, and other behavior. The linked documentation contains all the details you need to build upon this basic example.
On Windows Vista and later, the SHFileOperation function has been superseded by the methods provided by the IFileOperation interface. If you're targeting only these later versions of Windows, you should prefer to use this interface. Otherwise, SHFileOperation will continue to work fine.
if(QSysInfo::kernelType()=="linux")
{
QDateTime currentTime(QDateTime::currentDateTime()); // save System time
QString trashFilePath=QDir::homePath()+"/.local/share/Trash/files/"; // trash file path contain delete files
QString trashInfoPath=QDir::homePath()+"/.local/share/Trash/info/"; // trash info path contain delete files information
// create file format for trash info file----- START
QFile infoFile(trashInfoPath+FileName.completeBaseName()+"."+FileName.completeSuffix()+".trashinfo"); //filename+extension+.trashinfo // create file information file in /.local/share/Trash/info/ folder
infoFile.open(QIODevice::ReadWrite);
QTextStream stream(&infoFile); // for write data on open file
stream<<"[Trash Info]"<<endl;
stream<<"Path="+QString(QUrl::toPercentEncoding(FileName.absoluteFilePath(),"~_-./"))<<endl; // convert path string in percentage decoding scheme string
stream<<"DeletionDate="+currentTime.toString("yyyy-MM-dd")+"T"+currentTime.toString("hh:mm:ss")<<endl; // get date and time format YYYY-MM-DDThh:mm:ss
infoFile.close();
// create info file format of trash file----- END
QDir file;
file.rename(FileName.absoluteFilePath(),trashFilePath+FileName.completeBaseName()+"."+FileName.completeSuffix()); // rename(file old path, file trash path)
}
Trash files in linux exist /home/user_name/.local/share/Trash/files/ directory but it also require info file for each trash file which exist in /home/user_name/.local/share/Trash/info/ directory. when we want to move file into trash, actually move file into /home/user_name/.local/share/Trash/files/ directory and create info file in /home/user_name/.local/share/Trash/info/ directory. inside .trashinfo format use percentage decoding scheme for set file path where file existed, info file also contain time and date of deletion.