Errors in detectMultiScale() for face detection
Hi guys,
My research team and i are working on a JRuby multithreaded application, that calls in an on-demand way a simple java class for face-recognition.
- the JVM is always Oracle jdk 1.8.0_121
- the JRuby version is always jruby 9.1.7.0
About openCV, we have tested the 3.2.0 and 3.1.0 versions, building it with java bindings in the following way:
cmake -DMAKE_BUILD_TYPE=DEBUG -DBUILD_SHARED_LIBS=OFF
putting opencv_320.jar in /usr/share/java, and libopencv_java3**.so in /usr/local/lib .
The java code is the following ( we use two face-detectors ):
public class FaceRecognition {
static{
System.load("/usr/local/lib/libopencv_java310.so");
}
public static String doFaceRec(byte[] img_stream) {
Mat frame = Imgcodecs.imdecode(new MatOfByte(img_stream), Imgcodecs.IMREAD_UNCHANGED);
CascadeClassifier faceDetector1 = new CascadeClassifier("haarcascade_profileface.xml");
faceDetector1.load("haarcascade_profileface.xml");
CascadeClassifier faceDetector2 = new CascadeClassifier("haarcascade_frontalface_alt.xml");
faceDetector2.load("haarcascade_frontalface_alt.xml");
if (faceDetector1.empty() || faceDetector2.empty()) {
frame.release();
System.out.println("faceDetector is empty");
return "0";
}
MatOfRect faceDetections = new MatOfRect();
MatOfRect faceDetections2 = new MatOfRect();
faceDetector1.detectMultiScale(frame, faceDetections, 1.3, 3, 0, new Size(), new Size());
faceDetector2.detectMultiScale(frame, faceDetections2, 1.1, 3, 0, new Size(), new Size());
int found = faceDetections.toArray().length + faceDetections2.toArray().length;
faceDetections.release();
faceDetections2.release();
frame.release();
return ""+found;
}
}
The application generates different threads that call the doFaceRec(..) method provided by FaceRecognition class; through a concurrent-lock mechanism we are sure that only one thread per time calls the doFaceRec(..) method.
We tested the application on different machines with same conditions and/or parameters, with no errors:
- Raspberry Pi 3 (quad-core, 1GB of RAM), Raspbian 8.0 / linux 4.4.38
- Sony vaio (i7 dual-core, 12GB of RAM) Ubuntu 16.04 / linux 4.4.0
- Dell XPS 13 9360 (i7 dual-core, 16GB of RAM), Ubuntu 16.04 / linux 4.8.4
Unfortunately, we had some errors testing the code in other machines:
- Lenovo with i7 quad-core processor, 16GB of RAM, the only machine with openjdk 8
- Amazon m4.4xlarge EC2 instance (Intel Xeon 16 vCPU, 64gb of RAM) Ubuntu 16.04 / linux 4.4.0
Without any limitation on the number of used threads, and using both opencv 3.2.0 and opencv 3.1.0 , we have two different errors ( we show only the errors on opencv3.2.0 because those with opencv3.1.0 are the same ):
Error 1:
[thread 140705678751488 also had an error][thread 140706560714496 also had an error][thread 140705812969216 also had an error][thread 140705804576512 also had an error][thread 140705787791104 also had an error]#
# A fatal error has been detected by the Java Runtime Environment:
#
# SIGSEGV (0xb) at pc=0x00007ff8dcb7bdcb, pid=3047, tid=0x00007ff89effd700
#
# JRE version: Java(TM) SE Runtime Environment (8.0_121-b13) (build 1.8.0_121-b13)
# Java VM: Java HotSpot(TM) 64-Bit Server VM (25.121-b13 mixed mode linux-amd64 compressed oops)
# Problematic frame:
# java: /dev/opencv/opencv-3.2.0/modules/objdetect/src/cascadedetect.cpp:922: int cv::CascadeClassifierImpl::runAt(cv::Ptr<cv::FeatureEvaluator>&, cv::Point, int, double&): Assertion `!oldCascade && (data.featureType == FeatureEvaluator::HAAR || data.featureType == FeatureEvaluator ...
Maybe try if the problem persists with pure C++ code to eliminate the Java component?
Also, maybe try to use the same OpenCV configuration everywhere and or compare the different OpenCV configurations to see if the issue is due to a particular OpenCV configuration?
Thank you for the answer,
We can try this way, but what do you think could change? Do you suspect a problem with the Java bindings?
What do you mean for '"configuration"? Because we have built the two opencv versions always in the same way, and the Java code is always the same..
Debug + multithreading is tricky. The best option for me is to eliminate the most possible number of variables and keep a minimal reproducible code everywhere with the same data (no camera stream, one video and copy the mat to all the threads).
In your code, you load two times the cascade file but it should be useless. I suspect you did that because it did not work with only one call, as other people have experienced it. This is not a normal behavior.
Possible causes:
CascadeClassifier
is not thread safe?Also, is it normal an i7 with only two cores? Otherwise, number of physical cores could be a hint?
btw, you should use either the constructor or the load function, not both (double work done)
can you try to comment the cascade.load() functions there ?
Are you sure that the constructor and load() are 'mutually exclusive'? because in some cases, only with the constructor, it not works..Is necessary to call load() to load correctly the xml..
because in some cases, only with the constructor, it not work -- that would be very weird.
"mutually exclusive" might not be the right word here. but it's a bad idea, to throw the whole classifier away, and load it a 2nd time, no ? in general, you'd even want to keep the instance alive for your whole program, not construct and load a classifier per image to process.
I still don't get the whole idea completly. From what I understand, you launch N threads and N threads execute
doFaceRec()
. But you say also thatdoFaceRec()
is protected by a mutex. I suppose you did that just for debugging and it is not the real code for the production, otherwise I don't see the point of the multithreading.For what it's worth, the few advices I could give:
detectMultiScale()
to see if it changes something maybe