I am working on Android+OpenCv+JNI to find out the largest contour in the image and then cropping that largest Contour using perspective transformation. My problem is after applying transformation I am not able to convert resultant Mat to Bitmap and returning with error
OpenCV Error: Assertion failed (src.type() == CV_8UC1 || src.type() == CV_8UC3 || src.type() == CV_8UC4) in void Java_org_opencv_android_Utils_nMatToBitmap2(JNIEnv*, jclass, jlong, jobject, jboolean), file /home/reports/ci/slave_desktop/50-SDK/opencv/modules/java/generator/src/cpp/utils.cpp, line 98
Here is my JNI code:
JNIEXPORT jint JNICALL Java_org_opencv_samples_tutorial3_Sample3Native_FindSquares(
JNIEnv* env, jobject, jlong addrRgba, jint draw, jlong addrDescriptor) {
Mat& image = *(Mat*) addrRgba;
Mat& pMatDesc = *(Mat*) addrDescriptor;
int thresh = 50, N = 4;
int found = 0;
Mat pyr, timg, gray0(image.size(), CV_8U), gray;
// down-scale and upscale the image to filter out the noise
pyrDown(image, pyr, Size(image.cols / 2, image.rows / 2));
pyrUp(pyr, timg, image.size());
vector < vector<Point> > contours;
// find squares in every color plane of the image
for (int c = 1; c < 3; c++) {
int ch[] = { c, 0 };
mixChannels(&timg, 1, &gray0, 1, ch, 1);
// try several threshold levels
for (int l = 0; l < N; l++) {
// hack: use Canny instead of zero threshold level.
// Canny helps to catch squares with gradient shading
if (l == 0) {
// apply Canny. Take the upper threshold from slider
// and set the lower to 0 (which forces edges merging)
Canny(gray0, gray, 0, thresh, 5);
// dilate canny output to remove potential
// holes between edge segments
dilate(gray, gray, Mat(), Point(-1, -1));
} else {
// apply threshold if l!=0:
// tgray(x,y) = gray(x,y) < (l+1)*255/N ? 255 : 0
gray = gray0 >= (l + 1) * 255 / N;
}
// find contours and store them all as a list
findContours(gray, contours, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE);
vector<Point> approx;
// test each contour
for (size_t i = 0; i < contours.size(); i++) {
//__android_log_print(ANDROID_LOG_INFO, "Test", "Error:", v);
// approximate contour with accuracy proportional
// to the contour perimeter
approxPolyDP(Mat(contours[i]), approx,
arcLength(Mat(contours[i]), true) * 0.02, true);
// square contours should have 4 vertices after approximation
// relatively large area (to filter out noisy contours)
// and be convex.
// Note: absolute value of an area is used because
// area may be positive or negative - in accordance with the
// contour orientation
if (approx.size() == 4 && fabs(contourArea(Mat(approx))) > 1000
&& isContourConvex(Mat(approx))) {
double maxCosine = 0;
for (int j = 2; j < 5; j++) {
// find the maximum cosine of the angle between joint edges
double cosine = fabs(
angle(approx[j % 4], approx[j - 2],
approx[j - 1]));
maxCosine = MAX(maxCosine, cosine);
}
// if cosines of all angles are small
// (all angles are ~90 degree) then write quandrange
// vertices to resultant sequence
if (maxCosine < 0.3) {
circle(image, approx[0], 5, Scalar(255, 0, 0, 255), 3,
4, 0);
circle(image, approx[1], 5, Scalar(255, 0, 0, 255), 3,
4, 0);
circle(image, approx[2], 5, Scalar(255, 0, 0, 255), 3,
4, 0);
circle(image, approx[3], 5, Scalar(255, 0, 0, 255), 3,
4, 0);
//rectangle(image, approx[0], approx[2], Scalar(0,255,0,255), 5, 4, 0);
//Center of this rectangle
int x = (int) ((approx[0].x + approx[1].x + approx[2].x
+ approx[3].x) / 4.0);
int y = (int) ((approx[0].y + approx[1].y + approx[2].y
+ approx[3].y) / 4.0);
if ((int) draw) {
//outline
line(image, approx[0], approx[1],
Scalar(0, 255, 0, 255), 1, 4, 0);
line(image, approx[1], approx[2],
Scalar(0, 255, 0, 255), 1, 4, 0);
line(image, approx[2], approx[3],
Scalar(0, 255, 0, 255), 1, 4, 0);
line(image, approx[3], approx[0],
Scalar(0, 255, 0, 255), 1, 4, 0);
//center
//circle(image, Point(x,y), 1, Scalar(255,0,0,255));
}
vector<Point2f> src(4);
src[0] = approx[0];
src[1] = approx[1];
src[2] = approx[2];
src[3] = approx[3];
cv::Mat quad = cv::Mat::zeros(300, 220, CV_32FC1 );
// transformed quadrangle
vector<Point2f> quad_pts(4);
quad_pts[0] = Point(0, 0);
quad_pts[1] = Point(quad.cols, 0);
quad_pts[2] = Point(quad.cols, quad.rows);
quad_pts[3] = Point(0, quad.rows);
Mat transmtx = getPerspectiveTransform(src, quad_pts);
warpPerspective(src, quad, transmtx, quad.size());
quad.copyTo(pMatDesc);
found = 1;
jint result = (jint) found;
return result;
}
}
}
}
}
jint result = (jint) found;
return result;
}
In my java code I am calling this function as
found = FindSquares(mRgba.getNativeObjAddr(), mDraw, descriptor.getNativeObjAddr());
And finally I am trying to convert final Mat to Bitmap
Mat final_mat = new Mat(descriptor.height(), descriptor.width(), CvType.CV_8UC4);
descriptor.copyTo(final_mat);
bitmap = Bitmap.createBitmap(final_mat.cols(), final_mat.rows(),
Bitmap.Config.ARGB_8888);
Utils.matToBitmap(final_mat, bitmap);
The final_mat channel type is becoming CV_32FC1. How to convert the channel type to CV_8UC4 Please help me to find out the solution.
Edit: I have changed the finat_mat image to CV_8UC3
descriptor.copyTo(final_mat);
descriptor.convertTo(final_mat, CvType.CV_8UC1);
Imgproc.cvtColor(final_mat,final_mat,Imgproc.COLOR_GRAY2RGB);
But I am getting blank(Black) image as a result??