[英]Converting `BufferedImage` to `Mat` in OpenCV
如何在OpenCV
中將BufferedImage
轉換為Mat
?
我正在使用OpenCV
的 JAVA 包裝器(不是JavaCV )。 由於我是OpenCV
新手,我在理解Mat
工作原理時遇到了一些問題。
我想做這樣的事情。 (基於 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);
這不起作用。 Lena_copy.png
只是一張尺寸正確的黑色圖片。
我也試圖做同樣的事情,因為需要將處理過的圖像與兩個庫結合起來。 我試圖做的是將byte[]
放入Mat
而不是 RGB 值。 它奏效了! 所以我所做的是:
1.Converted BufferedImage
到字節數組:
byte[] pixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
2.如果你把type設置為CV_8UC3,你可以簡單地把它放在Mat上
image_final.put(0, 0, pixels);
編輯:你也可以嘗試按照這個答案做相反的事情
不想處理大像素陣列? 簡單地使用這個
緩沖圖像到墊子
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);
}
墊到緩沖圖像
public static BufferedImage Mat2BufferedImage(Mat matrix)throws IOException {
MatOfByte mob=new MatOfByte();
Imgcodecs.imencode(".jpg", matrix, mob);
return ImageIO.read(new ByteArrayInputStream(mob.toArray()));
}
注意,雖然它非常微不足道。 但是,通過這種方式,您可以獲得可靠的解決方案,但它使用編碼+解碼。 所以你會失去一些性能。 一般為 10 到 20 毫秒。 JPG編碼會損失一些圖像質量,而且速度很慢(可能需要 10 到 20 毫秒)。 BMP無損且快速(1 或 2 毫秒),但只需要很少的內存(可以忽略不計)。 PNG是無損的,但編碼時間比 BMP 多一點。 使用BMP應該適合我認為的大多數情況。
這個對我來說效果很好,執行時間為 0 到 1 毫秒。
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;
}
我在我的程序中使用以下代碼。
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;
}
參考: 這里
我在這里找到了解決方案。 解決方案類似於 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 );
一種簡單的方法是創建一個新的使用
Mat newMat = Mat(rows, cols, type);
然后從您的 BufferedImage 獲取像素值並使用
newMat.put(row, col, pixel);
要將 BufferedImage 轉換為 Mat 我使用以下方法:
public static Mat img2Mat(BufferedImage image) {
image = convertTo3ByteBGRType(image);
byte[] data = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
Mat mat = new Mat(image.getHeight(), image.getWidth(), CvType.CV_8UC3);
mat.put(0, 0, data);
return mat;
}
在轉換為 Mat 之前,我將 bufferedImage 的類型更改為 TYPE_3BYTE_BGR,因為對於某些類型的 BufferedImages 方法((DataBufferByte) image.getRaster().getDataBuffer()).getData(); 可能會返回int[]並且會破壞代碼。
下面是轉換為 TYPE_3BYTE_BGR 的方法。
private static BufferedImage convertTo3ByteBGRType(BufferedImage image) {
BufferedImage convertedImage = new BufferedImage(image.getWidth(), image.getHeight(),
BufferedImage.TYPE_3BYTE_BGR);
convertedImage.getGraphics().drawImage(image, 0, 0, null);
return convertedImage;
}
當您使用 JavaCP 包裝器bytedeco 庫(版本 1.5.3)時,您可以使用Java2DFrameUtils 。
簡單的用法是:
import org.bytedeco.javacv.Java2DFrameUtils;
...
BufferedImage img = ImageIO.read(new File("some/image.jpg");
Mat mat = Java2DFrameUtils.toMat(img);
您可以在 OpenCV 中執行如下操作:
File f4 = new File("aa.png");
Mat mat = Highgui.imread(f4.getAbsolutePath());
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.