Cómo determinar una región de interés y luego recortar una imagen utilizando OpenCV

Hice una pregunta similar aquí, pero eso se centra más en tesseract.

Tengo una imagen de muestra como abajo. Me gustaría hacer del cuadrado blanco mi región de interés y luego recortar esa parte (cuadrado) y crear una nueva imagen con ella. Trabajaré con diferentes imágenes para que el cuadrado no siempre esté en la misma ubicación en todas las imágenes. Así que tendré que detectar de alguna manera los bordes del cuadrado.

introduzca la descripción de la imagen aquí

¿Cuáles son algunos métodos de preprocesamiento que puedo realizar para lograr el resultado?

Usando la imagen de prueba, pude eliminar todos los ruidos con una simple operación de erosión .

Después de eso, una simple iteración en el Mat para encontrar los píxeles de la esquina es trivial, y hablé de eso en esta respuesta . Para propósitos de prueba, podemos dibujar líneas verdes entre esos puntos para mostrar el área que nos interesa en la imagen original:

Al final, establezco el ROI en la imagen original y recorté esa parte.

El resultado final se muestra en la siguiente imagen:

Escribí un código de muestra que realiza esta tarea utilizando la interfaz C ++ de OpenCV. Confío en tus habilidades para traducir este código a Python. Si no puede hacerlo, olvide el código y siga la hoja de ruta que compartí en esta respuesta.

 #include  #include  int main(int argc, char* argv[]) { cv::Mat img = cv::imread(argv[1]); std::cout << "Original image size: " << img.size() << std::endl; // Convert RGB Mat to GRAY cv::Mat gray; cv::cvtColor(img, gray, CV_BGR2GRAY); std::cout << "Gray image size: " << gray.size() << std::endl; // Erode image to remove unwanted noises int erosion_size = 5; cv::Mat element = cv::getStructuringElement(cv::MORPH_CROSS, cv::Size(2 * erosion_size + 1, 2 * erosion_size + 1), cv::Point(erosion_size, erosion_size) ); cv::erode(gray, gray, element); // Scan the image searching for points and store them in a vector std::vector points; cv::Mat_::iterator it = gray.begin(); cv::Mat_::iterator end = gray.end(); for (; it != end; it++) { if (*it) points.push_back(it.pos()); } // From the points, figure out the size of the ROI int left, right, top, bottom; for (int i = 0; i < points.size(); i++) { if (i == 0) // initialize corner values { left = right = points[i].x; top = bottom = points[i].y; } if (points[i].x < left) left = points[i].x; if (points[i].x > right) right = points[i].x; if (points[i].y < top) top = points[i].y; if (points[i].y > bottom) bottom = points[i].y; } std::vector box_points; box_points.push_back(cv::Point(left, top)); box_points.push_back(cv::Point(left, bottom)); box_points.push_back(cv::Point(right, bottom)); box_points.push_back(cv::Point(right, top)); // Compute minimal bounding box for the ROI // Note: for some unknown reason, width/height of the box are switched. cv::RotatedRect box = cv::minAreaRect(cv::Mat(box_points)); std::cout << "box w:" << box.size.width << " h:" << box.size.height << std::endl; // Draw bounding box in the original image (debugging purposes) //cv::Point2f vertices[4]; //box.points(vertices); //for (int i = 0; i < 4; ++i) //{ // cv::line(img, vertices[i], vertices[(i + 1) % 4], cv::Scalar(0, 255, 0), 1, CV_AA); //} //cv::imshow("Original", img); //cv::waitKey(0); // Set the ROI to the area defined by the box // Note: because the width/height of the box are switched, // they were switched manually in the code below: cv::Rect roi; roi.x = box.center.x - (box.size.height / 2); roi.y = box.center.y - (box.size.width / 2); roi.width = box.size.height; roi.height = box.size.width; std::cout << "roi @ " << roi.x << "," << roi.y << " " << roi.width << "x" << roi.height << std::endl; // Crop the original image to the defined ROI cv::Mat crop = img(roi); // Display cropped ROI cv::imshow("Cropped ROI", crop); cv::waitKey(0); return 0; } 

Al ver que el texto es el único blob grande, y todo lo demás es apenas más grande que un píxel, una simple apertura morfológica debería ser suficiente

Puedes hacer esto en OpenCV o con imagemgic.

Después, el rectángulo blanco debe ser lo único que queda en la imagen. Puede encontrarlo con opencvs findcontours, con la biblioteca CvBlobs para opencv o con la función imagemgick -crop

Aquí está su imagen con 2 pasos de erosión seguidos de 2 pasos de dilatación aplicada: introduzca la descripción de la imagen aquí Simplemente puede conectar esta imagen en la función opencv findContours como en el ejemplo del tutorial de Squares para obtener la posición