I am trying to implement face recognition in my photo database using JavaCV. While detecting possible faces works fine (there are a lot of examples for Java already), I am stuck at doing the actual recognition. To be more precise, at training the face recognizer.
For testing purposes I have a folder structure with a subfolder per known person labeled "s" + id, in which the training photos are located. What works is reading the images and adding them to an array. What does not work is creating a second array with the identifiers. LBPHFaceRecognizer.train does require a Mat and I cannot figure out how to create the required data structure. What I have so far is:
MatVector images = new MatVector();
List<Integer> ids = new ArrayList<Integer>();
File root = new File("orl_faces/");
for (File subFolder : root.listFiles()) {
if (subFolder.getName().matches("s\\d+") && subFolder.isDirectory()) {
int personId = Integer.parseInt(subFolder.getName().substring(1));
for (File file : subFolder.listFiles()) {
if (file.getName().endsWith(".pgm") && !"10.pgm".equals(file.getName())) {
IplImage img = cvLoadImage(file.getAbsolutePath());
images.put(img);
ids.add(personId);
}
}
}
}
// ---- FIXME here is where I am stuck ----
Mat labels = new Mat(new Size(ids.size(), 1));
for (int i = 0; i < ids.size(); i++) {
MatExpr m = Mat.ones(new Size(1, 1), CV_32SC1);
Mat m2 = m.asMat();
labels.push_back(m2);
}
model.train(images, labels);
When executing this, I get a
Exception in thread "main" java.lang.RuntimeException: vector<T> too long
at org.bytedeco.javacpp.opencv_face$FaceRecognizer.train(Native Method)
and obviously even if it did work, I still would not have my numbers in there. Any help is greatly appreciated.
You can use MatOfInt and an array of ints. For example, if you collect labels in List<Integer:
int[] allLabels = new int[labels.size()];
for (int i = 0; i < labels.size(); i++) {
allLabels[i] = labels.get(i);
}
faceRecognizer.train(faces, new MatOfInt(allLabels));
This should work :)
Related
I'm trying to ingest a mp4 file and make it a timelapse. It works with the code attached below. However, the output file has frame rate of 16*originalFrameRate. Since I don't intend to play it as a slow motion video I'd prefer to drop those redundant frames to make the output file smaller.
Movie inputMovie = MovieCreator.build(fileUri);
List<Track> videoTracks = new LinkedList<>();
for (Track track : inputMovie.getTracks()) {
if (track.getHandler().equals("vide")) {
videoTracks.add(track);
}
}
final int speedByFactorOf = 16;
Movie outputMovie = new Movie();
AppendTrack appendedTracks = new AppendTrack(videoTracks.toArray(new Track[videoTracks.size()]));
outputMovie.addTrack(new WrappingTrack(appendedTracks) {
#Override
public long[] getSampleDurations() {
long[] l = super.getSampleDurations();
for (int i = 0; i < l.length; i++) {
l[i] /= speedByFactorOf;
}
return l;
}
});
BasicContainer out = (BasicContainer) new DefaultMp4Builder().build(outputMovie);
FileChannel fc = new RandomAccessFile("timelapse.mp4", "rw").getChannel();
out.writeContainer(fc);
fc.close();
out.close();
I was unable to find any examples of how to change the output frame rate.
As stated by #tarun-lalwani if the project you're referring to is https://github.com/sannies/mp4parser then it is only able to edit the MP4 container and NOT the video / audio / media etc. held within the container. Even if you could use metadata to accelerate the FPS by sixteen times, the file size would not become any smaller because all the frames would still be within the file (just shown for a shorter duration). You would need to use something like FFmpeg (e.g. via https://github.com/bramp/ffmpeg-cli-wrapper ) or some other programmatic video editor to do what you're describing thus only keeping every sixteenth frame of video so the video file actually becomes smaller.
TLDR; mp4parser is not the correct project for editing video (as opposed to metadata) and what you want to achieve sounds like it is beyond the scope of just fiddling with the container.
I run the following piece of Processing (Java) code inside a bigger loop. These lines save a string in a .txt file called kinectDEM.tmp, before doing that, the old file is renamed to kinectDEM1.txt and the new one (kinectDEM.tmp) is renamed to kinectDEM0.txt.
It works fine but sometimes it get stuck and the kinectDEM1.txt file disappears, the code still work but doesn't save the .txt files. No error message appears.
Is there something wrong saving .txt files in that way?
Here's the code:
import java.io.File;
import SimpleOpenNI.*;
import java.util.*;
SimpleOpenNI kinect;
List<int[]> previousKinectValues = new LinkedList<int[]>();
int numPreviousToConsider = 60;
void setup()
{
size(640, 480);
kinect = new SimpleOpenNI(this);
kinect.enableDepth();
frameRate(60);
}
int precedente = millis();
void draw()
{
kinect.update();
PImage depthImage = kinect.depthImage();
image(depthImage, 0, 0);
int[] newDepthValues = kinect.depthMap();
previousKinectValues.add(newDepthValues);
if (previousKinectValues.size() > numPreviousToConsider) {
previousKinectValues.remove(0);
}
int[] depthValues = average(previousKinectValues);
depthValues = reverse(depthValues);
StringBuilder sb = new StringBuilder();
Deque<Integer> row = new LinkedList<Integer>();
int kinectheight = 770; // kinect distance from the baselevel [mm]
int scaleFactor = 1;
int pixelsPerRow = 640;
int pixelsToSkip = 40;
int rowNum = 0;
for (int i = 0; i < depthValues.length; i++) {
if (i > 0 && i == (rowNum + 1) * pixelsPerRow) {
fillStringBuilder(sb, row);
rowNum++;
sb.append("\n");
row = new LinkedList<Integer>();
}
if (i < ((rowNum+1) * pixelsPerRow) - pixelsToSkip) {
//if (i >= (rowNum * pixelsPerRow) + pixelsToSkip) {
row.addFirst((kinectheight - depthValues[i]) * scaleFactor);
}
}
fillStringBuilder(sb, row);
String kinectDEM = sb.toString();
final String[] txt= new String[1]; //creates a string array of 2 elements
int savingtimestep = 2000; // time step in millisec between each saving
if (millis() > precedente + savingtimestep) {
txt[0] = "ncols 600\nnrows 480\nxllcorner 0\nyllcorner 0\ncellsize 1\nNODATA_value 10\n" +kinectDEM;
saveStrings("kinectDEM0.tmp", txt);
precedente = millis();
// delete the old .txt file, from kinectDEM1 to kinectDEMtrash
File f = new File(sketchPath("kinectDEM1.txt"));
boolean success = f.delete();
// rename the old .txt file, from kinectDEM0 to kinectDEM1
File oldName1 = new File(sketchPath("kinectDEM0.txt"));
File newName1 = new File(sketchPath("kinectDEM1.txt"));
oldName1.renameTo(newName1);
// rename kinectDEM0.tmp file to kinectDEM0.txt
File oldName2 = new File(sketchPath("kinectDEM0.tmp"));
File newName2 = new File(sketchPath("kinectDEM0.txt"));
oldName2.renameTo(newName2);
}
}
void fillStringBuilder(StringBuilder sb, Deque<Integer> row) {
boolean emptyRow = false;
while (!emptyRow) {
Integer val = row.pollFirst();
if (val == null) {
emptyRow = true;
} else {
sb.append(val);
val = row.peekFirst();
if (val != null) {
sb.append(" ");
}
}
}
}
int[] average(List<int[]> previousKinectValues) {
if (previousKinectValues.size() > 0) {
int[] first = previousKinectValues.get(0);
int[] avg = new int[first.length];
for (int[] prev : previousKinectValues) {
for (int i = 0; i < prev.length; i++) {
avg[i] += prev[i];
}
}
int num = previousKinectValues.size();
for (int i = 0; i < avg.length; i++) {
avg[i] /= num;
}
return avg;
}
return new int[0];
}
You can simplify your problem into a much smaller example sketch:
saveStrings("one.txt", new String[]{"ABC"});
File oldName = new File(sketchPath("one.txt"));
File newName = new File(sketchPath("two.txt"));
boolean renamed = oldName.renameTo(newName);
println(renamed);
In the future, please try to narrow your problem down to an MCVE like this.
Anyway, this program saves the text ABC to a file named one.txt. It then tries to rename one.txt to two.txt. This is exactly what you're trying to do, just without all that extra kinect code, which doesn't really have anything to do with your problem.
Please run this little example program and then view your sketch directory (Sketch > Show Sketch Folder). You'll see the two.txt file, and that file will contain the text ABC on a single line. Also notice that the program prints true to the console, indicating that the rename was successful. This is exactly what you'd expect.
Now, change the first line to this:
saveStrings("one.txt", new String[]{"XYZ"});
Run the program again. First notice that it prints out false to the console, indicating that the rename was not successful. Then view the sketch folder, and you'll see two text files: one.txt which contains XYZ and two.txt which contains ABC. This is not what we expect, and this is what's happening in your code as well.
So, what's happening is this:
We run our code, create one.txt containing ABC, then rename it to two.txt. We then run the code again, creating one.txt containing XYZ. We then try to rename that new file to two.txt, but we can't.
From the Java API for the File#renameTo() function, emphasis mine:
Many aspects of the behavior of this method are inherently platform-dependent: The rename operation might not be able to move a file from one filesystem to another, it might not be atomic, and it might not succeed if a file with the destination abstract pathname already exists. The return value should always be checked to make sure that the rename operation was successful.
Note that the Files class defines the move method to move or rename a file in a platform independent manner.
So it looks like the rename step is failing, becuase you can't rename a file to overwrite an existing file. Instead, we can use the Files#move() function, which allows us to specify overwrite options:
Files.move(oldName.toPath(), newName.toPath(), StandardCopyOption.REPLACE_EXISTING);
So, i'm trying to save my player data onto a txt file, then load the data from the text from when the game is opened again, but its not working, I get it to save while in the game, but when I close the game, and open it back up its no longer saved, and it has all the default data in the game, and in the file...
Here is the some of the code from the game (Sorry it's in pastebin, I thought i might be too long to just paste it into here.)
Game.java
Save.java
I am in need of some assistance, trying to get it to load from the text document, and when the game opens, not resetting the text document into its default settings.
The issue is in Save.savePlayer()
At the beginning you declare saveInfo to hold the values that the game holds at that point in time. When initially loading they will hold the default values.
int[] saveInfo = { Game.hp, Game.level, Game.mana, Game.expTotal,
Game.goldTotal, Game.arrow, Game.shuriken, Game.bomb,
Game.hpPotion, Game.mpPotion, Game.potion, Game.items };
The variables here:Game.hp=100, Save.saveInfo[0]=100
Then you set all of the game variables to saveInfo at the beginning of Save.savePlayer()
Game.hp = saveInfo[0];
Game.level = saveInfo[1];
Game.mana = saveInfo[2];
Game.expTotal = saveInfo[3];
Game.goldTotal = saveInfo[4];
Game.arrow = saveInfo[5];
Game.shuriken = saveInfo[6];
Game.bomb = saveInfo[7];
Game.hpPotion = saveInfo[8];
Game.mpPotion = saveInfo[9];
Game.potion = saveInfo[10];
Game.items = saveInfo[11];
The variables here:Game.hp=100, Save.saveInfo[0]=100
They don't change because you just set them back to their default values.
Then you load the saved state but you don't do anything with the data. You should be setting the variables after loading here so they're set to the new saveInfo values instead of the old.
for (int i = 0; i < saveInfo.length; i++) {
saveInfo[i] = Integer.parseInt(inputReader.readLine());
}
I think this part is the problem...
private void readPlayer(String filePath) {
File inputFile;
BufferedReader inputReader;
try {
inputFile = new File(filePath);
inputReader = new BufferedReader(new FileReader(inputFile));
Game.hp = saveInfo[0];
Game.level = saveInfo[1];
Game.mana = saveInfo[2];
Game.expTotal = saveInfo[3];
Game.goldTotal = saveInfo[4];
Game.arrow = saveInfo[5];
Game.shuriken = saveInfo[6];
Game.bomb = saveInfo[7];
Game.hpPotion = saveInfo[8];
Game.mpPotion = saveInfo[9];
Game.potion = saveInfo[10];
Game.items = saveInfo[11];
for (int i = 0; i < saveInfo.length; i++) {
saveInfo[i] = Integer.parseInt(inputReader.readLine());
}
inputReader.close();
} catch (Exception e) {
e.printStackTrace();
}
}
put these lines
for (int i = 0; i < saveInfo.length; i++) {
saveInfo[i] = Integer.parseInt(inputReader.readLine());
}
before
Game.hp = saveInfo[0];
Game.level = saveInfo[1];
Game.mana = saveInfo[2];
Game.expTotal = saveInfo[3];
Game.goldTotal = saveInfo[4];
Game.arrow = saveInfo[5];
Game.shuriken = saveInfo[6];
Game.bomb = saveInfo[7];
Game.hpPotion = saveInfo[8];
Game.mpPotion = saveInfo[9];
Game.potion = saveInfo[10];
Game.items = saveInfo[11];
in order to read the file before setting the game values...
If you do not mind it, then using xstream and apache fileutils is an excellent solution and less coding. I am just sharing my thoughts.
import org.apache.commons.io.FileUtils;
import com.thoughtworks.xstream.XStream;
//saving your data
XStream xstream=new XStream(new DOMDriver());
String xml = xstream.toXML(yourGambeObj);
FileUtils.writeStringToFile(new File("yourfilename", xml);
//reading your data
Game gameData=xstream.fromXML(new File("yourfilename"),Game.class);
//now you can use access your methods n attribute. no conversion as you did in serialization.
Please download and add these jars.XStream &
Apache Commons IO
So, I was fiddling around with some things, and I did it! So, the problem was, that i would load it from the save data, then write over it, then load it again, for some reason, it would do the whole Save.java 2 times and just save over it, but I put them all as public static voids and instead of calling the whole Constructor, I call them by individual methods by where and what they need to do, which seem to work great! Thank you all for all your help, it helped a lot!
I made a game using JFrame, and now I want to deploy it in JApplet, yet I get the following exception:
java.lang.ExceptionInInitializerError
As much as Google told me it is caused by static initializers, and the only thing I do in my static initialization blocks is call to the following function:
public static BufferedImage[] loadAnimation (String fileName, int subimagewidth, int subimageheight, int pixelsbetweensprites) {
BufferedImage spr = null;
BufferedImage[] animation;
int x, y; //amount of images in each direction
try {
Object ob = new Object();
spr = ImageIO.read(ob.getClass().getResourceAsStream(fileName));
} catch (IOException ex) {
System.exit(0);
Logger.getLogger(AnimationLoader.class.getName()).log(Level.SEVERE, null, ex);
}
x = spr.getWidth() / subimagewidth;
y = spr.getHeight() / subimageheight;
animation = new BufferedImage[x*y];
for (int i = 0; i < x; i++) {
for (int j = 0; j < y; j++) {
animation[j*x+i] = spr.getSubimage(i*(subimagewidth + pixelsbetweensprites), j*(subimageheight+pixelsbetweensprites), subimagewidth, subimageheight);
}
}
return animation;
}
Is this problem occurs because it is JApplet, or because it is unsigned?
How to fix it (preferably without spending money on signature)?
This:
Object ob = new Object();
spr = ImageIO.read(ob.getClass().getResourceAsStream(fileName));
You probably want to load the image from the same location your code originates from (e.g. a jar file). Instead you ask java.lang.Object.class to give back the stream of the image which is probably not you want (this would search the filename resource in the internal libraries of the JRE or JDK - more specifically in the rt.jar file).
If indeed you want to load the image from the same jar your class files originates from, you should acquire the stream like this:
InputStream in = YourClass.class.getResourceAsStream(filename);
You should pass this InputStream to your loadAnimation() method, or pass both the Class along with the file name to be used to get the stream of the image.
I have a Spring-based Java webapp. And my problem is:
I have a file which has 34MB and has 2.7 million lines. Lines are just single words one after another:
abc
abcdfg
xyz
etc
I need to choose 15 random unique lines from this file which are not next to each other in a quite fast way. I know that to search such a big files I can use Apache Lucene. Do you know if Lucene can get for me these random lines. Or maybe you have some other idea that can help me to solve this problem.
I would really appreciate any help
Thanks in advance
EDIT:
Or maybe just put this file into database [PostgreSQL]?
Lucene would not work for you.
Instead just generate random numbers (make sure they are not next to each other) and then read those lines from the text file.
Here is the code that does it:
public static void main(String[] args) throws IOException
{
BufferedReader reader = new BufferedReader(new FileReader(
"MyFile.txt"));
try
{
final int MAX_NUM = <ENTER-YOUR-MAX-NUMBER-OF-LINES>;
Set<Integer> randomLines = new HashSet<Integer>();
Random rnd = new Random(System.currentTimeMillis());
for (int i = 0; i < 15; i++)
{
int aNum = rnd.nextInt(MAX_NUM);
// to make sure no lines next to each other...
if (!randomLines.contains(aNum) && !randomLines.contains(aNum+1) && !randomLines.contains(aNum-1))
{
randomLines.add(aNum);
}
}
List<String> result = new ArrayList<String>();
String aLine;
int lineNo = 0;
while ((aLine = reader.readLine()) != null)
{
if (randomLines.contains(lineNo))
{
result.add(aLine);
}
lineNo++;
}
System.out.println("Result: " + result);
}
finally
{
reader.close();
}
}
I would suggest using Mongo DB (it is not as reliable as RMDBS but it is extremally quick).
http://www.mongodb.org/display/DOCS/Quickstart
I would parse text file to Mongo documents and then retrieve random 3 doc's from Mongo db which would result in 3 random phrases.
1) In Java Read text file and save each line as separate doc in mongo, or execute commands like
in mongo direct
> doc = { phrase : 'uniquephrase'}
> db.posts.insert(doc);
2) in your java connect to the mongo, get collection size and select random 3 numbers from, then serve 3 docs... (or anything else)