Estoy tratando de traducir la siguiente función de Python, que aplica una máscara a una imagen, a Java:
# Applies an image mask. def region_of_interest(img, vertices): #defining a blank mask to start with mask = np.zeros_like(img) #defining a 3 channel or 1 channel color to fill the mask with depending on the input image if len(img.shape) > 2: channel_count = img.shape[2] # ie 3 or 4 depending on your image ignore_mask_color = (255,) * channel_count else: ignore_mask_color = 255 #filling pixels inside the polygon defined by "vertices" with the fill color cv2.fillPoly(mask, vertices, ignore_mask_color) #returning the image only where mask pixels are nonzero masked_image = cv2.bitwise_and(img, mask) return masked_imageHasta ahora, esto es lo que tengo:
public static opencv_core.Mat applyMask(opencv_core.Mat image, opencv_core.MatVector vertices) { opencv_core.Mat mask = opencv_core.Mat.zeros(image.size(), opencv_core.CV_8U).asMat(); opencv_core.Scalar color = new opencv_core.Scalar(image.channels()); // 3 double[] colors = new double[] { 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0, 255.0}; color.put(colors, 0, colors.length); opencv_imgproc.fillPoly(mask, vertices, color); opencv_core.Mat dst = new opencv_core.Mat(); opencv_core.bitwise_and(image, mask, dst); return dst; }Pero, no está funcionando. Cuando intento invocar este método como en el siguiente ejemplo:
opencv_core.MatVector points = new opencv_core.MatVector( new opencv_core.Mat(2, 3, opencv_core.CV_32F, new IntPointer(1, 2, 3, 4, 5, 6)) ); opencv_core.MatVector vertices = new opencv_core.MatVector(points); opencv_core.Mat masked = LaneManager.applyMask(src, vertices); (Supongo que esta es la forma correcta de construir una matriz de 2x3 de tres puntos con dos coordenadas cada uno (1,2) , (3, 4) y (5,6) )
Obtengo una excepción:
java.lang.RuntimeException: std::bad_alloc at org.bytedeco.javacpp.opencv_imgproc.fillPoly(Native Method) Estoy usando OpenCV proporcionado por org.bytedeco.javacpp-presets:opencv-platform:3.2.0-1.3 a través de Maven Central.
Debo admitir que estoy perdido aquí: ¿Cuál es la forma idiomática de Java de hacer lo mismo que la función de Python anterior?
Muy bien, finalmente lo descubrí. Si define sus coordenadas con:
int[] points = new int[] {x1, y1, x2, y2, ...};Luego, simplemente puede aplicar una máscara con el siguiente código:
opencv_core.Mat mask = new opencv_core.Mat(image.size(), image.type()); // Array of polygons where each polygon is represented as an array of points opencv_core.Point polygon = new opencv_core.Point(); polygon.put(points, 0, points.length); opencv_imgproc.fillPoly(mask, polygon, new int[] {points.length / 2}, 1, new opencv_core.Scalar(255, 255, 255, 0)); opencv_core.Mat masked = new opencv_core.Mat(image.size(), image.type()); opencv_core.bitwise_and(image, mask, masked); Donde image es la imagen original y masked es el resultado enmascarado.
El problema era que la lista original de puntos no estaba definida correctamente.
Tal vez algún genio tenga las respuestas completas. Aquí hay algo para pensar:
El error
std::bad_allococurre cuando no puede asignar el espacio de almacenamiento requerido. ( http://answers.opencv.org/question/28959/cascade-training-killed-and-bad_alloc/ )
void fillPoly(Mat& img, const Point** pts, const int* npts, int ncontours, const Scalar& color, int lineType=LINE_8, int shift=0, Point offset=Point() ) , yvoid fillPoly(InputOutputArray img, InputArrayOfArrays pts, const Scalar& color, int lineType=LINE_8, int shift=0, Point offset=Point() )No necesita convertir de
MataInputArray, pero puede (y debe) simplemente pasar un objetoMatdonde se solicita unInputArray( https://stackoverflow.com/a/32976883/1587329 )