Como habréis podido leer en el título este es un asunto relacionado con programación en Java para una app Android usando la librería openCV. En resumidas cuentas el programa carga una red neuronal que ya hemos entrenado con una batería de imágenes. El programa original, por comodidad y por poca experiencia lo codificamos en Java pensando que como Android y Java van bastante de la mano no habría una dificultad grande a la hora de traducirlo para una app, bien el problema parte a la hora de proporcionarle la entrada a la red neuronal.
Código
Mat frame = new Mat(); // Matriz de OpenCv Mat fgMask = new Mat(); MatOfByte mem = new MatOfByte(); BackgroundSubtractor backSub; backSub = Video.createBackgroundSubtractorKNN(5, 0, false); VideoCapture capture = new VideoCapture(0); // Captura camara por defecto if (!capture.isOpened()) { } while (true) { capture.read(frame); if (frame.empty()) { break; } Imgproc.cvtColor(frame, frame, Imgproc.COLOR_BGR2GRAY, 0);//Imagen a Escala de grises Imgproc.GaussianBlur(frame, frame, new Size(15, 15), 0); //Aplicamos un Suavizado backSub.apply(frame, fgMask); //Eliminamos fondo de frame y guardamos en fgMask Imgproc.resize(fgMask, fgMask, new Size(250, 250)); //redimensionamos // Aquí es donde hicimos el apaño para java, que no puede funcionar en Android // Puesto que BufferedImage e Image no existen en las librerias para Android Mat image= new Mat(); Imgcodecs.imencode(".jpg", fgMask, mem); try { image = BufferedImage2Mat(buff); Logger.getLogger(VideoCaptureejemplo.class.getName()).log(Level.SEVERE, null, ex); } Mat blob = blobFromImage(image,1 ,new Size(250,250)); clasificador.setInput(blob); Mat res = clasificador.forward(); } } ImageIO.write(image, "jpg", byteArrayOutputStream); byteArrayOutputStream.flush(); return Imgcodecs.imdecode(new MatOfByte(byteArrayOutputStream.toByteArray()), CV_32FC1); }
Testeando y probando he llegado a la conclusión que a pesar de que la función BlobFromImage solicita una Matriz como primer parametro esta debe de estar construida de una forma un poco más especial, si yo trato de enviar una Matriz como fgMask en vez de una BufferedImage lanzará un error:
Contenido de fgMask:
Mat [ 1*1*250*250*CV_32FC1, isCont=true, isSubmat=false, nativeObj=0x1fb55df0, dataAddr=0x23991140 ]
Contenido de fgMask(BufferedImage):
Mat [ 1*3*250*250*CV_32FC1, isCont=true, isSubmat=false, nativeObj=0x1f59f110, dataAddr=0x21d63c00 ]
Código del Error:
Código:
[ERROR:0] global C:\build\master_winpack-bindings-win64-vc14-static\opencv\modules\dnn\src\dnn.cpp (3512) cv::dnn::dnn4_v20210608::Net::Impl::getLayerShapesRecursively OPENCV/DNN: [Convolution]:(sequential/conv2d/Conv2D): getMemoryShapes() throws exception. inputs=1 outputs=0/1 blobs=2
[ERROR:0] global C:\build\master_winpack-bindings-win64-vc14-static\opencv\modules\dnn\src\dnn.cpp (3515) cv::dnn::dnn4_v20210608::Net::Impl::getLayerShapesRecursively input[0] = [ 1 1 250 250 ]
[ERROR:0] global C:\build\master_winpack-bindings-win64-vc14-static\opencv\modules\dnn\src\dnn.cpp (3523) cv::dnn::dnn4_v20210608::Net::Impl::getLayerShapesRecursively blobs[0] = CV_32FC1 [ 16 3 3 3 ]
[ERROR:0] global C:\build\master_winpack-bindings-win64-vc14-static\opencv\modules\dnn\src\dnn.cpp (3523) cv::dnn::dnn4_v20210608::Net::Impl::getLayerShapesRecursively blobs[1] = CV_32FC1 [ 16 1 ]
[ERROR:0] global C:\build\master_winpack-bindings-win64-vc14-static\opencv\modules\dnn\src\dnn.cpp (3525) cv::dnn::dnn4_v20210608::Net::Impl::getLayerShapesRecursively Exception message: OpenCV(4.5.3) C:\build\master_winpack-bindings-win64-vc14-static\opencv\modules\dnn\src\layers\convolution_layer.cpp:386: error: (-2:Unspecified error) Number of input channels should be multiple of 3 but got 1 in function 'cv::dnn::ConvolutionLayerImpl::getMemoryShapes'
Exception in thread "main" CvException [org.opencv.core.CvException: cv::Exception: OpenCV(4.5.3) C:\build\master_winpack-bindings-win64-vc14-static\opencv\modules\dnn\src\layers\convolution_layer.cpp:386: error: (-2:Unspecified error) Number of input channels should be multiple of 3 but got 1 in function 'cv::dnn::ConvolutionLayerImpl::getMemoryShapes'
]
at org.opencv.dnn.Net.forward_1(Native Method)
at org.opencv.dnn.Net.forward(Net.java:237)
¿Alguien sabe como cambiar o qué significa el segundo digito en la información de las matrices que he puesto arriba? No sé pero siento que de modificar ese caracter sin recurrir a la chapuza de BufferedImage se podría solucionar todo fácilmente.