Java調(diào)用C++動態(tài)庫DLL實現(xiàn)圖像處理
前言
相關(guān):Java 調(diào)用 C++ 動態(tài)庫(DLL)完整實踐:無圖像無實體處理場景
這里主要介紹如何通過 JNI(Java Native Interface)在 Java 中調(diào)用一個用 C++ 編寫的校色算法庫。不涉及圖像和 java 實體處理。環(huán)境如下:
- 系統(tǒng):Windows 10
- JDK:1.8
- IDE:Visual Studio 2022
- Java 構(gòu)建工具:Maven
- 目標(biāo)平臺:x64
一、整體目標(biāo)
Java 端通過 JNI 調(diào)用算法提供的動態(tài)庫,實現(xiàn)圖像缺色偏色檢測功能。為了方便,我把所有的依賴庫都放在了 jdk 的 bin 目錄,這樣我在調(diào)用的時候只需要導(dǎo)入我的自己生成的 jni 庫就可以,如果需要頻繁切換 jdk,那建議自己配置 java.library.path 或?qū)⒁蕾噹旆诺姜毩⒛夸浿?,處理好動態(tài)庫的依賴關(guān)系即可。
二、準(zhǔn)備工作
1. C++ 頭文件(API 定義)
這是算法的頭文件,jni 層需要根據(jù)他的方法調(diào)用即可。建議和 java 的方法保持一致,不保持一致也可以,自己在 jni 層處理好就可以。
頭文件方法定義:
// 版本號
COLORCAST_API int ColorCastGetVersion(char* pOutBuf, int nOutBufSize);
COLORCAST_API ColorCastResults analyzeImageColorCast(
unsigned char* pData, int pw, int ph, int pchannels,
double skin_ratio_threshold = 0.1, double C_threshold = 20.0,
double Red_threshold = 18.0, double Green_threshold = 5.0,
double Yellow_threshold = 30.0, double Blue_threshold = 5.0,
double face_threshold = 0.5);
COLORCAST_API ContrastColorCastResults contrastImageColorCast(
unsigned char* tData, int tw, int th, int tchannels,
unsigned char* pData, int pw, int ph, int pchannels,
int YCrCb_cbmax = 125,
int ROIwidthDiv = 6,
int ROIheightDiv = 100,
double USwidthRatio = 0.5,
double USheightRatio = 0.01
);
結(jié)構(gòu)頭文件:
// 偏色對比結(jié)果(雙圖比對)
struct ContrastColorCastResults {
// 紅色比對色偏指數(shù)
double Red_Contrast = 999;
// 綠色比對色偏指數(shù)
double Green_Contrast = 999;
// 黃色比對色偏指數(shù)
double Yellow_Contrast = 999;
// 藍色比對色偏指數(shù)
double Blue_Contrast = 999;
// ROI偏色占比
double ColorCast_ratio = 999;
};
2. Java 接口類定義
這里示例圖像的三種傳輸方式:
- Java 層將圖像轉(zhuǎn)換為 BGR 格式的 byte[],直接傳給 JNI;
- Java 層傳原始圖像數(shù)據(jù),JNI 使用 OpenCV 解碼;
- Java 層傳遞文件路徑,JNI 自行讀取文件內(nèi)容。
package com.emp.empxmrz.util;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
/***
* @title
* @author shijiangyong
* @date 2025/8/27 11:23
**/
public class ColorCastDetExampleJni {
static {
System.loadLibrary("ColorCastDetExampleJni");
}
// 獲取版本號
public static native int getVersion(byte[] buffer, int bufSize);
// 對比圖偏色檢測
// 傳圖片數(shù)據(jù),處理成BGR格式
public static native ColorCastDetExampleJni.ContrastColorCastResults contrastImageColorCast(
byte[] tData, int tw, int th, int tchannels,
byte[] photoData, int pw, int ph, int pchannels,
int yCrCbCbmax, int roiWidthDiv, int roiHeightDiv,
double usWidthRatio, double usHeightRatio
);
// 傳原圖片數(shù)據(jù),不轉(zhuǎn)格式
public static native ColorCastDetExampleJni.ContrastColorCastResults contrastImageColorCastOri(
byte[] tData,
byte[] photoData,
int yCrCbCbmax, int roiWidthDiv, int roiHeightDiv,
double usWidthRatio, double usHeightRatio
);
// 傳圖片本地路徑
public static native ColorCastDetExampleJni.ContrastColorCastResults contrastImageColorCastByPath(
String tData,
String photoData,
int yCrCbCbmax, int roiWidthDiv, int roiHeightDiv,
double usWidthRatio, double usHeightRatio
);
@Data
public static class ContrastColorCastResults {
@Schema(description = "紅色比對偏色指數(shù)")
public double redContrast;
@Schema(description = "綠色比對偏色指數(shù)")
public double greenContrast;
@Schema(description = "黃色比對偏色指數(shù)")
public double yellowContrast;
@Schema(description = "藍色比對偏色指數(shù)")
public double blueContrast;
@Schema(description = "ROI區(qū)域偏色占比")
public double colorCastRatio;
}
}
三、生成 JNI 頭文件
javah -classpath target/classes -d src/main/jni com.emp.empxmrz.util.ColorCastDetExampleJni
這會生成 com_emp_empxmrz_util_ColorCastDetExampleJni.h 和 com_emp_empxmrz_util_ColorCastDetExampleJni_ContrastColorCastResults.h,它定義了 JNI 接口供 C++ 實現(xiàn)。生成之后不能隨便移動類的位置或修改包名、類名等,如果必須調(diào)整的話,需要重新生成。
生成的頭文件大概如下:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_emp_empxmrz_util_ColorCastDetExampleJni */
#ifndef _Included_com_emp_empxmrz_util_ColorCastDetExampleJni
#define _Included_com_emp_empxmrz_util_ColorCastDetExampleJni
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: com_emp_empxmrz_util_ColorCastDetExampleJni
* Method: getVersion
* Signature: ([BI)I
*/
JNIEXPORT jint JNICALL Java_com_emp_empxmrz_util_ColorCastDetExampleJni_getVersion
(JNIEnv *, jclass, jbyteArray, jint);
/*
* Class: com_emp_empxmrz_util_ColorCastDetExampleJni
* Method: contrastImageColorCast
* Signature: ([BIII[BIIIIIIDD)Lcom/emp/empxmrz/util/ColorCastDetExampleJni/ContrastColorCastResults;
*/
JNIEXPORT jobject JNICALL Java_com_emp_empxmrz_util_ColorCastDetExampleJni_contrastImageColorCast
(JNIEnv *, jclass, jbyteArray, jint, jint, jint, jbyteArray, jint, jint, jint, jint, jint, jint, jdouble, jdouble);
/*
* Class: com_emp_empxmrz_util_ColorCastDetExampleJni
* Method: contrastImageColorCastOri
* Signature: ([B[BIIIDD)Lcom/emp/empxmrz/util/ColorCastDetExampleJni/ContrastColorCastResults;
*/
JNIEXPORT jobject JNICALL Java_com_emp_empxmrz_util_ColorCastDetExampleJni_contrastImageColorCastOri
(JNIEnv *, jclass, jbyteArray, jbyteArray, jint, jint, jint, jdouble, jdouble);
/*
* Class: com_emp_empxmrz_util_ColorCastDetExampleJni
* Method: contrastImageColorCastByPath
* Signature: (Ljava/lang/String;Ljava/lang/String;IIIDD)Lcom/emp/empxmrz/util/ColorCastDetExampleJni/ContrastColorCastResults;
*/
JNIEXPORT jobject JNICALL Java_com_emp_empxmrz_util_ColorCastDetExampleJni_contrastImageColorCastByPath
(JNIEnv *, jclass, jstring, jstring, jint, jint, jint, jdouble, jdouble);
#ifdef __cplusplus
}
#endif
#endif
四、JNI 實現(xiàn)(C++)
這是 jni 的頭文件實現(xiàn),因為我是要調(diào)用多個算法,所以使用 vs 創(chuàng)建了一個解決方案,里面創(chuàng)建了多個項目,每個項目都是一種算法的 jni 層,根據(jù)自己的實際情況操作就可以,實現(xiàn)類中需要包含算法頭文件和 jni 頭文件,java實體的頭文件不用添加。項目結(jié)構(gòu)大致如下:

cpp 完整代碼如下:
#include "ColorCast.h"
#include "com_emp_empxmrz_util_ColorCastDetExampleJni.h"
#include <iostream>
#include <stdexcept>
#include <string>
#include <opencv2/core.hpp>
#include <opencv2/imgcodecs.hpp>
void native_log(const std::string& message) {
std::cerr << "[NativeLog] " << message << std::endl;
}
void throwJavaException(JNIEnv* env, const char* message) {
jclass exceptionCls = env->FindClass("java/lang/RuntimeException");
if (exceptionCls != nullptr) {
env->ThrowNew(exceptionCls, message);
}
}
void throwIllegalArgument(JNIEnv* env, const char* message) {
jclass exClass = env->FindClass("java/lang/IllegalArgumentException");
if (exClass != nullptr) {
env->ThrowNew(exClass, message);
}
}
JNIEXPORT jint JNICALL Java_com_emp_empxmrz_util_ColorCastDetExampleJni_getVersion(JNIEnv* env, jobject obj, jbyteArray buffer, jint bufSize) {
try {
jboolean isCopy = JNI_FALSE;
jbyte* bufPtr = env->GetByteArrayElements(buffer, &isCopy);
if (bufPtr == nullptr) {
throwJavaException(env, "Failed to get buffer pointer");
return 0;
}
// 寫入版本號
int len = ColorCastGetVersion(reinterpret_cast<char*>(bufPtr), static_cast<int>(bufSize));
// 寫成功,手動同步數(shù)據(jù)回 Java
env->ReleaseByteArrayElements(buffer, bufPtr, 0);
return len;
}
catch (const std::exception& e) {
native_log(e.what());
throwJavaException(env, e.what());
return 0;
}
}
// 構(gòu)造 ContrastColorCastResults Java 對象
jobject createContrastColorCastResults(JNIEnv* env, const ContrastColorCastResults& result) {
jclass cls = env->FindClass("com/emp/empxmrz/util/ColorCastDetJni$ContrastColorCastResults");
if (cls == nullptr) {
throwJavaException(env, "Failed to find ContrastColorCastResults class");
return nullptr;
}
jmethodID constructor = env->GetMethodID(cls, "<init>", "()V");
if (constructor == nullptr) {
throwJavaException(env, "Failed to get constructor for ContrastColorCastResults");
return nullptr;
}
jobject obj = env->NewObject(cls, constructor);
env->SetDoubleField(obj, env->GetFieldID(cls, "redContrast", "D"), result.Red_Contrast);
env->SetDoubleField(obj, env->GetFieldID(cls, "greenContrast", "D"), result.Green_Contrast);
env->SetDoubleField(obj, env->GetFieldID(cls, "yellowContrast", "D"), result.Yellow_Contrast);
env->SetDoubleField(obj, env->GetFieldID(cls, "blueContrast", "D"), result.Blue_Contrast);
env->SetDoubleField(obj, env->GetFieldID(cls, "colorCastRatio", "D"), result.ColorCast_ratio);
return obj;
}
JNIEXPORT jobject JNICALL Java_com_emp_empxmrz_util_ColorCastDetExampleJni_contrastImageColorCast
(JNIEnv* env, jobject obj,
jbyteArray templateData, jint tw, jint th, jint tchannels,
jbyteArray photoData, jint pw, jint ph, jint pchannels,
jint cbmax, jint roiWidthDiv, jint roiHeightDiv,
jdouble usWidthRatio, jdouble usHeightRatio) {
try {
jbyte* tData = env->GetByteArrayElements(templateData, nullptr);
jbyte* pData = env->GetByteArrayElements(photoData, nullptr);
ContrastColorCastResults result = contrastImageColorCast(
reinterpret_cast<unsigned char*>(tData), tw, th, tchannels,
reinterpret_cast<unsigned char*>(pData), pw, ph, pchannels,
cbmax, roiWidthDiv, roiHeightDiv, usWidthRatio, usHeightRatio
);
env->ReleaseByteArrayElements(templateData, tData, 0);
env->ReleaseByteArrayElements(photoData, pData, 0);
// 將 ContrastColorCastResults 映射到 Java 對象
return createContrastColorCastResults(env, result);
}
catch (const std::exception& e) {
native_log(e.what());
throwJavaException(env, e.what());
return nullptr;
}
}
JNIEXPORT jobject JNICALL Java_com_emp_empxmrz_util_ColorCastDetExampleJni_contrastImageColorCastOri
(JNIEnv* env, jobject obj,
jbyteArray templateData, jbyteArray photoData,
jint cbmax, jint roiWidthDiv, jint roiHeightDiv,
jdouble usWidthRatio, jdouble usHeightRatio) {
try {
if (templateData == nullptr) {
throwIllegalArgument(env,"templateData is null");
return nullptr;
}
if (photoData == nullptr) {
throwIllegalArgument(env, "photoData is null");
return nullptr;
}
jsize tempLen = env->GetArrayLength(templateData);
if (tempLen <= 0) {
throwIllegalArgument(env, "templateData is null");
return nullptr;
}
jsize photoLen = env->GetArrayLength(photoData);
if (photoLen <= 0) {
throwIllegalArgument(env, "photoData is null");
return nullptr;
}
// Zero-copy: 獲取 JVM 中的數(shù)據(jù)指針(映射)
jbyte* tData = env->GetByteArrayElements(templateData, nullptr);
if (tData == nullptr) {
throwJavaException(env, "templateData Failed to get byte array elements");
return nullptr;
}
// Zero-copy: 獲取 JVM 中的數(shù)據(jù)指針(映射)
jbyte* pData = env->GetByteArrayElements(photoData, nullptr);
if (pData == nullptr) {
throwJavaException(env, "photoData Failed to get byte array elements");
return nullptr;
}
// 原圖
// 構(gòu)造一個 OpenCV Mat 來包裝 byte[] 數(shù)據(jù)(不復(fù)制)
cv::Mat tBuf(1, tempLen, CV_8UC1, reinterpret_cast<uchar*>(tData));
// 解碼為圖像
cv::Mat tImage = cv::imdecode(tBuf, cv::IMREAD_UNCHANGED);
if (tImage.empty()) {
env->ReleaseByteArrayElements(photoData, pData, JNI_ABORT);
throwJavaException(env, "templateData Failed to decode image");
return nullptr;
}
// 目標(biāo)圖
cv::Mat pBuf(1, photoLen, CV_8UC1, reinterpret_cast<uchar*>(pData));
cv::Mat pImage = cv::imdecode(pBuf, cv::IMREAD_UNCHANGED);
if (pImage.empty()) {
env->ReleaseByteArrayElements(templateData, tData, JNI_ABORT);
throwJavaException(env, "photoData Failed to decode image");
return nullptr;
}
ContrastColorCastResults result = contrastImageColorCast(
reinterpret_cast<unsigned char*>(tImage.data), tImage.cols, tImage.rows, tImage.channels(),
reinterpret_cast<unsigned char*>(pImage.data), pImage.cols, pImage.rows, pImage.channels(),
cbmax, roiWidthDiv, roiHeightDiv, usWidthRatio, usHeightRatio
);
// 釋放映射,不拷貝回 Java(JNI_ABORT)
env->ReleaseByteArrayElements(templateData, tData, JNI_ABORT);
env->ReleaseByteArrayElements(photoData, pData, JNI_ABORT);
// 將 ContrastColorCastResults 映射到 Java 對象
return createContrastColorCastResults(env, result);
}
catch (const std::exception& e) {
native_log(e.what());
throwJavaException(env, e.what());
return nullptr;
}
}
JNIEXPORT jobject JNICALL Java_com_emp_empxmrz_util_ColorCastDetExampleJni_contrastImageColorCastByPath
(JNIEnv* env, jobject obj,
jstring templateData, jstring photoData,
jint cbmax, jint roiWidthDiv, jint roiHeightDiv,
jdouble usWidthRatio, jdouble usHeightRatio) {
try {
const char* tImagePath = env->GetStringUTFChars(templateData, nullptr);
const char* pImagePath = env->GetStringUTFChars(photoData, nullptr);
// 直接用 OpenCV 讀取圖像
cv::Mat tImage = cv::imread(tImagePath);
if (tImage.empty()) {
env->ReleaseStringUTFChars(templateData, tImagePath); // 釋放資源
env->ReleaseStringUTFChars(photoData, pImagePath);
throwJavaException(env, "Failed to load templateData");
return nullptr;
}
cv::Mat pImage = cv::imread(pImagePath);
if (pImage.empty()) {
env->ReleaseStringUTFChars(templateData, tImagePath); // 釋放資源
env->ReleaseStringUTFChars(photoData, pImagePath);
throwJavaException(env, "Failed to load photoData");
return nullptr;
}
ContrastColorCastResults result = contrastImageColorCast(
reinterpret_cast<unsigned char*>(tImage.data), tImage.cols, tImage.rows, tImage.channels(),
reinterpret_cast<unsigned char*>(pImage.data), pImage.cols, pImage.rows, pImage.channels(),
cbmax, roiWidthDiv, roiHeightDiv, usWidthRatio, usHeightRatio
);
env->ReleaseStringUTFChars(templateData, tImagePath);
env->ReleaseStringUTFChars(photoData, pImagePath);
// 將 ContrastColorCastResults 映射到 Java 對象
return createContrastColorCastResults(env, result);
}
catch (const std::exception& e) {
native_log(e.what());
throwJavaException(env, e.what());
return nullptr;
}
}
建議添加異常處理,避免JVM 崩潰,注意資源的釋放。
五、Visual Studio 配置
1. 添加包含目錄
打開【項目屬性】 > C/C++ > 常規(guī) > 附加包含目錄:

防止編譯階段報錯。
2. 添加庫目錄
打開【鏈接器】 > 常規(guī) > 附加庫目錄:

3. 添加依賴庫
打開【鏈接器】 > 輸入 > 附加依賴項:

告訴編譯器如何調(diào)用 .dll 中的函數(shù); 出現(xiàn) JNI 方法未導(dǎo)出錯誤,可添加 .def 文件顯式指定導(dǎo)出符號 ,內(nèi)容如下,其實就是 jni 頭文件方法:
LIBRARY ColorCastDetExampleJni
EXPORTS
Java_com_emp_empxmrz_util_ColorCastDetExampleJni_getVersion
Java_com_emp_empxmrz_util_ColorCastDetExampleJni_contrastImageColorCast
Java_com_emp_empxmrz_util_ColorCastDetExampleJni_contrastImageColorCastOri
Java_com_emp_empxmrz_util_ColorCastDetExampleJni_contrastImageColorCastByPath
4.生成 DLL
編譯后會生成 ColorCastDetExampleJni.dll 和 ColorCastDetExampleJni.lib,將他們復(fù)制到 jdk 的 bin 目錄或者你自己定義的目錄下, java 就可以直接調(diào)用 ColorCastDetExampleJni了。
六、Java 調(diào)用測試
工具類 CustomImgUtils和 ImageProcessor在這篇文章里,Java 圖像處理傳 JNI 到 C++(OpenCV):兩種高效實現(xiàn)方式對比
java 測試結(jié)果是否正確,也可以自己封裝成接口。
service 層:
package com.emp.empxmrz.service;
import com.emp.empxmrz.controller.vo.ColorCastDetExampleReq;
import com.emp.empxmrz.util.ColorCastDetExampleJni;
import com.emp.empxmrz.util.CustomImgUtils;
import com.emp.empxmrz.util.ImageProcessor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
/***
* @title
* @author shijiangyong
* @date 2025/9/15 10:17
**/
@Slf4j
@Service
public class ColorCastDetExampleJniServiceImpl implements ColorCastDetExampleJniService{
@Override
public String getVersion() {
byte[] versionBuffer = new byte[12];
int result = ColorCastDetExampleJni.getVersion(versionBuffer, versionBuffer.length);
String version = "獲取版本號失敗";
if (result == 0) {
version = new String(versionBuffer, StandardCharsets.UTF_8).trim();
log.info("Algorithm model version number: {}", version);
} else {
log.warn("Failed to get version number: {} ", result);
}
return version;
}
@Override
public ColorCastDetExampleJni.ContrastColorCastResults contrastImageColorCast(ColorCastDetExampleReq req) {
MultipartFile sourceFile = req.getSourceFile();
if (sourceFile == null || sourceFile.isEmpty()) {
throw new IllegalArgumentException("Source file is null or empty");
}
MultipartFile targetFile = req.getTargetFile();
if (targetFile == null || targetFile.isEmpty()) {
throw new IllegalArgumentException("Target file is null or empty");
}
try {
byte[] sourceBytes = ImageProcessor.inputStreamToByteArray(sourceFile.getInputStream());
BufferedImage sourceImage = ImageIO.read(new ByteArrayInputStream(sourceBytes));
if (sourceImage == null) {
throw new RuntimeException("圖像讀取失敗");
}
byte[] targetBytes = ImageProcessor.inputStreamToByteArray(targetFile.getInputStream());
BufferedImage targetImage = ImageIO.read(new ByteArrayInputStream(targetBytes));
if (targetImage == null) {
throw new RuntimeException("圖像讀取失敗");
}
byte[] sourceMatrixBGR = CustomImgUtils.getMatrixBGR(sourceImage);
byte[] targetMatrixBGR = CustomImgUtils.getMatrixBGR(targetImage);
return ColorCastDetExampleJni.contrastImageColorCast(sourceMatrixBGR, sourceImage.getWidth(), sourceImage.getHeight(), sourceImage.getColorModel().getNumColorComponents(),
targetMatrixBGR, targetImage.getWidth(), targetImage.getHeight(), targetImage.getColorModel().getNumColorComponents(),
req.getYCrCbCbmax(), req.getRoiWidthDiv(), req.getRoiHeightDiv(), req.getUsWidthRatio(), req.getUsHeightRatio());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
public ColorCastDetExampleJni.ContrastColorCastResults contrastImageColorCastOri(ColorCastDetExampleReq req) {
String sourceFileUrl = req.getSourceFileUrl();
if (sourceFileUrl == null || sourceFileUrl.isEmpty()) {
throw new IllegalArgumentException("Source file url is null or empty");
}
String targetFileUrl = req.getTargetFileUrl();
if (targetFileUrl == null || targetFileUrl.isEmpty()) {
throw new IllegalArgumentException("Target file url is null or empty");
}
try {
byte[] sourceMatrixBGR = this.getImageBytes(sourceFileUrl);
byte[] targetMatrixBGR = this.getImageBytes(targetFileUrl);
return ColorCastDetExampleJni.contrastImageColorCastOri(sourceMatrixBGR, targetMatrixBGR,
req.getYCrCbCbmax(), req.getRoiWidthDiv(), req.getRoiHeightDiv(), req.getUsWidthRatio(), req.getUsHeightRatio());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
@Override
public ColorCastDetExampleJni.ContrastColorCastResults contrastImageColorCastByPath(ColorCastDetExampleReq req) {
String sourceFileUrl = "E:\\test\\CertifHaed.jpg";
String targetFileUrl = "E:\\test\\face_big_homepage.jpg";
return ColorCastDetExampleJni.contrastImageColorCastByPath(sourceFileUrl,targetFileUrl,req.getYCrCbCbmax(), req.getRoiWidthDiv(),
req.getRoiHeightDiv(), req.getUsWidthRatio(), req.getUsHeightRatio());
}
/**
* http流轉(zhuǎn)BufferedImage
* @param req
* @return
* @throws IOException
*/
private BufferedImage getBufferedImage(String req) throws IOException {
URL url = new URL(req);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(5000);
conn.setReadTimeout(10000);
return ImageIO.read(conn.getInputStream());
}
/**
* http流轉(zhuǎn)Byte[]
* @param req
* @return
* @throws IOException
*/
private byte[] getImageBytes(String req) throws IOException {
URL url = new URL(req);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(5000);
conn.setReadTimeout(10000);
try (InputStream inputStream = conn.getInputStream()) {
return ImageProcessor.inputStreamToByteArray(inputStream);
}
}
}
controller 層:
package com.emp.empxmrz.controller;
import com.emp.empxmrz.controller.vo.ColorCastDetExampleReq;
import com.emp.empxmrz.service.ColorCastDetExampleJniService;
import com.emp.empxmrz.util.ColorCastDetExampleJni;
import com.emp.empxmrz.util.R;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/***
* @title
* @author shijiangyong
* @date 2025/9/15 10:47
**/
@Slf4j
@RestController
@AllArgsConstructor
@Tag(name = "demo示例")
@RequestMapping("/example")
public class ColorCastDetExampleJniController {
private final ColorCastDetExampleJniService colorCastDetExampleJniService;
@PostMapping("/getVersion")
@Operation(summary = "管理后臺-獲取算法版本")
public R<String> getVersion() {
return R.ok(colorCastDetExampleJniService.getVersion());
}
@PostMapping("/contrast/color/castDet")
@Operation(summary = "管理后臺-偏色檢測算法")
public R<ColorCastDetExampleJni.ContrastColorCastResults> contrastImageColorCast(ColorCastDetExampleReq req) {
return R.ok(colorCastDetExampleJniService.contrastImageColorCast(req));
}
@PostMapping("/contrast/color/castDetOri")
@Operation(summary = "管理后臺-偏色檢測算法")
public R<ColorCastDetExampleJni.ContrastColorCastResults> contrastImageColorCastOri(ColorCastDetExampleReq req) {
return R.ok(colorCastDetExampleJniService.contrastImageColorCastOri(req));
}
@PostMapping("/contrast/color/castDetByPath")
@Operation(summary = "管理后臺-偏色檢測算法")
public R<ColorCastDetExampleJni.ContrastColorCastResults> contrastImageColorCastByPath(ColorCastDetExampleReq req) {
return R.ok(colorCastDetExampleJniService.contrastImageColorCastByPath(req));
}
}
調(diào)用示例:
路徑去掉 Ori 就是測試上面兩個入?yún)?,加?Ori 就是測試下面兩個入?yún)ⅲ凑搅?java 層,就自己隨便玩了。實體類就不貼了。

調(diào)試建議
如果報錯找不到 ColorCastDetExampleJni.dll,請將該 DLL 放入:
- 項目運行目錄;
- 或者
jdk/bin目錄; - 或者設(shè)置
-Djava.library.path。
如果 JNI 函數(shù)名對應(yīng)不上,請確保:
- 包名、類名、方法名匹配;
- DLL 導(dǎo)出的函數(shù)使用
extern "C"。 - JNI 方法未正確導(dǎo)出,可通過
.def文件顯式指定導(dǎo)出符號。
七、總結(jié)
- 編寫 Java native 接口;
- 使用
javah生成 JNI 頭文件; - C++ 實現(xiàn) JNI 方法;
- 配置 Visual Studio 編譯動態(tài)庫;
- Java 調(diào)用測試。
如果你不想污染自己的JDK bin,可以將 .dll 和 .lib 放到一個統(tǒng)一的目錄下,這樣的話切換 jdk 比較方便,因為我只使用 jdk8,所以貪圖方便放在了 bin 目錄,但這是不規(guī)范滴 。
到此這篇關(guān)于Java調(diào)用C++動態(tài)庫DLL實現(xiàn)圖像處理的文章就介紹到這了,更多相關(guān)Java調(diào)用DLL實現(xiàn)圖像處理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java實現(xiàn)多選批量刪除功能(vue+Element)
這篇文章主要為大家詳細介紹了Java實現(xiàn)多選批量刪除功能,包括前端vue實現(xiàn)代碼文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-08-08
使用Jenkins來構(gòu)建SVN+Maven項目的實現(xiàn)
這篇文章主要介紹了使用Jenkins來構(gòu)建SVN+Maven項目的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09
在Eclipse IDE使用Gradle構(gòu)建應(yīng)用程序(圖文)
這篇文章主要介紹了在Eclipse IDE使用Gradle構(gòu)建應(yīng)用程序(圖文),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-12-12
Java并發(fā)編程之柵欄(CyclicBarrier)實例介紹
這篇文章主要介紹了Java并發(fā)編程之柵欄(CyclicBarrier)實例介紹,柵欄類似閉鎖,但是它們是有區(qū)別的,需要的朋友可以參考下2015-04-04

