как обрезать пустую часть из изображения (формы документа) в python?

#python #opencv #python-imaging-library

#python #opencv #python-imaging-library

Вопрос:

введите описание изображения здесьУ меня есть отсканированная копия документа в виде изображения, отправленного пользователем, она занимает только 40% высоты листа. Я хочу обрезать только эту часть, как этого добиться. Необязательно, чтобы требуемая форма всегда была сверху листа, она может быть где угодно, а остальное — чистая белая бумага, как обрезать эту часть?

Отсканированная копия, которую я получил с помощью scanner, сделана только на python, поэтому на странице есть маленькие черные точки.

Комментарии:

1. Хорошей отправной точкой для ответа были бы некоторые материалы для тестирования и ваш текущий подход

2. Я пытался найти похожее изображение, но не смог найти, и я не могу отправить исходный документ вот так. Это всего лишь половина высоты листа формата а4, но пользователь сначала распечатал этот документ и отправил этот лист формата а4 в виде отсканированной копии, мне нужно обрезать только эту форму.

3. Можете ли вы поделиться образцом изображения и ожидаемым результатом?

4. Я предоставил общий доступ к изображению, мне нужна только часть содержимого, как вы видите, 70% части пусто. Но необязательно, чтобы сторона содержимого всегда была сверху.

5. Используйте пороговое значение , чтобы (более или менее) белой частью пренебрегали (используйте THRESH_BINARY_INV параметр). Затем просто выполните итерацию по изображению в поисках минимального и максимального x и y значений с помощью value 255 . Эти четыре точки описывают прямоугольник, в котором должно присутствовать что-либо небелое.

Ответ №1:

Вы можете выполнить следующие шаги, чтобы обрезать пустую или непустую часть:

 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();
  

И это результат:

введите описание изображения здесь

Надеюсь, это поможет!

Обновить:Если вас интересуют все минимальные и максимальные значения (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;
    }
}
  

Таким образом, вы можете обрезать любую часть изображения, как только у вас появятся эти точки.

Комментарии:

1. Это (частично) то, что я предложил. Тем не менее, поскольку вы ищете только maxY , результат вашего решения для изображений, где интересная часть находится внизу, не будет таким, как хотелось бы автору вопроса, с которого вы всегда начинаете (0, 0) .

2. Обновлен ответ @HansHirse. Я уже выполнил самую важную часть алгоритма, остальное вы можете сделать сами.

3. @KaranKanwal Большая часть кода очень понятна, он просто использует OpenCV API. cv:: это пространство имен на C , в Python вы можете использовать cv. вместо этого. И double это тип данных, для которого в Python вам не нужно объявлять тип. Я не могу писать код на Python, но вы можете просто рассмотреть шаги, которые я реализовал в алгоритме, и преобразовать его в Python, или вы можете рассказать кому-нибудь из своих друзей о коде C , чтобы преобразовать его в Python. Этот скрипт уже выполняет то, что вы хотите в своем вопросе.

4. хорошо, конечно, я попробую это. прямо сейчас я просто пишу код, просматривая ваш код.

5. @KaranKanwal Если вы знакомы с OpenCV API, то вы можете легко догадаться, что я написал на C , по большей части это относится не к используемому языку, а к реализованным шагам. Так что пусть вас не смущает приведенный выше код на C . Удачи!