最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java將圖像數(shù)據(jù)傳到C++的兩種高效實現(xiàn)方式對比

 更新時間:2025年08月25日 16:34:36   作者:頗有幾分姿色  
在圖像處理時,Java 的圖像數(shù)據(jù)換到 c++中是無法直接使用的,本文為大家整理了兩種高效實現(xiàn)方式并進行了對比,感興趣的小伙伴可以了解一下

在圖像處理時,Java 的圖像數(shù)據(jù)換到 c++中是無法直接使用的,需要轉(zhuǎn)為 BGR 格式,要么在 java 層處理,要么在 jni 層處理,算法工程師的提供的動態(tài)庫一般不會處理圖片格式,直接拿到圖像數(shù)據(jù)就使用了,這里寫的是我自己用過的兩種實現(xiàn)方式。

背景

調(diào)試時遇到的問題:

  • 圖像的顏色通道順序(Java 是 RGB,OpenCV 是 BGR),需要轉(zhuǎn)換
  • 圖像類型多樣(ARGB、灰度、RGB、BGR 等)
  • 是否需要中間轉(zhuǎn)換?
  • 數(shù)據(jù)如何傳輸最優(yōu)?

兩種實現(xiàn)方式

環(huán)境:

JDK:8

OPENCV:4.5.3

對比:

實現(xiàn)方式Java 處理通道順序JNI 層構(gòu)造 cv::Mat性能靈活性
方式一:Java 轉(zhuǎn)為 BGRJava 層預(yù)處理為 BGR直接生成 Mat
方式二:Java 原始 byte[]不處理C++ 層判斷格式并轉(zhuǎn)換

沒有做過實際的數(shù)據(jù)對比,但處理速度上方式二是比方式一快的,至于快多少,不估了,啥時候有空再上數(shù)據(jù)吧。

以下是代碼示例:

假設(shè)算法頭文件其中一個方法是這樣的:

//進行MRZ碼識別,只識別,不進行任何MRZ碼內(nèi)容校驗。
/**
 * @brief       對輸入的圖像,進行字符OCR,并選擇最長的兩行字符輸出
 * @param       pData:  圖像數(shù)據(jù),BGR格式或Gray
 * @param       nw:     圖像寬度
 * @param       nh:     圖像高度
 * @param       channels:   圖像通道數(shù)
 * @param       ocr:    字符識別對象句柄,來自InitModel
 * @return      emp_MRZ*:   字符識別結(jié)果,需要調(diào)用Release_empMRZ接口釋放內(nèi)存。
 */
PassportMRZ_API emp_MRZ* detectMRZ(unsigned char * pData, int nw, int nh,int channels,void * ocr);

方式一:Java 層轉(zhuǎn)為 BGR 格式,再傳給 JNI

Java 實現(xiàn)

方法映射

public native static EmpMRZ detectMRZ(byte[] imageData, int width, int height, int channels, long ocrPtr);

圖像處理工具類:

public class CustomImgUtils {
    /**
     * @param image
     * @param bandOffset 用于判斷通道順序
     * @return
     */
    private static boolean equalBandOffsetWith3Byte(BufferedImage image,int[] bandOffset){
        if(image.getType()==BufferedImage.TYPE_3BYTE_BGR){
            if(image.getData().getSampleModel() instanceof ComponentSampleModel){
                ComponentSampleModel sampleModel = (ComponentSampleModel)image.getData().getSampleModel();
                if(Arrays.equals(sampleModel.getBandOffsets(), bandOffset)){
                    return true;
                }
            }
        }
        return false;
    }
    /**
     * 判斷圖像是否為BGR格式
     * @return
     */
    public static boolean isBGR3Byte(BufferedImage image){
        return equalBandOffsetWith3Byte(image,new int[]{0, 1, 2});
    }
    /**
     * 判斷圖像是否為RGB格式
     * @return
     */
    public static boolean isRGB3Byte(BufferedImage image){
        return equalBandOffsetWith3Byte(image,new int[]{2, 1, 0});
    }


    /**
     * 判斷圖像是否為ARGB格式
     * @return
     */
    public static boolean isARGB(BufferedImage image){
        return image.getType() == BufferedImage.TYPE_INT_ARGB ||
        image.getType() == BufferedImage.TYPE_INT_ARGB_PRE ||
        image.getType() == BufferedImage.TYPE_4BYTE_ABGR ||
        image.getType() == BufferedImage.TYPE_4BYTE_ABGR_PRE;
    }

    /**
     * 判斷圖像是否為灰度圖
     * @return
     */
    public boolean isGray(BufferedImage image){
        return image.getType() == BufferedImage.TYPE_BYTE_GRAY;

    }


    /**
     * 對圖像解碼返回RGB格式矩陣數(shù)據(jù)
     * @param image
     * @return
     */
    public static byte[] getMatrixRGB(BufferedImage image) {
        if(null==image)
            throw new NullPointerException();
        byte[] matrixRGB;
        if(isRGB3Byte(image)){
            matrixRGB= (byte[]) image.getData().getDataElements(0, 0, image.getWidth(), image.getHeight(), null);
        }else{
            // 轉(zhuǎn)RGB格式
            BufferedImage rgbImage = new BufferedImage(image.getWidth(), image.getHeight(),
                                                       BufferedImage.TYPE_3BYTE_BGR);
            new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_sRGB), null).filter(image, rgbImage);
            matrixRGB= (byte[]) rgbImage.getData().getDataElements(0, 0, image.getWidth(), image.getHeight(), null);
        }
        return matrixRGB;
    }
    /**
     * 對圖像解碼返回BGR格式矩陣數(shù)據(jù)
     * @param image
     * @param channels
     * @return
     */
    public static byte[] getMatrixBGR(BufferedImage image){
        if(null==image)
            throw new NullPointerException();
        byte[] matrixBGR;
        if(isBGR3Byte(image)){
            matrixBGR= (byte[]) image.getData().getDataElements(0, 0, image.getWidth(), image.getHeight(), null);
        } else if (isGray(image)) {
            byte[] gray = ((DataBufferByte) image.getRaster().getDataBuffer()).getData();
            // 創(chuàng)建BGR矩陣
            matrixBGR = new byte[gray.length * 3];
            for (int i = 0, j = 0; i < gray.length; ++i, j += 3) {
                // Blue
                matrixBGR[j] = gray[i];
                // Green
                matrixBGR[j + 1] = gray[i];
                // Red
                matrixBGR[j + 2] = gray[i];
            }
            return matrixBGR;
        } else {
            // ARGB格式圖像數(shù)據(jù)
            int[] intrgb = image.getRGB(0, 0, image.getWidth(), image.getHeight(), null, 0, image.getWidth());
            matrixBGR = new byte[image.getWidth() * image.getHeight() * 3];
            // ARGB轉(zhuǎn)BGR格式
            for (int i = 0, j = 0; i < intrgb.length; ++i, j += 3) {
                // Blue
                matrixBGR[j] = (byte) (intrgb[i] & 0xff);
                // Green
                matrixBGR[j + 1] = (byte) ((intrgb[i] >> 8) & 0xff);
                // Red
                matrixBGR[j + 2] = (byte) ((intrgb[i] >> 16) & 0xff);
            }
        }
        return matrixBGR;
    }

    // 判斷是否為單通道圖像(灰度圖或單通道類型)
    public static boolean isSingleChannel(BufferedImage image) {
        // 通過顏色模型判斷:顏色分量數(shù)量為1時表示單通道
        return image.getColorModel().getNumColorComponents() == 1;
    }

    // 單通道轉(zhuǎn)三通道的具體實現(xiàn)
    public static BufferedImage convertSingleToThreeChannels(BufferedImage srcImage) {
        int width = srcImage.getWidth();
        int height = srcImage.getHeight();
        BufferedImage destImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

        for (int y = 0; y < height; y++) {
            for (int x = 0; x < width; x++) {
                int grayValue = srcImage.getRaster().getSample(x, y, 0);
                int rgb = (grayValue << 16) | (grayValue << 8) | grayValue;
                destImage.setRGB(x, y, rgb);
            }
        }
        return destImage;
    }

}

邏輯層:

public R<MrzInfo> delectJni(MultipartFile file) throws IOException {
       log.info("begin detect");
       try {
           long start = System.currentTimeMillis();
           if (null ==file || file.isEmpty()) {
               return R.failed("傳入文件為空");
           }
           BufferedImage bufferedImage = ImageIO.read(file.getInputStream());
//        int channels = bufferedImage.getColorModel().getNumComponents();
           int channels = 3;
           if (CustomImgUtils.isSingleChannel(bufferedImage)) {
               // 通道轉(zhuǎn)換
               bufferedImage = CustomImgUtils.convertSingleToThreeChannels(bufferedImage);
           }
           int width = bufferedImage.getWidth();
           int height = bufferedImage.getHeight();
           byte[] matrixBGR = CustomImgUtils.getMatrixBGR(bufferedImage);
           MrzInfo mrzInfo = new MrzInfo();
           long mrzStart = System.currentTimeMillis();
           EmpMRZ result = PassportMRZ.detectMrz(matrixBGR, width, height, channels);
           // ……
       } catch (Exception e) {
           log.error("error:",e);
           return R.failed(new MrzInfo(),"detect exception");
       }

   }

JNI實現(xiàn)

jbyte* imageDataBytes = env->GetByteArrayElements(imageData, nullptr);
// 獲取后直接傳到對應(yīng)方法里即可,有時可能需要轉(zhuǎn)換:reinterpret_cast<unsigned char*>(imageDataBytes)

這樣做的好處是:

  • 圖像格式一致,C++ 層無需關(guān)心圖像類型
  • 支持灰度、ARGB、RGB 等復(fù)雜格式

方式二:Java 層不處理,傳原始 byte[] 到 JNI

Java 實現(xiàn)

public native static EmpMRZ detectMRZ(byte[] imageData, long ocrPtr);

圖像處理工具類:

public class ImageProcessor {
    // 公共方法:將 InputStream 轉(zhuǎn)換為 byte[]
    public static byte[] inputStreamToByteArray(InputStream inputStream) throws IOException {
        try (ByteArrayOutputStream buffer = new ByteArrayOutputStream();
             InputStream is = inputStream) {
            byte[] data = new byte[8192];
            int nRead;
            while ((nRead = is.read(data, 0, data.length)) != -1) {
                buffer.write(data, 0, nRead);
            }
            return buffer.toByteArray();
        }
    }

邏輯調(diào)用層:

byte[] imageBytes = ImageProcessor.inputStreamToByteArray(file.getInputStream());
detectMRZ(imageBytes, ocrPtr);

JNI實現(xiàn)

JNIEXPORT jobject JNICALL Java_com_emp_empxmrz_util_MrzDetect_detectMRZ
(JNIEnv* env, jclass, jbyteArray imageData, jlong modelPtr) {
    // ......

    // 獲取傳入的圖片字節(jié)數(shù)組
    jsize len = env->GetArrayLength(imageData);
    if (len <= 0) {
        fprintf(stderr, "[JNI] Invalid image data length: %d\n", len);
        jclass exceptionCls = env->FindClass("java/lang/RuntimeException");
        env->ThrowNew(exceptionCls, "Invalid image data length");
        return nullptr;
    }

    jbyte* dataPtr = env->GetByteArrayElements(imageData, nullptr);
    if (dataPtr == nullptr) {
        fprintf(stderr, "[JNI] Failed to get image data elements\n");
        return nullptr;
    }

    // 復(fù)制數(shù)據(jù)到 vector
    std::vector<uchar> buffer(dataPtr, dataPtr + len);
    env->ReleaseByteArrayElements(imageData, dataPtr, JNI_ABORT);

    // 通過 OpenCV imdecode 解碼圖片數(shù)據(jù)
    cv::Mat image = cv::imdecode(buffer, cv::IMREAD_UNCHANGED);
    if (image.empty()) {
        fprintf(stderr, "[JNI] Failed to decode image\n");
        jclass exceptionCls = env->FindClass("java/lang/RuntimeException");
        env->ThrowNew(exceptionCls, "Failed to decode image");
        return nullptr;
    }

    int width = image.cols;
    int height = image.rows;
    int channels = image.channels();

    emp_MRZ* pRes = nullptr;
    try {
        // 調(diào)用 detectMRZ 接口進行識別
        pRes = detectMRZ(image.data, width, height, channels, ocr);
        if (pRes == nullptr) {
            fprintf(stderr, "[JNI] detectMRZ returned NULL\n");
            return nullptr;
        }
        // ......
    }
    catch (const std::exception& e) {
        fprintf(stderr, "[JNI] Exception in detectMRZ: %s\n", e.what());
        jclass exceptionCls = env->FindClass("java/lang/RuntimeException");
        env->ThrowNew(exceptionCls, e.what());
        if (pRes) {
            Release_empMRZ(pRes);
        }
        return nullptr;
    }
}

這樣做的好處是:

  • Java 層代碼干凈、簡單(只讀流,不處理圖像)
  • 支持所有格式:JPEG、PNG、BMP、WebP 等
  • C++ 自動識別圖像通道:灰度、BGR、BGRA 等
  • 適合網(wǎng)絡(luò)圖像、文件流、Base64 解碼后圖像等各種來源
  • 易于跨平臺、跨語言傳輸(例如 HTTP 上傳)

Java 和 C++ 的圖像數(shù)據(jù)交互不算復(fù)雜,關(guān)鍵是理解圖像格式的要求。

到此這篇關(guān)于Java將圖像數(shù)據(jù)傳到C++的兩種高效實現(xiàn)方式對比的文章就介紹到這了,更多相關(guān)Java圖像數(shù)據(jù)傳到C++內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java安全編碼:防范Java安全漏洞的最佳實踐

    Java安全編碼:防范Java安全漏洞的最佳實踐

    Java作為一種跨平臺的編程語言,在廣泛應(yīng)用的同時,也會從時至?xí)r出現(xiàn)安全漏洞,這些漏洞可能會對Java應(yīng)用程序的安全性造成嚴(yán)重威脅,因此,必須采取必要的措施,以確保Java應(yīng)用程序的安全性,以最佳實踐來防范Java安全漏洞,是應(yīng)對安全威脅的最好方法之一,
    2024-01-01
  • Lombok中@Builder和@SuperBuilder注解的用法案例

    Lombok中@Builder和@SuperBuilder注解的用法案例

    @Builder?是?lombok?中的注解,可以使用builder()構(gòu)造的Person.PersonBuilder對象進行鏈?zhǔn)秸{(diào)用,給所有屬性依次賦值,這篇文章主要介紹了Lombok中@Builder和@SuperBuilder注解的用法,需要的朋友可以參考下
    2023-01-01
  • java Arrays工具類實例詳解

    java Arrays工具類實例詳解

    這篇文章主要介紹了java Arrays工具類實例詳解的相關(guān)資料,需要的朋友可以參考下
    2017-07-07
  • Java Socket實現(xiàn)多人聊天系統(tǒng)

    Java Socket實現(xiàn)多人聊天系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了Java Socket實現(xiàn)多人聊天系統(tǒng),具有圖形界面,實現(xiàn)文件傳輸功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-07-07
  • Java并發(fā)編程示例(十):線程組

    Java并發(fā)編程示例(十):線程組

    這篇文章主要介紹了Java并發(fā)編程示例(十):線程組,Java提供了ThreadGroup類來控制一個線程組,一個線程組可以通過線程對象來創(chuàng)建,也可以由其他線程組來創(chuàng)建,生成一個樹形結(jié)構(gòu)的線程,需要的朋友可以參考下
    2014-12-12
  • 基于jvm-sandbox的imock開發(fā)指南詳解

    基于jvm-sandbox的imock開發(fā)指南詳解

    這篇文章主要為大家介紹了基于jvm-sandbox的imock開發(fā)指南詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-08-08
  • Java面向?qū)ο蠛蛢?nèi)存分析圖文詳解

    Java面向?qū)ο蠛蛢?nèi)存分析圖文詳解

    這篇文章主要給大家介紹了關(guān)于Java面向?qū)ο蠛蛢?nèi)存分析的相關(guān)資料,文章可以讓初學(xué)者順利的分析內(nèi)存,更加容易的體會程序執(zhí)行過程中內(nèi)存的變化,需要的朋友可以參考下
    2021-05-05
  • 一文讀懂IDEA里面的Artifact到底是什么

    一文讀懂IDEA里面的Artifact到底是什么

    這篇文章主要介紹了IDEA里面的Artifact到底是什么,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧
    2021-01-01
  • 詳解Javaweb狀態(tài)管理的Session和Cookie

    詳解Javaweb狀態(tài)管理的Session和Cookie

    這篇文章主要介紹了Javaweb狀態(tài)管理的Session和Cookie,將瀏覽器與web服務(wù)器之間多次交互當(dāng)做一個整體來處理,并且多次交互所涉及的數(shù)據(jù)(狀態(tài))保存下來,需要的朋友可以參考下
    2023-05-05
  • java內(nèi)存泄漏排查過程及解決

    java內(nèi)存泄漏排查過程及解決

    公司某服務(wù)內(nèi)存持續(xù)增長,疑似內(nèi)存泄漏,未觸發(fā)OOM,排查方法包括檢查JVM配置、分析GC執(zhí)行狀態(tài)、導(dǎo)出堆內(nèi)存快照并用IDEA Profiler工具定位大對象及代碼
    2025-07-07

最新評論

平果县| 都安| 页游| 原阳县| 澜沧| 普宁市| 临湘市| 革吉县| 东海县| 沁水县| 临西县| 出国| 揭阳市| 苍山县| 西昌市| 泰安市| 浙江省| 鹤壁市| 共和县| 延长县| 五常市| 安多县| 荆州市| 呼图壁县| 寿阳县| 滕州市| 麻江县| 尤溪县| 林西县| 章丘市| 铜梁县| 黎城县| 开原市| 芒康县| 南郑县| 峨边| 牙克石市| 竹溪县| 清远市| 镇巴县| 弥勒县|