Dear OpenCV team! Need your help again and sorry for such a long question.
I'm trying to generate java wrappers for OpenCV OCR Text/Tesseract module, which is in contrib repository now. Here is what I managed so far (skipping all the trivial stuff like enabling contrib, installing tesseract etc):
- Changed modules/text/CMakeLists.txt, added "java".
Added methods to ERFilter as follows:
CV_EXPORTS_W Ptr<erfilter> createERFilterNM1(const String& filename, int thresholdDelta = 1, float minArea = (float)0.00025, float maxArea = (float)0.13, float minProbability = (float)0.4, bool nonMaxSuppression = true, float minProbabilityDiff = (float)0.1) { return createERFilterNM1(loadClassifierNM1(filename), thresholdDelta, minArea, maxArea, minProbability, nonMaxSuppression, minProbabilityDiff); }
CV_EXPORTS_W Ptr<erfilter> createERFilterNM2(const String& filename, float minProbability = (float)0.3) { return createERFilterNM2(loadClassifierNM2(filename), minProbability); }
The idea was to merge interfaces loadClassifierNM1 and loadClassifierNM2 with "native" createERFilterNM1 and createERFilterNM2, respectively and get rid of necessity to wrap Ptr<erfilter::callback>& type in Java.
- Made ERFilter orphan - removed inheritance from Algorithm. I did not get the reason why it has to be inherited. The side effect of inheritance was - when java wrapper is handling method argumenths of type Ptr_* (like in the function detectRegions), it actually passes nativeObj field through JNI C wrapper. This field is declared as protected in Algorithm so it can be accessed only by children of Algorithm or by classes in the same package. Since Text is in different package and even different repository, the generation of java wrappers fails. Making ERFilter orphan haps to resolve this problem.
After these 3 steps java wrapper for Text module is generated successfully. However! This code crashes java with Exception Type EXC_BAD_ACCESS (SIGABRT):
private List<rect> findContours2(Mat img) { List<rect> boundRects = new ArrayList<rect>();
List<Mat> channels = new ArrayList<>();
Text.computeNMChannels(img, channels);
System.out.println("Extracting Class Specific Extremal Regions from "+channels.size()+" channels ...");
ERFilter erc1 = Text.createERFilterNM1(getClass().getResource(DEFAULT_CLASSIFIER_NM1).getPath(),16,0.00015f,0.13f,0.2f,true,0.1f);
ERFilter erc2 = Text.createERFilterNM2(getClass().getResource(DEFAULT_CLASSIFIER_NM2).getPath(), 0.5f);
for(Mat channel : channels) {
List<MatOfPoint> regions = new ArrayList<>();
Text.detectRegions(channel, erc1, erc2, regions); // **Java fails here with Exception Type: EXC_BAD_ACCESS (SIGABRT)**
MatOfRect mor = new MatOfRect();
Text.erGrouping(image, channel, regions, mor);
for(Rect r : mor.toArray()) {
boundRects.add(r);
}
}
return boundRects;
}
The crash seems to be happening in JNI C layer. Here is the source generated for detectRegions method:
JNIEXPORT void JNICALL Java_org_opencv_text_Text_detectRegions_10 (JNIEnv*, jclass, jlong, jlong, jlong, jlong);
JNIEXPORT void JNICALL Java_org_opencv_text_Text_detectRegions_10
(JNIEnv* env, jclass , jlong image_nativeObj, jlong er_filter1_nativeObj, jlong er_filter2_nativeObj, jlong regions_mat_nativeObj)
{
static const char method_name[] = "text::detectRegions_10()";
try {
LOGD("%s", method_name);
std::vector< std::vector<Point> > regions;
Mat& regions_mat = *((Mat*)regions_mat_nativeObj);
Mat& image = *((Mat*)image_nativeObj);
cv::text::detectRegions( image, Ptr<cv::text::ERFilter>((cv::text::ERFilter*)er_filter1_nativeObj), Ptr<cv::text::ERFilter>((cv::text::ERFilter*)er_filter2_nativeObj), regions );
vector_vector_Point_to_Mat( regions, regions_mat );
return;
} catch(const std::exception &e) {
throwJavaException(env, &e, method_name);
} catch (...) {
throwJavaException(env, 0, method_name);
}
return;
}
It seems the Ptr pointer is used incorrectly but I can't figure out the correct way for this case. Any ideas or help would be very much appreciated.