Comment puis-je convertir une BufferedImage en un Mat dans OpenCV? J'utilise le Java wrapper pour OpenCV (pas JavaCV). Comme je suis nouveau sur OpenCV, j'ai quelques problèmes pour comprendre comment fonctionne Mat.
Je veux faire quelque chose comme ça. (D'après la réponse de Ted W.):
BufferedImage image = ImageIO.read(b.getClass().getResource("Lena.png"));
int rows = image.getWidth();
int cols = image.getHeight();
int type = CvType.CV_16UC1;
Mat newMat = new Mat(rows,cols,type);
for(int r=0; r<rows; r++){
for(int c=0; c<cols; c++){
newMat.put(r, c, image.getRGB(r, c));
}
}
Highgui.imwrite("Lena_copy.png",newMat);
Ça ne marche pas. "Lena_copy.png" est juste une image noire avec les bonnes dimensions.
J'essayais également de faire la même chose, en raison de la nécessité de combiner l'image traitée avec deux bibliothèques. Et ce que j'ai essayé de faire, c'est de mettre byte[]
dans Mat
au lieu de la valeur RVB. Et ça a marché! Donc ce que j'ai fait, c'est:
1.Converti BufferedImage
en tableau d'octets avec:
byte[] pixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
2. Ensuite, vous pouvez simplement le mettre à Mat si vous définissez le type sur CV_8UC3
image_final.put(0, 0, pixels);
Edit: Vous pouvez également essayer de faire l'inverse comme sur cette réponse
Celui-ci a bien fonctionné pour moi, et il faut de 0 à 1 ms pour être exécuté.
public static Mat bufferedImageToMat(BufferedImage bi) {
Mat mat = new Mat(bi.getHeight(), bi.getWidth(), CvType.CV_8UC3);
byte[] data = ((DataBufferByte) bi.getRaster().getDataBuffer()).getData();
mat.put(0, 0, data);
return mat;
}
Vous ne voulez pas gérer un grand tableau de pixels? Utilisez simplement ceci
BufferedImage to Mat
public static Mat BufferedImage2Mat(BufferedImage image) throws IOException {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ImageIO.write(image, "jpg", byteArrayOutputStream);
byteArrayOutputStream.flush();
return Imgcodecs.imdecode(new MatOfByte(byteArrayOutputStream.toByteArray()), Imgcodecs.CV_LOAD_IMAGE_UNCHANGED);
}
Mat à BufferedImage
public static BufferedImage Mat2BufferedImage(Mat matrix)throws IOException {
MatOfByte mob=new MatOfByte();
Imgcodecs.imencode(".jpg", matrix, mob);
return ImageIO.read(new ByteArrayInputStream(mob.toArray()));
}
Remarque, bien que ce soit très négligeable. Cependant, de cette manière, vous pouvez obtenir une solution fiable mais elle utilise l'encodage + le décodage. Vous perdez donc des performances. C'est généralement de 10 à 20 millisecondes. JPG l'encodage perd de la qualité de l'image aussi c'est lent (cela peut prendre 10 à 20 ms). BMP est sans perte et rapide (1 ou 2 ms) mais nécessite un peu plus de mémoire (négligeable). PNG est sans perte mais un peu plus de temps pour encoder que BMP. L'utilisation de BMP devrait convenir à la plupart des cas, je pense.
J'ai trouvé une solution ici . La solution est similaire à Andriys.
Camera c;
c.Connect();
c.StartCapture();
Image f2Img, cf2Img;
c.RetrieveBuffer(&f2Img);
f2Img.Convert( FlyCapture2::PIXEL_FORMAT_BGR, &cf2Img );
unsigned int rowBytes = (double)cf2Img.GetReceivedDataSize()/(double)cf2Img.GetRows();
cv::Mat opencvImg = cv::Mat( cf2Img.GetRows(), cf2Img.GetCols(), CV_8UC3, cf2Img.GetData(),rowBytes );
J'utilise le code suivant dans mon programme.
protected Mat img2Mat(BufferedImage in) {
Mat out;
byte[] data;
int r, g, b;
if (in.getType() == BufferedImage.TYPE_INT_RGB) {
out = new Mat(in.getHeight(), in.getWidth(), CvType.CV_8UC3);
data = new byte[in.getWidth() * in.getHeight() * (int) out.elemSize()];
int[] dataBuff = in.getRGB(0, 0, in.getWidth(), in.getHeight(), null, 0, in.getWidth());
for (int i = 0; i < dataBuff.length; i++) {
data[i * 3] = (byte) ((dataBuff[i] >> 0) & 0xFF);
data[i * 3 + 1] = (byte) ((dataBuff[i] >> 8) & 0xFF);
data[i * 3 + 2] = (byte) ((dataBuff[i] >> 16) & 0xFF);
}
} else {
out = new Mat(in.getHeight(), in.getWidth(), CvType.CV_8UC1);
data = new byte[in.getWidth() * in.getHeight() * (int) out.elemSize()];
int[] dataBuff = in.getRGB(0, 0, in.getWidth(), in.getHeight(), null, 0, in.getWidth());
for (int i = 0; i < dataBuff.length; i++) {
r = (byte) ((dataBuff[i] >> 0) & 0xFF);
g = (byte) ((dataBuff[i] >> 8) & 0xFF);
b = (byte) ((dataBuff[i] >> 16) & 0xFF);
data[i] = (byte) ((0.21 * r) + (0.71 * g) + (0.07 * b));
}
}
out.put(0, 0, data);
return out;
}
Référence: ici
Une façon simple serait de créer un nouveau
Mat newMat = Mat(rows, cols, type);
puis récupérez les valeurs en pixels de votre BufferedImage et mettez-les dans newMat en utilisant
newMat.put(row, col, pixel);