如何从python中的图像(文档形式)中裁剪空白部分?

时间:2019-03-06 12:37:09

标签: python opencv python-imaging-library

enter image description here我有一份文档的扫描件作为用户提交的图像,它仅覆盖纸张高度的40%。我只想裁剪那部分,如何实现。 不必总是将所需的表格放在纸的顶部,可以在任何地方,其余的是白纸,如何裁剪该部分?

我仅使用python制成的扫描仪获得的扫描副本,因此页面上几乎没有黑点。

1 个答案:

答案 0 :(得分:0)

您可以考虑以下步骤来裁剪空白或不空白的部分:

cv::namedWindow("result", cv::WINDOW_FREERATIO);
cv::Mat img = cv::imread(R"(xbNQF.png)"); // read the image

// main code starts from here
cv::Mat gray; // convert the image to gray and put the result in gray mat
cv::cvtColor(img, gray, cv::COLOR_BGR2GRAY); // img -> gray
// threshold the gray image to remove the noise and put the result again in gray image
// it will convert all the background to black and all the text and fields to white
cv::threshold(gray, gray, 150, 255, cv::THRESH_BINARY_INV);

// now enlage the text or the inpout text fields
cv::dilate(gray, gray, cv::getStructuringElement(cv::MORPH_RECT, cv::Size(15, 3)));
// now clean the image, remove unwanted small pixels
cv::erode(gray, gray, cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3)));

// find all non zero to get the max y
cv::Mat idx; // the findNonZero() function will put the result in this mat
cv::findNonZero(gray, idx); // pass the mat idx to the function
// now iterate throgh the idx to find the max y
double maxY = 0; // this will keep the max y, init value is 0
for (int i=0; i<idx.rows; ++i) {
    cv::Point pnt = idx.at<cv::Point>(i);
    if (pnt.y > maxY) { // if this Y is greater than the last Y, copy it to the last Y
        maxY = pnt.y; // this
    }
}

// crop the none blank (upper) part
// NOTE: from this point you can also crop the blank part
// (0,0) means start form left-top, (gray.cols, int(maxY+5)) means 
// whidth the same as the original image, and the height is
// the maxY + 5, 5 here means let give some margin the cropped image
// if you don't want, then you can delete it.
cv::Mat submat = img(cv::Rect(0, 0, gray.cols, int(maxY+5)));
cv::imshow("result", submat);

cv::waitKey();

结果如下:

enter image description here

希望有帮助!

更新: 如果您对(x,y)的所有最小值,最大值感兴趣,则可以这样搜索:

double maxX = 0, minX = std::numeric_limits<double>::max();
double maxY = 0, minY = std::numeric_limits<double>::max();
for (int i=0; i<idx.rows; ++i) {
    cv::Point pnt = idx.at<cv::Point>(i);
    if (pnt.x > maxX) {
        maxX = pnt.x;
    }
    if (pnt.x < minX) {
        minX = pnt.x;
    }
    if (pnt.y > maxY) {
        maxY = pnt.y;
    }
    if (pnt.y < minY) {
        minY = pnt.y;
    }
}

因此,一旦拥有这些点,便可以在图像的任何位置进行裁剪。