javacv: Iterating CvSeq in Java - java

I use:
cvFindContours(gray, mem, contours, Loader.sizeof(CvContour.class) , CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0));
and as the result I have CvSeq contours to iterate (as far as I understand it).
So I use it like that:
if(contours!=null) {
for (ptr = contours; ptr != null; ptr = ptr.h_next()) {
//..do sth with ptr
}
}
It works, but from time to time (quite often) I get:
Exception in thread "Thread-3" java.lang.NullPointerException: This pointer address is NULL.
at com.googlecode.javacv.cpp.opencv_core$CvSeq.h_next(Native Method)
at pl..filter(FullFilter.java:69)
at pl..Window$1.run(Window.java:41)
at java.lang.Thread.run(Unknown Source)
The line in which the exception is thrown is the line with ptr.h_next().
I tried to check for nulls but it doesn't work:
System.out.println("PTR="+ptr); // it's not null here!
if(ptr.h_next()==null) //exception in this line!
System.out.println("NULL");
System.out.println(ptr.h_next());
The first line shows:
PTR=com.googlecode.javacv.cpp.opencv_core$CvSeq[address=0x0,position=0,limit=1,capacity=1,deallocator=com.googlecode.javacpp.Pointer$NativeDeallocator#66d53ea4]
I tried also invoking contours.total() but it always throws the same exception.
So, what is a proper way to use in Java such C-like sequences?
EDIT:
my full method:
public IplImage filter(IplImage image) {
IplConvKernel kernel = cvCreateStructuringElementEx(2,2,1,1,CV_SHAPE_RECT, null);
cvDilate(image, image, kernel, 1);
kernel = cvCreateStructuringElementEx(5,5,2,2,CV_SHAPE_RECT, null);
cvErode(image, image, kernel, 1);
IplImage resultImage = cvCloneImage(image);
IplImage gray = cvCreateImage(cvGetSize(image), IPL_DEPTH_8U, 1);
cvCvtColor(image, gray, CV_BGR2GRAY);
CvMemStorage mem = CvMemStorage.create();
CvSeq contours = new CvSeq();
CvSeq ptr = new CvSeq();
cvThreshold(gray, gray, 20, 255, opencv_imgproc.CV_THRESH_BINARY);
double thresh = 20;
Canny( gray, gray, thresh, thresh*2, 3 ,true);
cvFindContours(gray, mem, contours, Loader.sizeof(CvContour.class) , CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0));
int i=0;
CvRect boundbox;
if(contours!=null) {
for (ptr = contours; ptr != null; ptr = ptr.h_next()) { //EXCEPTION HERE!
System.out.println((i++)+"\t"+ptr);
cvDrawContours( resultImage, ptr, CvScalar.BLUE, CvScalar.RED, -1, 3, 8, cvPoint(0,0) );
System.out.println("PTR="+ptr);
}
}
return resultImage;
}
It works fine for some time and suddenly (probably when no contours found?) it ends with the following exception:
Exception in thread "Thread-3" java.lang.NullPointerException: This pointer address is NULL.
at com.googlecode.javacv.cpp.opencv_core$CvSeq.h_next(Native Method)
at pl.kasprowski.eyetracker.FullFilter2.filter(FullFilter2.java:39)
at pl.kasprowski.eyetracker.Window$1.run(Window.java:42)
at java.lang.Thread.run(Unknown Source)
Im feeding the method directly with images taken from camera (once a second).
EDIT:
After some experiments it occurs that from time to time when I invoke cvFindContours as above I get a contour object which IS NOT NULL but invoking any method like contour.h_next() or contour.total() results in exception like above. What can be wrong? Or - how to check if the contour object is OK?! Of course I could catch NullPointerException but I don't think it's a correct way to solve the problem...

Problem solved.
I added additional condition. Instead of:
if(contours!=null) {
I wrote
if(contours!=null && !contours.isNull()) {
and it works. I don't see exactly why it is necessary but I think it's connected with Java <-> C semantic gap.

Try to use cvGetSeqElem(contours, i)
Example :
for (int i = 0; i < contours.total(); i++) {
CvRect rect = cvBoundingRect(cvGetSeqElem(contours, i),0);
//....... Your code ....//
}

Related

OPENCV crash when saving to file trained machine learning data (like SVM or ANN)

I have built a simple project in android studio, and included OpenCV in order to train either an SVM (support vector machine) or an ANN (artificial neural network). Everything seems to go well, including data creation, training and inspection of trained data, except for saving. Whenever I save a opencv ml-object (like ann.save(...) or svm.save(...)), android studio crashes.
SVM -
When I extract supportvectors using the line
classifier.getSupportVectors()
the numbers seem sain. However, the app crashes when I move past a breakpoint placed at
classifier.save("C:\\foo\\trentsvm.txt");
In logCat I dig up the following feedback:
07-04 14:36:10.939 25258-25258/com.example.tbrandsa.opencvtest A/libc:
Fatal signal 11 (SIGSEGV), code 2, fault addr 0x7f755f53f0 in tid
25258 (ndsa.opencvtest) [ 07-04 14:36:10.942 439: 439 W/]
debuggerd: handling request: pid=25258 uid=10227 gid=10227 tid=25258
I get a similar error if i instead try to save an artificial neural network (ANN), see update far below.
I have tried saving the file as XML and txt, and as "C:\trentsvm.someformat", and as "trentsvm.someformat". I also get the same error in my Eclipse java project. High pain, no gain. Full code is below. Could you help?
PS: I use OpenCv version 3.2.0. and Android Studio 2.3.2
// I based this code on stuff i found online. Not sure if all is as important or good.
// Purpose: multilabel classification - digit recognition for android app.
// Create data and labels for a digit recognition algorithm
int numTargets = 10; // (0-9 => 10 types of labels)
int totalSamples = 100; // Could have been number of images of digits
int totalIndicators = 10; // Could have been number of properites per digit image.
Mat labels = new Mat(totalSamples,1, CvType.CV_16S);
Mat data = new Mat(totalSamples, totalIndicators,CvType.CV_16S);
// Fill with dummy values:
for (int s = 0; s<totalSamples; s++)
{
int someLabel = s%numTargets;
labels.put(s,0, (double)someLabel);
for (int m = 0; m<totalIndicators; m++)
{
int someDataValue = (s%numTargets)*totalIndicators + m;
data.put(s, m, (double)someDataValue);
}
}
data.convertTo(data, CvType.CV_32F);
labels.convertTo(labels, CvType.CV_32S);
SVM classifier = SVM.create();
TermCriteria criteria = new TermCriteria(TermCriteria.EPS + TermCriteria.MAX_ITER,100,0.1);
classifier.setKernel(SVM.LINEAR);
classifier.setType(SVM.C_SVC); //We choose here the type CvSVM::C_SVC that can be used for n-class classification (n >= 2).
classifier.setGamma(0.5);
classifier.setNu(0.5);
classifier.setC(1);
classifier.setTermCriteria(criteria);
classifier.train(data, Ml.ROW_SAMPLE, labels);
// Check how trained SVM predicts the training data
Mat estimates = new Mat(totalSamples, 1, CvType.CV_32F);
classifier.predict(data, estimates, StatModel.RAW_OUTPUT);
for (int i = 0; i<totalSamples; i++)
{
double l = labels.get(i, 0)[0];
double e = estimates.get(i, 0)[0];
System.out.print("\n fact: "+l+", estimat: "+e);
}
Mat suppV = classifier.getSupportVectors();
try {
if (classifier.isTrained()){
// It crashes at the next line!
classifier.save("C:\\foo\\trentsvm.txt");
}
}
catch (Exception e)
{
}
Update july 5th: As suggested by ZdaR, I tried the to use an in-phone adress, but it did not solve the problem.
String address = Environment.getExternalStorageDirectory().getPath()+"/trentsvm.xml";
// address now has value "storage/emulated/0/trentsvm.xml"
classifier.save(address);
In logcat:
07-05 14:50:12.420 11743-11743/com.example.tbrandsa.opencv2 A/libc:
Fatal signal 11 (SIGSEGV), code 2, fault addr 0x7d517f1990 in tid
11743 (brandsa.opencv2)
[ 07-05 14:50:12.424 3134: 3134 W/ ] debuggerd: handling
request: pid=11743 uid=10319 gid=10319 tid=11743
Update july 6th:
When I run the same script in eclipse and use a debugger (JUnit 4, VM arguments: -Djava.library.path=C:\Users\tbrandsa\Downloads\opencv\build\java\x64;src\test\jniLibs, ) debugging on the pc without device, the caught exception "e" says the following
cause= Exception,
detailMessage= "Unknown Exception" ,
stackTrace=> StackTraceElement[0] ,
suppressedExeptions= Collections$UnmodifiableRandomAccessList,
Update july 13th:
I just tried with an artificial neural network (ANN) too, and it crashes when trying to save.
Error:
Fatal signal 11 (SIGSEGV), code 1, fault addr 0x15a57e688000c in tid
8507 (brandsa.opencv2) debuggerd: handling request: pid=8507
uid=10319 gid=10319 tid=8507
Code:
// Mat data is of size 100*20*CV_32FC1,
// Mat labels is of size 100*1*CV_32FC1
// layerSizes is of size 3*1*CV_8UC1
int[] hiddenLayers = {10};
Mat layerSizes = new Mat(2 + hiddenLayers.length,1,CvType.CV_8U);
layerSizes.put(0, 0, data.width());
for (int l = 0; l< hiddenLayers.length; l++){
layerSizes.put(1 + l, 0,hiddenLayers[l]);}
layerSizes.put(1 + hiddenLayers.length, 0,labels.width());
ANN_MLP ann = ANN_MLP.create();
ann.setLayerSizes(layerSizes);
ann.setActivationFunction(ANN_MLP.SIGMOID_SYM);
ann.train(data, Ml.ROW_SAMPLE , labels);
ann.save("/storage/emulated/0/Pictures/no.rema.priceagent.test/trentann.xml");

Feature Layer is getting null bounds with featurecollection derived from RasterToVectorProcess

Null Pinter Exception simply means that it is because of value is getting null. But In case of using APis such as GeoTiff it becomes annoying to find out the error in usage.
My code is as follows:
System.out.println("vectorization starts");
GridCoverage2D srcCoverage = new GeoTiffReader(new File("E:/output/ll_processed.TIFF")).read(new GeneralParameterValue[]{policy, gridsize, useJaiRead});
SimpleFeatureCollection fc = RasterToVectorProcess.process(srcCoverage, 3, cov.getEnvelope(), Collections.singletonList(0.0d), true, null);
System.out.println("process ends");
System.out.println("vectorization ends");
//MapContext map = new DefaultMapContext();
//map.setTitle("raster to vector conversion");
Style style = SLD.createPolygonStyle(Color.BLUE, Color.CYAN, 1.0f);
//map.addLayer(fc, style);
//map.getLayerBounds();
//JMapFrame.showMap(map);
MapContent mapContent= new MapContent();
mapContent.setTitle("Illegal Mining");
Layer layer = new FeatureLayer(fc, style,"VectorLayer");
//int boundary = 10;
// ReferencedEnvelope env2 = new ReferencedEnvelope(srcCoverage.getEnvelope().getMinimum(0) - boundary, srcCoverage.getEnvelope().getMaximum(0) + boundary,
//srcCoverage.getEnvelope().getMinimum(1) - boundary, srcCoverage.getEnvelope().getMaximum(1) + boundary, srcCoverage.getCoordinateReferenceSystem());
//mapContent.getViewport().setBounds(fc.getBounds());
Line 199 : if(layer.getBounds()!=null) // here the error is coming also tried with if(layer != null && layer.getBounds()!=null)
{
mapContent.addLayer(layer);
}else{
System.out.println("Layer bounds are null");
}
mapContent.getViewport().setCoordinateReferenceSystem(
DefaultGeographicCRS.WGS84);
Error
at org.geotools.map.FeatureLayer.getBounds(FeatureLayer.java:199)
I am trying to convert Tiff to Vector image and Then I want to store it on disk.
Most likely, your featureSource is null, since the geotools FeatureLayer class method getBounds() uses the featureSource to retrieve the bounds, but in the constructor FeatureLayer doesn't check whether the featureSource is null.
The featureSource is the first argument to the constructor of FeatureLayer. In your case, that's variable SimpleFeatureCollection fc.
Most likely, the method process.process returned null so fc is null.
Minor Change in RasterToVectorProcess.java
//features.add(builder.buildFeature(null));
//System.out.println("ignored");
//add
System.out.println("adding...");
SimpleFeature feature = builder.buildFeature(null);
((Collection<SimpleFeature>) features).add(feature);

glGetTexImage ACCESS VIOLATION

When I call glGetTexImage() on a texture from a Framebuffer, I get this error:
EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x00007ffabf967a2b, pid=1816, tid=14712
Here is my code:
MagicaAdventura.GAME.gameBuffer.bindTexture();
glGetTexImage(GL_TEXTURE_2D, 0, GL12.GL_BGR, GL_UNSIGNED_BYTE, buf);//line that causes the error
And here is the code for the bind method:
public void bind(int texture) {
if(currentBound[texture] != resource.getID() || lastBoundInFramebuffer != Renderer.CURRENT_FRAMEBUFFER) {
GL13.glActiveTexture(GL13.GL_TEXTURE0 + texture);
lastBoundInFramebuffer = Renderer.CURRENT_FRAMEBUFFER;
currentBound[texture] = resource.getID();
GL11.glBindTexture(GL11.GL_TEXTURE_2D, resource.getID());
}
}
The texture binding code works fine for other things.
The buffer wasn't allocating space for the padding the texture to a power of 2 so I switched to using glReadPixels.

Adding Two Mat of type 32FC4 in OpenCV for Android

To reduce the noise in an image, I am trying to get the average of 10 images.
Mat imgMain = new Mat(n_height, n_width, CvType.CV_32FC4);
Mat imgFin = new Mat(n_height, n_width, CvType.CV_32FC4);
for(int i=1; i <= 10; i++) {
//Crop the image
image.recycle();
image = null;
image = BitmapFactory.decodeFile("/storage/sdcard0/DCIM/A" + String.valueOf(i) + ".jpg");
pimage = Bitmap.createBitmap(image, leftOff1, topOff1, n_width, n_height);
Utils.bitmapToMat(pimage, imgMain);
scaleAdd(imgMain, 0.1, imgFin, imgFin);
}
Running the application, I get the following msg:
Caused by: CvException [org.opencv.core.CvException: cv::Exception:
/hdd2/buildbot/slaves/slave_ardbeg1/50-SDK/opencv/modules/core/src/matmul.cpp:2079:
error: (-215) src1.type() == src2.type() in function void
cv::scaleAdd(cv::InputArray, double, cv::InputArray, cv::OutputArray)
]
at org.opencv.core.Core.scaleAdd_0(Native Method)
at org.opencv.core.Core.scaleAdd(Core.java:6690)
at MainActivity.imageAnalysis(MainActivity.java:123)
where line 123 is scaleAdd(imgMaing, 0.1, imgFin, imgFin);
According to the reference, src1, src2 and dst MAT should be of same size and type. However, I get this error when I set imgFin type to 32FC4 but do not get any errors when imgFin is set to 8UC4. Any experience of this kind? I need to keep the floating numbers in imgFin which is why I can't go with 8UC4.
// this line will overwrite your imgMain,
// the type will be CV_8UC4, regardless, what you said before.
Utils.bitmapToMat(pimage, imgMain);
// so, convert to float:
imgMain.convertTo(imgMain, CvType.CV_32FC4);
// now add float images, to avoid precision loss:
scaleAdd(imgMain, 0.1, imgFin, imgFin);

NegativeArraySizeException on CollisionShape

I am trying to put a collision-shape onto my model.
But everytime I init the game, I get an NegativeArraySizeException.
private void createSoundBit(float x, float y, float z)
{
Spatial npc1 = assetManager.loadModel("Models/sound/sound.j3o");
npcNode.attachChild(npc1);
CollisionShape noteshape = CollisionShapeFactory.createDynamicMeshShape(npc1);
npcRigid = new RigidBodyControl(noteshape,123.0f);
npcRigid.setFriction(0f);
npcRigid.setMass(60f);
npcRigid.setPhysicsLocation(new Vector3f(x,y,z));
collmanager = new CollManager();
getPhysicsSpace().addCollisionListener(collmanager);
npc1.addControl(npcRigid);
bulletAppState.getPhysicsSpace().add(npcRigid);
rootNode.attachChild(npcNode);
}
I don't know why it happens
Stacktrace:
java.lang.NegativeArraySizeException
at com.jme3.bullet.collision.shapes.HullCollisionShape.getPoints(HullCollisionShape.java:71)
at com.jme3.bullet.collision.shapes.HullCollisionShape.<init>(HullCollisionShape.java:24)
at com.jme3.bullet.util.CollisionShapeFactory.createSingleDynamicMeshShape(CollisionShapeFactory.java:241)
at com.jme3.bullet.util.CollisionShapeFactory.createCompoundShape(CollisionShapeFactory.java:112)
at com.jme3.bullet.util.CollisionShapeFactory.createCompoundShape(CollisionShapeFactory.java:94)
at com.jme3.bullet.util.CollisionShapeFactory.createDynamicMeshShape(CollisionShapeFactory.java:188)
at Main.createSoundBit(Main.java:206)
at Main.simpleInitApp(Main.java:83)
at com.jme3.app.SimpleApplication.initialize(SimpleApplication.java:225)
at com.jme3.system.lwjgl.LwjglAbstractDisplay.initInThread(LwjglAbstractDisplay.java:130)
at com.jme3.system.lwjgl.LwjglAbstractDisplay.run(LwjglAbstractDisplay.java:207)
at java.lang.Thread.run(Thread.java:722)
For me it can be one of two things: your file sound.j3o is corrupted or there is a bug in jmonkeyengine. Try to load some other file and see what's happening. Part of source where is a problem:
FloatBuffer vertices = mesh.getFloatBuffer(Type.Position);
vertices.rewind();
int components = mesh.getVertexCount() * 3;
float[] pointsArray = new float[components];
// ...
So, looks like mesh.getVertexCount() returned negative value.

Categories