Conversion de BufferedImage en Mat à opencv
Comment puis-je convertir un BufferedImage en un tapis en OpenCV? J'utilise le java wrapper pour OpenCV (pas JavaCV). Comme je suis nouveau à OpenCV j'ai quelques problèmes à 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);
Cela ne fonctionne pas. "Lena_copie.png " est juste une image noire avec les dimensions correctes.
7 réponses
j'essayais aussi de faire la même chose, à cause de la nécessité de combiner l'image traitée avec deux bibliothèques. Et ce que j'ai essayé de faire est de mettre byte[]
Mat
au lieu de la valeur RVB. Et cela a fonctionné! Donc, ce que j'ai fait:
1.Converti BufferedImage
pour le tableau d'octets:
byte[] pixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
2. Ensuite, vous pouvez simplement le mettre à Tapis si vous définissez le type 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 traiter avec le grand tableau de pixels? Utilisez simplement ceci
BufferedImage de 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);
}
Tapis de 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:, même si c'est très négligeable. Cependant, de cette façon, vous pouvez obtenir une solution fiable, mais il utilise l'encodage + décodage. Donc tu perds un peu de performance. C'est généralement de 10 à 20 millisecondes. JPG l'encodage perd de la qualité d'image aussi il est lent (peut prendre 10 à 20ms). 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 à encoder que BMP. En utilisant BMP devrait correspondre à la plupart des cas je pense.
j'ai trouvé une solution ici. La solution est similaire à celle d ' Andriy.
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 );
une façon simple serait de créer une nouvelle utilisation
Mat newMat = Mat(rows, cols, type);
puis récupérez les valeurs des pixels de votre BufferedImage et mettez-les dans newMat en utilisant
newMat.put(row, col, pixel);
j'utilise 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
Vous pouvez le faire dans OpenCV comme suit:
File f4 = new File("aa.png");
Mat mat = Highgui.imread(f4.getAbsolutePath());