最近項目中涉及到了圖像算法識別,涉及到傳遞mat,於是就有了這樣的一篇博客
由於對外接口要求對方提供的是base64編碼的jpg圖像數據,但是算法需要的是Mat類型的數據,這樣就需要引入opencv_java來實現這樣的轉換。
實際上整個過程就需要幾個步驟:
1.實現base64的解碼;
2.將解碼後的數據轉換爲BufferedImage;
3.將BufferedImage轉換爲Mat類型數據;
前兩步都很好實現,難點在第三步上,我們就具體講講第三步的實現
1.首先,maven項目引入幾個pom依賴:
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>javacv</artifactId>
<version>1.4.4</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.bytedeco/javacpp -->
<dependency>
<groupId>org.bytedeco</groupId>
<artifactId>javacpp</artifactId>
<version>1.4.4</version>
</dependency>
<!-- https://mvnrepository.com/artifact/opencv/opencv -->
<dependency>
<groupId>opencv</groupId>
<artifactId>opencv</artifactId>
<version>1.1.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.bytedeco.javacpp-presets/opencv -->
<!-- <dependency> <groupId>org.bytedeco.javacpp-presets</groupId> <artifactId>opencv</artifactId>
<version>4.0.1-1.4.4</version> </dependency> -->
<dependency>
<groupId>org.bytedeco.javacpp-presets</groupId>
<artifactId>opencv</artifactId>
<version>2.4.11-0.11</version>
</dependency>
<!-- 需要自己安裝配置opencv -->
<dependency>
<groupId>org</groupId>
<artifactId>opencv</artifactId>
<version>2413</version>
</dependency>
除最後一個pom依賴外,其餘的應該都能夠從maven倉庫中下載得到。
那我們就來講下如何獲得最後一個maven依賴。
1.1)首先,我們來到opencv的官網:https://opencv.org/releases.html
選擇自己需要下載的平臺及版本,因爲要和公司算法做兼容,所以我選用的是2.4.13版本,window下安裝配置極其簡單,將下載得到的.exe文件解壓縮,然後將到opencv\build\java下即可得到需要的jar包,再然後將jar包轉換爲maven庫裏的依賴就可以了。
具體命令我就不放在這了,拿一個通用的模板命令掛在這,按自己實際去轉換吧。
mvn install:install-file -Dfile=XX.jar -DgroupId=org -DartifactId=opencv -Dversion=2413 -Dpackaging=jar
1.2)引入了pom依賴之後,windows下還需要opencv\build\java
下需要的opencv的dll文件,將86(32位系統)或64(64位系統)下的
opencv_java2413.dll文件引入到系統的jdk的bin目錄下
1.3)上邊的是windows的例子,實際很多情況下代碼是在GPU的linux服務器上運行的,那麼就需要下載linux平臺下的文件,在服務器上使用Cmake編譯安裝,安裝之後得到的會是.so文件,將對應的.so文件移入到/usr/lib下即可。
如果不移動就需要將將.so文件的具體路徑放入到/etc/profile配置文件中,然後使用source命令更新系統配置。
準備工作都做完了,剩下的就是代碼了
首先,需要從系統的環境中加載需要的opencv文件
static {
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
}
其次,就是代碼的具體實現了,包含了BufferedImage與mat(2413不支持mat轉BufferedImage,但是4.0.1版本支持,具體的各位自己去探索吧)數據的互轉及轉opencv的rect方法。
【注】代碼是按照.jpg處理的,需要變更的東西還是各位按需求自定義吧。
import java.awt.AlphaComposite;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferByte;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import javax.imageio.ImageIO;
import org.opencv.core.Core;
import org.opencv.core.CvType;
import org.opencv.core.Mat;
import org.opencv.core.Rect;
import sun.misc.BASE64Decoder;
public class Java2MatTools {
/**
* 加載文件 opencv_java401.dll(windows)/libopencv_java401.so文件
* (windows將文件放到jdk的bin目錄下;linux爲了簡單起見可以放到/usr/lib下面)
*/
static {
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
}
/**
* 路徑圖片轉爲base64
*
* @param imagePath
* @return
* @throws IOException
*/
public static Mat imagePath2Mat(String imagePath) throws IOException {
// 註釋部分模擬傳入base64數據
BufferedImage image = ImageIO.read(new FileInputStream(imagePath));
Mat matImage = Java2MatTools.BufImg2Mat(image, BufferedImage.TYPE_3BYTE_BGR, CvType.CV_8UC3);// CvType.CV_8UC3
// 小型圖片可以輸出 查看下
// System.out.println(matImage.dump());
// mat = matImage.dump();
return matImage;
}
/**
* base64轉Mat
*
* @param base64
* @return
* @throws IOException
*/
public static Mat base642Mat(String base64) throws IOException {
// 對base64進行解碼
BASE64Decoder decoder = new BASE64Decoder();
byte[] origin = decoder.decodeBuffer(base64);
InputStream in = new ByteArrayInputStream(origin); // 將b作爲輸入流;
BufferedImage image = ImageIO.read(in);
Mat matImage = Java2MatTools.BufImg2Mat(image, BufferedImage.TYPE_3BYTE_BGR, CvType.CV_8UC3);// CvType.CV_8UC3
return matImage;
}
/**
*
* @param base64
* @throws IOException
*/
public static Rect base642Rect(String base64) throws IOException {
BASE64Decoder decoder = new BASE64Decoder();
byte[] origin = decoder.decodeBuffer(base64);
InputStream in = new ByteArrayInputStream(origin); // 將b作爲輸入流;
BufferedImage image = ImageIO.read(in);
return new Rect(0,0,image.getWidth(),image.getHeight());
}
/**
*
* @param base64
* @throws IOException
*/
public static Rect BufferedImage2Rect(BufferedImage image) throws IOException {
return new Rect(0,0,image.getWidth(),image.getHeight());
}
/**
*
* @param base64
* @throws IOException
*/
public static BufferedImage base642BufferedImage(String base64) throws IOException {
BASE64Decoder decoder = new BASE64Decoder();
byte[] origin = decoder.decodeBuffer(base64);
InputStream in = new ByteArrayInputStream(origin); // 將b作爲輸入流;
return ImageIO.read(in);
}
/**
* BufferedImage轉換成Mat
*
* @param original 要轉換的BufferedImage
* @param imgType bufferedImage的類型 如 BufferedImage.TYPE_3BYTE_BGR
* @param matType 轉換成mat的type 如 CvType.CV_8UC3
*/
public static Mat BufImg2Mat(BufferedImage original, int imgType, int matType) {
if (original == null) {
throw new IllegalArgumentException("original == null");
}
// Don't convert if it already has correct type
if (original.getType() != imgType) {
// Create a buffered image
BufferedImage image = new BufferedImage(original.getWidth(), original.getHeight(), imgType);
// Draw the image onto the new buffer
Graphics2D g = image.createGraphics();
try {
g.setComposite(AlphaComposite.Src);
g.drawImage(original, 0, 0, null);
} finally {
g.dispose();
}
}
byte[] pixels = ((DataBufferByte) original.getRaster().getDataBuffer()).getData();
Mat mat = Mat.eye(original.getHeight(), original.getWidth(), matType);
mat.put(0, 0, pixels);
return mat;
}
/**
* Mat轉換成BufferedImage
*
* @param matrix 要轉換的Mat
* @param fileExtension 格式爲 ".jpg", ".png", etc
* @return
*//*
public static BufferedImage Mat2BufImg(Mat matrix, String fileExtension) {
// convert the matrix into a matrix of bytes appropriate for
// this file extension
MatOfByte mob = new MatOfByte();
Imgcodecs.imencode(fileExtension, matrix, mob);
// convert the "matrix of bytes" into a byte array
byte[] byteArray = mob.toArray();
BufferedImage bufImage = null;
try {
InputStream in = new ByteArrayInputStream(byteArray);
bufImage = ImageIO.read(in);
} catch (Exception e) {
e.printStackTrace();
}
return bufImage;
}*/
/**
* Mat轉換保存成Image
*
* @param matrix 要轉換的Mat
* @param fileExtension 格式爲 ".jpg", ".png", etc
*
* @return
*/
/* public static void Mat2Img(Mat matrix, String fileExtension, String pathAndName) {
// convert the matrix into a matrix of bytes appropriate for
// this file extension
MatOfByte mob = new MatOfByte();
Imgcodecs.imencode(fileExtension, matrix, mob);
// convert the "matrix of bytes" into a byte array
byte[] byteArray = mob.toArray();
BufferedImage bufImage = null;
try {
InputStream in = new ByteArrayInputStream(byteArray);
bufImage = ImageIO.read(in);
writeImageFile(bufImage, pathAndName);
} catch (Exception e) {
e.printStackTrace();
}
}*/
/**
* 將bufferdimage轉換爲圖片
*
* @param bi
* @param pathAndName
* @throws IOException
*/
public static void writeImageFile(BufferedImage bi, String pathAndName) throws IOException {
File outputfile = new File(pathAndName);
ImageIO.write(bi, "jpg", outputfile);
}
}
ok,完事。