In OpenCV I am using ORB FeatureDetection in an Android app. It has parameters but these cannot be set directly in Java. The recommended way to set them is to write out a XML or YML file with the params and then read it back in.
However, there seems to be no way to be sure that in fact I have written the file correctly and that the parameters are applied. I thought I could use the write() method to verify that my new settings have taken. But this doesn't seem to work. It does indeed write a proper YML or XML file, but the files have no params.
Here is code to write the files:
_detector = FeatureDetector.create(FeatureDetector.ORB);
// write initial params.
String fileName = myDir.getPath() + "/orb_params.yml";
_detector.write(fileName);
fileName = myDir.getPath() + "/orb_params.xml";
_detector.write(fileName);
// try setting some params.
String tempFileName = writeToFile("tempFile", "%YAML:1.0\nscaleFactor: 1.1\nnLevels: 5\nfirstLevel: 0\nedgeThreshold: 31\npatchSize: 31\n");
_detector.read(tempFileName);
// write params again.
String fileName = myDir.getPath() + "/orb_params2.yml";
_detector.write(fileName);
fileName = myDir.getPath() + "/orb_params2.xml";
_detector.write(fileName);
The xml files look like this:
<?xml version="1.0"?>
<opencv_storage>
</opencv_storage>
The yml files look like this:
%YAML:1.0
Is the write method not implemented in Java? I see that it is implemented in Algorithm.cpp and I assume the ORB Feature Detector just uses that implementation, I see no code to indicate otherwise.
I don't know if this problem is limited to ORB Feature Detection or if other algos suffer these problems when trying to write parameters from Java.
addendum: I see that the write method appears to be implemented in the JNI code: https://github.com/Itseez/opencv/blob/ddf82d0b154873510802ef75c53e628cd7b2cb13/modules/features2d/misc/java/src/cpp/features2d_manual.hpp
Got a response on answers.opencv.org and am posting it here for those stumbling across this in the future:
According to this answer the read/write function is not implemented in C++ and thus won't work in Android either.
Related
Im currently trying to save some values in a text file in Processing Android (APDE). I want to later use this in another context, so it's important to use a complete file path. From Processing documentation for loadStrings():
... Alternatively, the file maybe be loaded from anywhere on the local
computer using an absolute path (something that starts with / on Unix
and Linux, or a drive letter on Windows)
So it must be possible.
I already searched for a answer, but never found something for Processing.
So my code is:
String[] saveData;
int score;
void setup(){
saveData=loadStrings("/storage/emulated/0/dataP/hi.txt");
score=parseInt(saveData[0]);
fullScreen();
frameRate(60);
noStroke();
noSmooth();
textAlign(CENTER);
textSize(height/20);
}
void draw(){
background(0);
fill(255) ;
text(score, width/2,height/2);
}
void mousePressed(){
score--;
saveData[0]=str(score);
println(saveData[0]);
saveStrings("/storage/emulated/0/hi.txt" ,saveData);
}
and I get the following error:
java.lang.IllegalArgumentException: File
/storage/emulated/0/dataP/hi.txt contains a path separator
I believe the confusion stems from the fact that loadStrings() method works differently for Java mode and Android mode. In Java mode, it is definitely possible to give loadStrings() an absolute Path with included separators, but in Android mode, loadStrings() will only work if you only specify a name without any separator (assumes by default to be looking into the data folder). Therefore, having any separator inside loadStrings() will throw the error.
One simple workaround you can try is to first create a separate path variable:
String path = "/storage/emulated/0/dataP/hi.txt";
And then give that as parameter to the loadStrings() method:
saveData = loadStrings(path);
If you were to use an SD card for storage, for example, you could do something like:
String SDCARD = Environment.getExternalStorageDirectory().getAbsolutePath();
File file = new File(SDCARD + File.separator + "mytext.txt");
String[] s = loadStrings(file.getPath());
As explained in the link in the comment I posted, loadStrings() and saveStrings() does not take absolute path as argument. What it means is that it can only access files with path "name.txt" and not "folder/name.txt". You have to do it using a FileInputStream and FileOutputStream if you must use absolute path. There are many examples of both these files on StackOverflow.
Can ARToolKit load a pattern file (source) dinamically from outside after when i builded from the studio and not added exactly source?
Is there any example for this?
Not tried, but seems possible. Try passing the absolute path of .patt file in the config for the addTrackable() method.
String config = "single;" + pattFileAbsolutePath + trackableWidth;
trackableUIDs[i] = getInstance().addTrackable(config);
It's worth giving a try.
I have two parts to this question: 1) what is the best solution to my need, and 2) how do I do this?
1) I have a client app which sends bundles to a service app. the bundles can break the limit on bundle size, so I need to write the actual request out and read it in on the service side. Because of this, I can't write to my private internal storage. I've used these pages heavily, and haven't had luck: http://developer.android.com/guide/topics/data/data-storage.html
http://developer.android.com/training/basics/data-storage/files.html
My current understanding is that my best path is to use this to get a public dir:
File innerDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS);
I then add in my filename:
String fileName = String.valueOf(request.timestamp + "_avoidRoute"+count+++".ggr");
Combing these two results in the full file path:
/storage/emulated/0/Download/GroundGuidance/Route/1425579692169_avoidRoute1.ggr
Which I write to disk like this:
fos = context.openFileOutput(fullPath, Context.MODE_WORLD_WRITEABLE);
fos.write(routeString.getBytes());
fos.close();
When I try to write this to disk I get the error
java.lang.IllegalArgumentException: File /storage/emulated/0/Download/GroundGuidance/Route/1425579692169_avoidRoute1.ggr contains a path separator
Of course it does - I need it to have a path. I've searched online for solutions to this error which tell me to us FileOutputStream to write a full path. I did, but while my app doesn't error and appears to create the file, I'm also not able to view it on my phone in Windows Explorer, leading me to believe that it is creating a file with private permissions. So this brings me to my post and two questions:
1) Is there a different approach I should be trying to take to share large amounts of data between my client and service apps?
2) If not, what am I missing?
Thanks all for reading and trying to help!
Combing these two results in the full file path:
/storage/emulated/0/Download/GroundGuidance/Route/1425579692169_avoidRoute1.ggr
Which I write to disk like this:
fos = context.openFileOutput(fullPath, Context.MODE_WORLD_WRITEABLE);
This is not an appropriate use of Context's openFileOutput() method as that does not take a full path, but rather a filename within an app's private storage area.
If you are going to develop a full path yourself, as you have, then use
fos = new FileOutputStream(fullPath)
The Sharing permission setting is not applicable to the External Storage, though you will need a manifest permission to write (and implicitly read) on your creator, and the one for reading on your consumer.
Or, instead of constructing a full path, you could use your private storage with a filename and Context.MODE_WORLD_WRITEABLE (despite the being deprecated as an advisory) and pass the absolute path of the result to the other app to use with new FileInputStream(path).
Or you could use any of the other data interchange methods - content providers, local sockets, etc.
I'm using mp4parser to mux h264 and aac file which are re-encoded from orginal video file,how can I write the metadata of the original video to the new mp4 file? Or is there a common method to write metadata to mp4 file?
metadata and MP4 is a really problem. There is no generally supported specification. But this is only one part of the problem.
Prob (1): When to write metadata
Prob (2): What to write
Prob (1) is relatively easy to solve: Just extend the DefaultMp4Builder or the FragmentedMp4Builder on your own and override the
protected ParsableBox createUdta(Movie movie) {
return null;
}
with something meaningful. E.g.:
protected ParsableBox createUdta(Movie movie) {
UserDataBox udta = new UserDataBox();
CopyrightBox copyrightBox = new CopyrightBox();
copyrightBox.setCopyright("All Rights Reserved, me, myself and I, 2015");
copyrightBox.setLanguage("eng");
udta.addBox(copyrightBox);
return udta;
}
some people used that to write apple compatible metadata but even though there are some classes in my code I never really figured out what works and what not. You might want to have a look into Apple's specification here
And yes: I'm posting this a year to late.
It seems that the 'mp4parser' library (https://code.google.com/p/mp4parser/), supports writing Metadata to mp4 files in Android. However, I've found there's little-to-no documentation on how to do this, beyond a few examples in their codebase. I've had some luck with the following example, which writes XML metadata into the 'moov/udta/meta' box:
https://github.com/copiousfreetime/mp4parser/blob/master/examples/src/main/java/com/googlecode/mp4parser/stuff/ChangeMetaData.java
If you consider the alternatives you might want to look at JCodec for this purpose. It now has the org.jcodec.movtool.MetadataEditor API (and a matching CLI org.jcodec.movtool.MetadataEditorMain).
Their documentation contains many samples: http://jcodec.org/docs/working_with_mp4_metadata.html
So basically when you want to add some metadata you need to know what key(s) it corresponds to. One way to find out is to inspect a sample file that already has the metadata you need. For this you can run the JCodec's CLI tool that will just print out all the existing metadata fields (keys with values):
./metaedit <file.mp4>
Then when you know the key you want to work with you can either use the same CLI tool:
# Changes the author of the movie
./metaedit -f -si ©ART=New\ value file.mov
or the same thing via the Java API:
MetadataEditor mediaMeta = MetadataEditor.createFrom(new
File("file.mp4"));
Map<Integer, MetaValue> meta = mediaMeta.getItunesMeta();
meta.put(0xa9415254, MetaValue.createString("New value")); // fourcc for '©ART'
mediaMeta.save(false); // fast mode is off
To delete a metadata field from a file:
MetadataEditor mediaMeta = MetadataEditor.createFrom(new
File("file.mp4"));
Map<Integer, MetaValue> meta = mediaMeta.getItunesMeta();
meta.remove(0xa9415254); // removes the '©ART'
mediaMeta.save(false); // fast mode is off
To convert string to integer fourcc you can use something like:
byte[] bytes = "©ART".getBytes("iso8859-1");
int fourcc =
ByteBuffer.wrap(bytes).order(ByteOrder.BIG_ENDIAN).getInt();
If you want to edit/delete the android metadata you'll need to use a different set of fucntion (because it's stored differently than iTunes metadata):
./metaedit -sk com.android.capture.fps,float=25.0 file.mp4
OR alternatively the same through the API:
MetadataEditor mediaMeta = MetadataEditor.createFrom(new
File("file.mp4"));
Map<String, MetaValue> meta = mediaMeta.getKeyedMeta();
meta.put("com.android.capture.fps", MetaValue.createFloat(25.));
mediaMeta.save(false); // fast mode is off
I have yet another hurdle to climb with my GOOGLE DRIVE SDK Android App. I am uploading scanned images with tightly controlled index fields - user defined 'tags' from local dictionary. For instance XXX.JPG has index words "car" + "insurance". Here is a simplified code snippet:
...
body.setTitle("XXX.JPG");
body.setDescription("car, insurance");
body.setIndexableText(new IndexableText().setText("car insurance"));
body.setMimeType("image/jpeg");
body.setParents(Arrays.asList(new ParentReference().setId(...)));
FileContent cont = new FileContent("image/jpeg", new java.io.File(fullPath("xxx.jpg")));
File gooFl = _svc.files().insert(body, cont).execute();
...
Again, everything works great, except when I start a search, I get results that apparently come from some OCR post process, thus rendering my system's DICTIONARY unusable. I assume I can use a custom MIME type, but then the JPEG images become invisible for users who use standard GOOGLE DRIVE application (local, browser-based ... ). So the question is: Can I upload MIME "image/jpeg" files with custom indexes (either Indexable, or Description fields) but stop GOOGLE from OCR-ing my files and adding indexes I did not intend to have?
Just to be more specific, I search for "car insurance" and instead of my 3 files I indexed this way, I get unmanageable pile of other results (JPEG scanned documents) that had "car" and "insurance" somewhere in them. Not what my app wants.
Thank you in advance, sean
...
Based on Burcu's advise below, I modified my code to something that looks like this (stripped to bare bones):
// define meta-data
File body = new File();
body.setTitle("xxx.jpg");
body.setDescription(tags);
body.setIndexableText(new IndexableText().setText(tags));
body.setMimeType("image/jpeg");
body.setParents(Arrays.asList(new ParentReference().setId(_ymID)));
body.setModifiedDate(DateTime.parseRfc3339(ymdGOO));
FileContent cont =
new FileContent("image/jpeg",new java.io.File(fullPath("xxx.jpg")));
String sID = findOnGOO(driveSvc, body.getTitle());
// file not found on gooDrive, upload and fix the date
if (sID == null) {
driveSvc.files().insert(body, cont).setOcr(false).execute();
driveSvc.files().patch(gooFl.getId(), body).setOcr(false).setSetModifiedDate(true).execute();
// file found on gooDrive - modify metadata and/or body
} else {
// modify content + metadata
if (contentModified) {
driveSvc.files().update(sID, body, cont).setOcr(false).setSetModifiedDate(true).execute();
// only metadata (tags,...)
} else {
driveSvc.files().patch(sID, body).setOcr(false).setSetModifiedDate(true).execute();
}
}
...
It is a block that uploads or modifies a Google Drive file. The two non-standard operations are:
1/ resetting the file's 'modified' date in order to force the date of file creation - tested, works OK
2/ stopping the OCR process that interferes with my apps indexing scheme - will test shortly and update here
For the sake of simplicity, I did not include the implementation of "findInGOO()" method. It is quite simple 2-liner and I can supply it upon request
sean
On insertion, set the ocr parameter to false:
service.files().update(body, content).setOcr(false).execute();