我正在使用 Android+OpenCv+JNI 来找出图像中最大的轮廓,然后使用透视变换裁剪最大的轮廓。我的问题是应用转换后我无法将结果 Mat 转换为 Bitmap 并返回错误
OpenCV 错误:断言失败 (src.type() == CV_8UC1 || src.type() == CV_8UC3 || src.type() == CV_8UC4) 在 void Java_org_opencv_android_Utils_nMatToBitmap2(JNIEnv*, jclass, jlong, jobject, jboolean) ,文件/home/reports/ci/slave_desktop/50-SDK/opencv/modules/java/generator/src/cpp/utils.cpp,第98行
这是我的 JNI 代码:
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;
}
在我的 java 代码中,我将此函数称为
找到 = FindSquares(mRgba.getNativeObjAddr(), mDraw, descriptor.getNativeObjAddr());
最后我试图将最终的 Mat 转换为 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);
final_mat 通道类型变为 CV_32FC1。如何将通道类型转换为 CV_8UC4 请帮我找出解决方案。
编辑:我已将 finat_mat 图像更改为 CV_8UC3
descriptor.copyTo(final_mat);
descriptor.convertTo(final_mat, CvType.CV_8UC1);
Imgproc.cvtColor(final_mat,final_mat,Imgproc.COLOR_GRAY2RGB);
但是结果我得到了空白(黑色)图像?