Android OpenCv c++;裁剪图像 < >我用OpenCV C++代码成功地检测文档边界。现在,我需要裁剪图像,使其看起来像样

Android OpenCv c++;裁剪图像 < >我用OpenCV C++代码成功地检测文档边界。现在,我需要裁剪图像,使其看起来像样,android,c++,image,opencv,Android,C++,Image,Opencv,如图所示,边界检测效果良好: 但现在,当我试图修剪它时,它看起来是这样的: 现在,这是我使用的代码: extern "C" JNIEXPORT void JNICALL Java_prisca_ctest_ScanActivity_doWithMat(JNIEnv *env, jobject instance, jlong matNumber) { //reference to the image from Java Mat &image = *(Mat *) mat

如图所示,边界检测效果良好:

但现在,当我试图修剪它时,它看起来是这样的:

现在,这是我使用的代码:

extern "C"
JNIEXPORT void JNICALL
Java_prisca_ctest_ScanActivity_doWithMat(JNIEnv *env, jobject instance, jlong matNumber) {
    //reference to the image from Java
    Mat &image = *(Mat *) matNumber;
    //resize image
    image = GetSquareImage(image);
    //add color effects for better detection
    Mat gray;
    cvtColor(image, gray, CV_BGR2GRAY);
    GaussianBlur(gray, gray, Size(5, 5), 0);
    Mat edged;
    Canny(gray, edged, 75, 200);
    //find contours and sort them from biggest to smallest
    vector<vector<Point> > contours;
    vector<Point> screenCnt;
    findContours(edged, contours, RETR_LIST, CHAIN_APPROX_SIMPLE);
    // sort contours
    sort(contours.begin(), contours.end(), compareContourAreas);

    Rect boundRect;

    //itterate over the contours and get the biggest contour for image
    for (int i = (int) (contours.size() - 1); i > 0; i--) {
        double peri = arcLength(Mat(contours[i]), true);
        vector<Point> approx;
        approxPolyDP(Mat(contours[i]), approx, 0.02 * peri, true);
        if (approx.size() == 4) {
            screenCnt = approx;
            boundRect = boundingRect(approx);
            break;
        }
    }
    Scalar color = Scalar(0, 255, 0);
    drawContours(image, Mat(screenCnt), -1, color, 5);
    //crop image with boundRect
    image = Mat(image, boundRect).clone();
}


Mat GetSquareImage(const cv::Mat &img, int target_width = 500) {
    int width = img.cols,
            height = img.rows;

    cv::Mat square = cv::Mat::zeros(target_width, target_width, img.type());

    int max_dim = (width >= height) ? width : height;
    float scale = ((float) target_width) / max_dim;
    cv::Rect roi;
    if (width >= height) {
        roi.width = target_width;
        roi.x = 0;
        roi.height = height * scale;
        roi.y = (target_width - roi.height) / 2;
    } else {
        roi.y = 0;
        roi.height = target_width;
        roi.width = width * scale;
        roi.x = (target_width - roi.width) / 2;
    }

    cv::resize(img, square(roi), roi.size());

    return square;
}


extern "C"
bool compareContourAreas(std::vector<cv::Point> contour1, std::vector<cv::Point> contour2) {
    double i = fabs(contourArea(cv::Mat(contour1)));
    double j = fabs(contourArea(cv::Mat(contour2)));
    return (i < j);
}
extern“C”
JNIEXPORT void JNICALL
Java_prisca_ctest_ScanActivity_doWithMat(JNIEnv*env,jobject实例,jlong matNumber){
//对来自Java的图像的引用
材料和图像=*(材料*)材料编号;
//调整图像大小
image=GetSquareImage(image);
//添加颜色效果以更好地检测
席灰色;
CVT颜色(图像、灰色、CV_bgr2灰色);
高斯模糊(灰色,灰色,大小(5,5),0);
垫边;
坎尼(灰色,边缘,75200);
//找到等高线并将其从最大到最小排序
矢量等值线;
载体筛选;
findContours(边缘、轮廓、修复列表、链近似图和简单图);
//等高线排序
排序(等高线.开始(),等高线.结束(),比较区域);
Rect-boundRect;
//对轮廓进行迭代,得到图像的最大轮廓
对于(inti=(int)(courts.size()-1);i>0;i--){
双周长=弧长(Mat(等高线[i]),真值);
向量近似;
近似多边形(Mat(等高线[i]),约为0.02*peri,真);
如果(大约尺寸()==4){
screenCnt=近似值;
boundRect=boundingRect(近似值);
打破
}
}
标量颜色=标量(0,255,0);
绘制轮廓(图像,垫(屏幕),1,颜色,5);
//使用boundRect裁剪图像
image=Mat(image,boundRect.clone();
}
Mat GetSquareImage(常数cv::Mat&img,int target_width=500){
int width=img.cols,
高度=img.rows;
cv::Mat square=cv::Mat::zero(target_width,target_width,img.type());
int max_dim=(宽度>=高度)?宽度:高度;
浮动比例=((浮动)目标宽度)/最大尺寸;
cv::Rect roi;
如果(宽度>=高度){
roi.width=目标宽度;
roi.x=0;
roi.height=高度*刻度;
roi.y=(目标宽度-roi.height)/2;
}否则{
roi.y=0;
roi.height=目标宽度;
roi.width=宽度*比例;
roi.x=(目标宽度-roi.width)/2;
}
cv::resize(img,square(roi),roi.size());
返回广场;
}
外部“C”
布尔比较区域(标准::矢量轮廓1,标准::矢量轮廓2){
双i=fabs(轮廓面积(cv::Mat(轮廓1));
双j=fabs(轮廓面积(cv::Mat(轮廓2));
返回(i
首先,我遵循了来自的教程。他调整图片大小以获得所需的结果,当我这样做时,我的文本不可读,图像也不会像预期的那样被裁剪(裁剪时没有周围的背景,只有纸张等)


有人有这方面的经验吗?如果有,有人能帮我吗?

看起来您需要使用
rotatedRect
而不是矩形。然后执行扭曲仿射


然后使用
getRotationMatrix2D
()获取旋转角度,旋转图像,按常规进行裁剪,然后旋转回正常状态。

我创建了一个git repo,其中包含用于本机支持的代码,即以正确的方式裁剪图像,请在:


如果您提出了更好的解决方案,请随意编辑代码。

还发现这可能很有用。这看起来很有希望,谢谢。至于图像质量,你能告诉我些什么吗?原始图像本身看起来有点不对焦,因为你的代码根本不会降低图像质量的采样,它可能只是android手机上的摄像头。这可能值得再拍一张图片,让文本更清晰一点。因此,使用我的代码中的函数GetSquareImage不会降低质量?不,它只是拍摄原始图片的一个区域。从技术上讲,它本身的分辨率较低,但它并没有降低图像质量