问题描述
  真实案例,扫描仪扫描到的法律文件,需要切边,去掉边 缘空白,这样看上去才真实。

opencv实践::切边-风君雪科技博客

#include <opencv2/opencv.hpp>
#include <iostream>
#include <math.h>

using namespace cv;
using namespace std;

#define IMAGE_PATH "D:/case2.png"

Mat src, gray_src, tmp_src, dst;
int threshold_value = 100;
int max_level = 255;
const char* roi_win = "Final Result";

void FindROI(int, void*);

void Check_Skew(int, void*);


int main(int argc, char** argv) {
    src = imread(IMAGE_PATH);
    if (src.empty()) {
        printf("could not load image...
");
        return -1;
    }
    namedWindow("input image", CV_WINDOW_AUTOSIZE);
    imshow("input image", src);
    
    //纠正图像角度
    Check_Skew(0, 0);

    //图像切边
    FindROI(0, 0);

    waitKey(0);
    return 0;
}

void Check_Skew(int, void*) {
    //寻找最大轮廓
    Mat canny_output;
    cvtColor(src, gray_src, COLOR_BGR2GRAY);
    //Canny 算法做边缘检测 
    Canny(gray_src, canny_output, threshold_value, threshold_value * 2, 3, false);

    //在二值图像中寻找轮廓 
    vector<vector<Point>> contours;
    vector<Vec4i> hireachy;
    findContours(canny_output, contours, hireachy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));

    //创建一张黑色的图,每个像素的每个通道都为0,Scalar(0,0,0)
    //Mat drawImg = Mat::zeros(src.size(), CV_8UC3);

    float maxw = 0;//矩形宽
    float maxh = 0;//矩形高
    double degree = 0;
    for (size_t t = 0; t < contours.size(); t++) {
        RotatedRect minRect = minAreaRect(contours[t]);
        //矩形角度绝对值
        degree = abs(minRect.angle);
        if (degree > 0) {
            maxw = max(maxw, minRect.size.width);
            maxh = max(maxh, minRect.size.height);
        }
        if (degree > 0) {
            if (maxw == minRect.size.width && maxh == minRect.size.height) {
                degree = minRect.angle;
            }
        }
    }
    printf("max contours width : %f
", maxw);
    printf("max contours height : %f
", maxh);
    printf("max contours angle : %f


", degree);

    //寻找几何中心
    Point2f center(src.cols / 2, src.rows / 2);
    //旋转degree角度
    Mat rotm = getRotationMatrix2D(center, degree, 1.0);
    //对图像做仿射变换
    warpAffine(src, tmp_src, rotm, src.size(), INTER_LINEAR, 0, Scalar(255, 255, 255));
    imshow("Correct Image", tmp_src);
}

void FindROI(int, void*) {
    //灰度图
    cvtColor(tmp_src, gray_src, COLOR_BGR2GRAY);
    Mat canny_output;
    //Canny 算法做边缘检测 
    Canny(gray_src, canny_output, threshold_value, threshold_value * 2, 3, false);

    //在二值图像中寻找轮廓 
    vector<vector<Point>> contours;
    vector<Vec4i> hireachy;
    findContours(canny_output, contours, hireachy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));

    //定义最小轮廓
    float minw = tmp_src.cols*0.5;
    float minh = tmp_src.rows*0.5;
    
    float minstW = 0.0;
    bool  bfirst = true;
    RotatedRect minstRect;
    Rect bbox;
    for (size_t t = 0; t < contours.size(); t++) {
        RotatedRect minRect = minAreaRect(contours[t]);
        if (minRect.size.width > minw && minRect.size.height > minh && minRect.size.width < (src.cols - 20)) {
            {
                //找宽度最小的矩形,既是要找的图像。
                printf("t = %d, w = %f , h = %f 
",t, minRect.size.width, minRect.size.height);
                if (bfirst)
                {
                    minstW = minRect.size.width;
                    minstRect = minRect;
                    bfirst = false;
                }
                else
                {
                    float tmp = min(minstW, minRect.size.width);
                    if (tmp < minstW)
                    {
                        minstW = tmp;
                        minstRect = minRect;
                    }
                }
            }
        }
    }
    bbox = minstRect.boundingRect();
    if (bbox.width > 0 && bbox.height > 0) {
        Mat roiImg = tmp_src(bbox);
        imshow(roi_win, roiImg);
    }
    return;
}