OpenCV on IOS haar cascade xml file path issues from C++ - c++

So I have my code in C++ and I am able to run it fine on linux/OSX/Android. The problem now is ios. I am simply trying to load the haar cascade xml files via full path "/foo/blah/myapp.app/haar.xml" and having one heck of a time.
C++ can't confirm the file exists nor can opencv load it. I am new to ios and am aware that the myapp.app could be a compressed dir like the android .apk dir.
I have confirmed that I'm looking in the right place....or at least I hope I have! to check i use getcwd in c++ to get running directory and I confirm that with the file path to the xml file. It looks legit!
What can I do? The nice part about using C++ for the lib is that I can use one code base for desktop/android/ios. I really don't want to have to mix in Objective-C into my lib just for file paths.
Thanks in advance!
The code I'm using is the following:
std::ifstream fexists(face_haar_path.c_str());
if(!fexists.good()) {
std::cout << "Could not find any facehaar.xml" << std::endl;
return NO_FACE_HAAR_FILE;
}
face_haar.load(face_haar_path); //cv::CascadeClassifier face_haar

Adding reference to file location in iOS apps is quite different. First add the .xml files to your Xcode project and use the following lines of code for loading the haar-cascade. Please note that should not contain the extension .xml (Example: For face_frontal.xml file, your cascade name should be face_frontal)
NSString *faceCascadePath = [[NSBundle mainBundle]
pathForResource:#"<your_cascade_name>"
ofType:#"xml"];
const CFIndex CASCADE_NAME_LEN = 2048;
char *CASCADE_NAME = (char *) malloc(CASCADE_NAME_LEN);
CFStringGetFileSystemRepresentation( (CFStringRef)faceCascadePath,
CASCADE_NAME,
CASCADE_NAME_LEN);
if(!face_cascade.load(CASCADE_NAME)) {
cout << "Unable to load the face detector!!!!" << endl;
exit(-1);
}

Related

How to read a file on Hololens with C++

I am trying to read a file in a test/debug UWP application that is being deployed to Hololens. I can put the file on the device with the device portal, but am unable to find the correct path to open the file.
I am using the MSFT BasicXrApp_uwp example as a basis, and have included FileUtility which has a FindFileInAppFolder function. This is consistently failing to find the file, with the error:
"The file should be embeded in app folder in debug build.",
after letting me know the app folder is:
C:\Data\Users\DefaultAccount\AppData\Local\DevelopmentFiles\364f83f4-6e13-42e4-8253-71dd3040951cVS.Debug_ARM.mikeh\
The part 364f83f4-6e13-42e4-8253-71dd3040951cVS is recognisable in the device portal as the User Folders/LocalAppData folder, but the Debug_ARM.mikeh part is not visible on the portal.
I am using C++ and trying to do the file reading in a static, non uwp library if possible (pointing that out so I don't get suggestions to use UWP async stuff, if that is possible).
So, how do I embed my file in the app folder, or how do I place the file so I can read it?
This is because the folder path which FindFileInAppFolder method returns is the InstalledLocation of the current package, but what you checked in the device portal is LocalFolder/LocalCacheFolder, for more information about what different between them please see: File access permissions.
how do I embed my file in the app folder, or how do I place the file so I can read it?
You can place your file in the LocalState folder by Device Portal and get this folder path through ApplicationData.LocalFolder Property, the path should be like: C:\Data\Users\DefaultAccount\AppData\Local\Packages\364f83f4-6e13-42e4-8253-71dd3040951c\LocalState. For how to access the files via C++ you can use for example File access sample
I'm using an answer here as there's more room than a comment.
I found a few extra things useful. I added in the cppWinRT nuget package to my application.
I did need to use the "async stuff", for example:
using namespace winrt;
using namespace Windows::Foundation;
using namespace Windows::Storage;
StorageFolder storageFolder= KnownFolders::GetFolderForUserAsync(nullptr, KnownFolderId::PicturesLibrary).get();
This let me find a file I'd uploaded ot the Pictures Library. But I couldn't open it after passing the path to my existing library:
const auto sampleFile = storageFolder.GetFileAsync(fileName).get();
std::wstring path = sampleFile.Path();
MyLibraryCall(to_string(path));
MyLibraryCall would try and open an ifstream, and even using std::ifstream::in would fail.
So I copied the file to the temp directory, where I could open it and process it.
This is pretty hacky but it did what I needed, which is let me load an .obj file that was rejected by the 3D parts viewer.
The loop over all filenames is because storageFolder.GetFileAsync(fileName).get() throws an exception if it fails, which for me I could not catch properly.
StorageFolder tempFolder = Windows::Storage::ApplicationData::Current().TemporaryFolder();
std::wstring path;
auto files = tempFolder.GetFilesAsync().get();
for (auto file : files)
{
if (file.Name() == fileName) {
path = file.Path();
break;
}
}
if (!path.size()) {
// hasn't been copied into temp
StorageFile movedFile = sampleFile.CopyAsync(tempFolder).get();
path = movedFile.Path();
}
MyLibraryCall(to_string(path));
Anyway- not the greatest but that will hopefully help someone else looking for a quick and dirty way to process a file on a hololens/UWP app.

QFileDialog: How to open/select file/dir from package in osX

I have googled a lot but dint find any relative solution for my problem.
PROBLEM: I want to open .MTS file and its working find if its available in any directory. But if its in any package then my QFileDialog is not able to look into that package and select those .MTS files.
CODE:
auto filePaths = QFileDialog::getOpenFileNames(this, "Open Video File", lastOpenedPath, "*.MTS;*.mov");
qDebug() << "File Paths " << filePaths;
Now the .MTS files created under AVCHD(Advanced Video Coding High Definition) package default in Sony & Panasonic HD Camera, and I want to import/select that .MTS files.
HINT: QFileDialog is able to import/select those .MTS files in Windows machine, but fail to import/select in mac machine.
Highly appreciated any thoughts.
Thanks.
Well, if I understand what you want to do properly, I'm not sure that it's possible in Qt alone.
It did turn out to be easier than I expected to simply call in to Cocoa and NSOpenPanel to achieve what I think you're looking for.
Sample project is at: https://github.com/NSGod/widgetsOpenFileDialogCocoa
Basically, I renamed mainwindow.cpp to mainwindow.mm, then added an #import <Cocoa/Cocoa.h>:
#import <Cocoa/Cocoa.h>
void MainWindow::on_openFileButton_clicked()
{
NSOpenPanel *openPanel = [NSOpenPanel openPanel];
[openPanel setAllowedFileTypes:[NSArray arrayWithObjects:#"mts", #"mov", nil]];
[openPanel setAllowsMultipleSelection:YES];
[openPanel setTreatsFilePackagesAsDirectories:YES];
[openPanel setTitle:#"Open Video File"];
NSInteger result = [openPanel runModal];
QStringList stringList;
if (result == NSFileHandlingPanelOKButton) {
NSArray *URLs = [openPanel URLs];
NSLog(#"URLs == %#", URLs);
for (NSURL *URL in URLs) {
stringList += QString::fromNSString(URL.path);
}
// do something with stringList
qDebug() << "filePaths == " << stringList;
}
}
Included in the project is a fakeBundle.component directory, which will be treated as a bundle (or "package") by OS X. But by setting treatsFilePackagesAsDirectories to YES, you can have the NSOpenPanel treat it as a directory (which it really is, of course).
Here is an image showing how the Finder treats this fakeBundle.component directory as if it were a single file:
And here in the NSOpenPanel, it's being treated as a directory:
An OSX package is a:
File system directory that is normally displayed to the user by the Finder as if it were a single file. Such a directory may be the top-level of a directory tree of objects stored as files, or it may be other archives of files or objects for various purposes, such as installer packages, or backup archives.
This is akin to an .mst or .msi file on Windows. Just as with OSX packages you would not be able to open your specified file within one of these packages. Your system open dialog is in fact doing you a disservice by allowing you to see into them, as you cannot open said files.
Your work around is to copy the file out of the package externally to the program then open the copy of the file.

Mp3 file is null using taglib(c++)

I am using taglib in c++ to change metadata from mp3 files. I have written a code that works great. But I found a MP3 file that cannot open with taglib.
The MP3 file has tags. I can see them with Vlc media player and MediaInfo and with explorer.exe.
I try this minimum codes but it say that the file is not valid.
TagLib::FileRef filer("file.mp3");
if(filer.isNull())
cout <<"null";
or this code:
TagLib::MPEG::File fileMpeg("file.mp3");
if(!fileMpeg.isValid())
{
cout << "file not valid";
}
other files work but not that one.
Thanks for your help.
I found the problem, The problem was not from the files but, from the files name or directory.
To fix the problem I sand cont wchar_t* rather than const char* because the files that I tried to open contain french characters from ISO or unicode encoding but not from ASCII.

Extracting .app on Mac with QuaZip

I'm basically trying to extract a Mac application from a zip file using QuaZip. The code I'm using is:
QuaZip zip("file.zip");
qDebug() << zip.open(QuaZip::mdUnzip);
QuaZipFile file(&zip);
QFile out("application.app");
out.open(QIODevice::WriteOnly);
for(bool f=zip.goToFirstFile(); f; f=zip.goToNextFile()) {
file.open(QIODevice::ReadOnly);
//same functionality as QIODevice::readData() -- data is a char*, maxSize is qint64
char c;
while (file.getChar(&c)) out.putChar(c);
file.close();
}
out.flush();
out.close();
zip.close();
If I try to start the extracted app, I get an error message saying I "can't open the Application, because the Classic-Environment is no longer supported." I tried to make the .app executable but it still didn't work. I don't know any other easy way to extract an application using Qt.
I extracted it with the normal archiver and the application worked.
I'm not super familiar with QuaZip, but it almost looks like you're trying to extract the whole archive to a single file called "application.app", which is pretty seriously wrong. Applications are actually folders, not files -- the Finder just displays the folder (which has a name ending in ".app") as if it were a single file.
If you can dig up an example of using QuaZip to extract a ZIP file, you should just be able to use that code largely unmodified (other than the __MACOSX metadata, possibly).
It may be easier to just call unzip from your app using QProcess or system().
unzip -q <path-to-zip> -d <path-to-destionation>

Opening a file in C++ outside of the working directory

I've got a program that is going to have several resource files that the user can put somewhere on the computer that isn't in the same folder as the executable. How do I get open those files?
I've found lots of answers saying that the reason things aren't working is that the file isn't in the working directory. I've tried providing fully qualified paths:
ifstream str;
str.open("/home/millere/foo.txt")
but that was unsuccessful. I know the path was correct (copy and paste). I can't find any documentation on it, but I assume it has to be possible. (vim ~/foo.txt from anywhere other than ~ works, for example).
Assuming you meant to use ifstream instead of iostream, your code is correct. ifstream can use a path to a file as well as the name of a file in the working directory.
No exceptions are thrown if the file does not exist, but the fail bit is set. You should check for this before trying to do anything with the stream.
std::ifstream input("/home/bob/stuff.txt");
if (!input) std::cerr << "Could not open the file!" << std::endl;
else
{
// ...
}
If you still cannot extract data from the file, the problem is somewhere else in your code.
I had the same issue and quickly noticed that, open when trying to get from a difference folder, had a different source directory (if using Cmake, the one that was specified by the cmake). You can find out, what the ouput/input source directory is by doing
system("ls")
or
system("dir")
on windows to show the content of the current ouput/input directory.