Java調用海康SDK讀取圖像


前言

視頻識別的一個項目,前期采用Java調用OpenCV讀取的方案,然后發送到Redis服務器,由於OpenCV采圖像不穩定,需要研究使用海康SDK讀取圖像。由於本人海康SDK的demo已成功運行,這里直接刪除了demo里不需要的東西,demo正常運行也會附到本文。
海康windows64SDK下載
opencv-4-4-0下載
代碼示例下載

1、加載動態鏈接庫dll

下載海康SDK,並放到指定文件夾

HCNetSDK INSTANCE = (HCNetSDK) Native.loadLibrary("D:\\Java\\HCNetSDK\\庫文件\\HCNetSDK.dll", HCNetSDK.class);

PlayCtrl INSTANCE = (PlayCtrl) Native.loadLibrary("D:\\Java\\HCNetSDK\\庫文件\\PlayCtrl.dll", PlayCtrl.class);

這里采用了直接加載dll的方式,沒有用eclipse加載lib文件的方式,HCNetSDK用於登錄、預覽,PlayCtrl用於播放,OpenCV 4.4.0

2、調用邏輯

先調用NET_DVR_Init方法進行初始化,調用NET_DVR_Login_V30進行登錄,調用NET_DVR_RealPlay_V30進行預覽

重點來了

lPreviewHandle = hCNetSDK.NET_DVR_RealPlay_V30(lUserID, m_strClientInfo, fRealDataCallBack, null, true);

這里需要fRealDataCallBack預覽回調,是一個參數,需要自定義一個類去實現一個接口,

case HCNetSDK.NET_DVR_SYSHEAD是預覽時第一次會進入系統頭這個邏輯,相當於配置一下,這里是配置了PlayM4_SetDecCallBackSDK解碼回調,這里需要一個fDecCallBackSDK解碼回調函數,在下面附上

case HCNetSDK.NET_DVR_STREAMDATA:是上面配置完,下一次就會進入這個case語句,這個邏輯是放入碼流數據

    class FRealDataCallBack implements HCNetSDK.FRealDataCallBack_V30 {
        public void invoke(NativeLong lRealHandle, int dwDataType, ByteByReference pBuffer, int dwBufSize, Pointer pUser) {
            switch (dwDataType) {
                case HCNetSDK.NET_DVR_SYSHEAD: //系統頭
                    System.out.println(logHead + "FRealDataCallBack 系統頭");
                    if (!playControl.PlayM4_GetPort(m_lPort)) //獲取播放庫未使用的通道號
                    {
                        break;
                    }
                    if (dwBufSize > 0) {
                        if (!playControl.PlayM4_SetDecCallBack(m_lPort.getValue(), fDecCallBack))  //設置解碼回調
                        {
                            break;
                        }
                        // 設置解碼回調函數 解碼且顯示
                        // if (!playControl.PlayM4_SetDecCallBackEx(m_lPort.getValue(), fDecCallBack, null, null)) {
                        //     break;
                        // }
                        if (!playControl.PlayM4_SetStreamOpenMode(m_lPort.getValue(), PlayCtrl.STREAME_REALTIME))  //設置實時流播放模式
                        {
                            break;
                        }

                        if (!playControl.PlayM4_OpenStream(m_lPort.getValue(), pBuffer, dwBufSize, 1024 * 1024)) //打開流接口
                        {
                            break;
                        }
                        if (!playControl.PlayM4_Play(m_lPort.getValue(), null)) //播放開始
                        {
                            break;
                        }
                    }
                case HCNetSDK.NET_DVR_STREAMDATA:   //碼流數據
                    if (!playControl.PlayM4_InputData(m_lPort.getValue(), pBuffer, dwBufSize)) {
                        break;
                    }
            }
        }
    }

fDecCallBackSDK解碼回調函數如下,解碼回調函數里面的數據,是sdk軟解碼以后的數據,可以直接拿來處理,不過里面的代碼需要在40ms里處理完畢,不然會產生很大的延遲

    class FDecCallBack implements PlayCtrl.DecCallBack {
        @Override
        public void invoke(NativeLong nPort, ByteByReference pBuffer, NativeLong nSize, PlayCtrl.FRAME_INFO frameInfo, NativeLong nReserved1, NativeLong nReserved2) {
            if (++count % 6 == 0) {
                try {
                    handle(pBuffer, nSize.intValue(), frameInfo);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }

        //這樣在回調函數DecCallBack 中可以得到視音頻數據,其中視頻數據是YV12格式的,音頻數據是PCM格式的。
        public void handle(ByteByReference pBuffer, int dwBufSize, PlayCtrl.FRAME_INFO frameInfo) {
            src = null;
            dst = null;
            bufferedImage = null;
            boolean isLog = new Date().getSeconds() % 10 == 0;
            String printStr = null;
            if (isLog) {
                stopWatch.reset();
                stopWatch.start();
            }

            int width = frameInfo.nWidth.intValue();
            int height = frameInfo.nHeight.intValue();
            byte[] byteArray = pBuffer.getPointer().getByteArray(0, dwBufSize);

            src = new Mat(height + height / 2, width, CvType.CV_8UC1);
            src.put(0, 0, byteArray);
            if (isLog) {
                stopWatch.split();
                printStr = "";
                printStr += logHead + "put " + stopWatch.getSplitTime() + "\r\n";
            }

            dst = new Mat(height, width, CvType.CV_8UC3);
            Imgproc.cvtColor(src, dst, Imgproc.COLOR_YUV2BGR_YV12);
            if (isLog) {
                stopWatch.split();
                printStr += logHead + "cvtColor " + stopWatch.getSplitTime() + "\r\n";
            }

            bufferedImage = Mat2BufImg.Mat2BufImg(dst);
            if (isLog) {
                stopWatch.split();
                printStr += logHead + "Mat2BufImg " + stopWatch.getSplitTime() + "\r\n";
            }

            String imgHex = Mat2BufImg.bufImgToBase64(bufferedImage, "jpg");
            if (isLog) {
                stopWatch.split();
                printStr += logHead + "bufImgToBase64 " + stopWatch.getSplitTime() + "\r\n";
            }

            Jedis jedis = JedisUtil.getJedis();
            jedis.set(ip, imgHex);
            JedisUtil.close(jedis);
            if (isLog) {
                stopWatch.split();
                printStr += logHead + "set " + stopWatch.getSplitTime() + "\r\n";
                System.out.println(printStr);
            }
        }
    }

3、結尾

大體流程就是這樣子,要不我畫一張流程圖哇,哈哈


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM