官網
https://www.hikrobotics.com/cn/machinevision/productdetail?id=1730
MV-CA050-20UC
https://www.hikrobotics.com/cn2/source/vision/document/2021/9/7/%E6%B5%B7%E5%BA%B7%E6%9C%BA%E5%99%A8%E4%BA%BAUSB3.0%E5%B7%A5%E4%B8%9A%E9%9D%A2%E9%98%B5%E7%9B%B8%E6%9C%BA%E7%94%A8%E6%88%B7%E6%89%8B%E5%86%8CV2.1.0.pdf
2 軟件
1. 請從海康機器人官網 www.hikrobotics.com“服務支持”>“下載中心”>“機器視覺” 中下載 MVS 客戶端安裝包及 SDK 開發包。
https://www.hikrobotics.com/cn/machinevision/service/download?module=0
注意下載linux的最新版本壓縮包
下載后解壓
linux找到x86的壓縮包 解壓
打開執行安裝腳本
安裝命令 step.sh中的內容
從其中看出,被安裝在 opt/文件夾下
#!/bin/bash DIRNAME=`dirname $0` #PWD = `pwd` cd $DIRNAME #sed -i "s/export LD_LIBRARY_PATH/#export LD_LIBRARY_PATH/g" ~/.bashrc source ~/.bashrc if [ ! -d "/opt/MVS" ]; then echo "Install MVS,Please wait..." tar -C /opt -xzf ./MVS.tar.gz else echo "Uninstall MVS,Please wait..." rm -rf /opt/MVS echo "Install MVS,Please wait..." tar -C /opt -xzf ./MVS.tar.gz fi # if [ ! -d "/usr/local/Qt-5.6.3/lib/fonts" ]; then mkdir -p /usr/local/Qt-5.6.3/lib/fonts cp -r /opt/MVS/bin/fonts/* /usr/local/Qt-5.6.3/lib/fonts else echo "path exist..." fi # #if cat ~/.bashrc | grep -c "export LD_LIBRARY_PATH=/opt/MVS/bin" > /dev/null #then # echo "Include path exist" #else # echo "export LD_LIBRARY_PATH=/opt/MVS/bin" >> ~/.bashrc #fi #source ~/.bashrc echo "Set up the SDK environment..." sh $DIRNAME/set_usb_priority.sh source $DIRNAME/set_env_path.sh sh $DIRNAME/set_sdk_version.sh if [ -f /opt/MVS/driver/unload.sh ]; then sh /opt/MVS/driver/unload.sh fi sh /opt/MVS/logserver/RemoveServer.sh sh /opt/MVS/logserver/InstallServer.sh echo "Install MVS complete!" echo "Tips: You should be launch a new terminal or execute source command for the bash environment!" cd $PWD
打開軟件
sdk文件
安裝的時候被解壓在 opt/ 文件夾
打開相機
設備列表會自動顯示當前枚舉到的設備。也可通過點擊 USB 接口處的刷新按鈕 , 對設備列表中顯示的設備進行手動刷新,如圖 2-7 所示。
枚舉到設備后,雙擊連接設備,MVS 客戶端主界面如圖 2-8 所示。
其他說明
SDK開發
開發樣例
說明
工業相機Linux SDK使用說明。Build20180531 =========================================================================== 版本號: 2.4.0.5 支持相機:GigE相機和U3V相機 支持系統:ubuntu 14.04(32和64位)、ubuntu 16.04(32和64位)、centos7(32和64位)、 redhat(64位) =========================================================================== 運行環境配置 =========================================================================== 在編譯示例程序之前,確認LD_LIBRARY_PATH和MVCAM_COMMON_RUNENV兩個環境變量已經生效. eg: echo $LD_LIBRARY_PATH 輸出:/opt/MVS/lib/xxx:... echo $MVCAM_COMMON_RUNENV 輸出:/opt/MVS/lib 如果當前環境不存在以上兩個環境變量或者變量中不包含/opt/MVS/lib相關值時,需要跳轉到安裝包所在路徑,並輸入: source ./set_env_path.sh =========================================================================== 程序演示 =========================================================================== Display:圖像顯示例程。 使用前請先安裝X11相關庫:sudo apt-get install libx11-dev. 創建的顯示窗口不支持拉伸。 1. 使用xlib庫來創建圖像窗口 2. 枚舉設備,選擇設備並創建句柄,打開設備 3. 開始取流,調用顯示函數傳入窗口句柄 4. 輸入enter結束取流 =========================================================================== ForceIP:設置forceip 1. 枚舉設備,選擇設備並創建句柄 2. 設置forceip 3. 輸入enter結束取流 =========================================================================== Grab_ImageCallback:回調方式抓取圖像 1. 枚舉設備,選擇設備並創建句柄,打開設備 2. 設置觸發模式為off 3. 開始取流 4. 若有圖像數據,ImageCallBackEx會被調用 5. 輸入enter結束取流 =========================================================================== GrabImage:主動方式抓取圖像 1. 枚舉設備,選擇設備並創建句柄,打開設備 2. 設置觸發模式為off 3. 開始取流,開線程用來獲取圖像數據 4. 若有圖像數據,MV_CC_GetOneFrameTimeout會返回MV_OK 5. 輸入enter結束取流 =========================================================================== GrabMultipleCamera:多相機取流 1. 枚舉設備,選擇設備並創建句柄,打開設備 2. 設置觸發模式為off 3. 開始取流,開線程用來獲取圖像數據 4. 若有圖像數據,MV_CC_GetOneFrameTimeout會返回MV_OK 5. 輸入enter結束取流 =========================================================================== ImageProcess:圖像處理(存圖和像素格式轉換) 1. 枚舉設備,選擇設備並創建句柄,打開設備 2. 開始取流,若有圖像數據,MV_CC_GetOneFrameTimeout會返回MV_OK 3. 選擇case 0、1或2來進行不同圖像處理方式 4. 輸入enter結束取流 =========================================================================== ReconnectDemo:重連示例 1. 開線程,用於重連相機,線程中有枚舉、創建句柄、打開相機、注冊異常回調功能 2. 若有相機異常斷線,則會重新枚舉相機並連接第0個相機, 3. 輸入enter結束程序 =========================================================================== SetIO:設置IO 1. 枚舉設備,選擇設備並創建句柄,打開設備 2. 獲取LineSelector,設置LineSelector 3. 獲取LineMode,設置LineMode 4. 輸入enter結束程序 =========================================================================== SetParam:設置參數 1. 枚舉設備,選擇設備並創建句柄,打開設備 2. 設置int型變量,獲取int型變量 3. 設置float型變量,獲取float型變量 4. 設置enum型變量,獲取enum型變量 5. 設置bool型變量,獲取bool型變量 6. 設置string型變量,獲取string型變量 7. 輸入enter結束程序 =========================================================================== Trigger_Image:觸發方式取流 1. 枚舉設備,選擇設備並創建句柄,打開設備 2. 設置觸發模式為on,設置觸發源為軟觸發 3. 開始取流,開線程用來發送觸發命令以及獲取圖像數據 4. 輸入enter結束取流 =========================================================================== Trigger_ImageCallback: 觸發回調方式取流 1. 枚舉設備,選擇設備並創建句柄,打開設備 2. 設置觸發模式為on,設置觸發源為軟觸發 3. 開始取流,開線程用來發送觸發命令 4. 若有圖像數據,ImageCallBackEx會被調用 5. 輸入enter結束取流 =========================================================================== ConnectSpecCamera: 無枚舉連接相機(相當於MVS中的遠程連接相機) 1. 填充相機ip、網卡ip 2. 創建句柄,連接相機 3. 開始取流 =========================================================================== Events: 使用相機事件 1. 枚舉設備,選擇設備並創建句柄,打開設備 2. 開啟Event 3. 注冊Event事件回調(可注冊單個、多個、全部事件) 4. 開啟取流,當事件來臨時會在回調中響應 =========================================================================== MultiCast: 組播取流 1. 枚舉設備,選擇設備並創建句柄,打開設備 2. 選擇control或monitor模式 3. 輸入組播組ip和端口 4. 開始取流(若是m端需c端開啟取流命令) =========================================================================== ParametrizeCamera_FileAccess: 1. 枚舉設備,選擇設備並創建句柄,打開設備 2. 開線程,使用FileAccess讀取相機配置文件 3. 開線程,使用FileAccess將配置文件寫入相機 =========================================================================== ParametrizeCamera_LoadAndSave: 需要確保代碼編輯器輸入的路徑為UTF-8編碼格式 1. 枚舉設備,選擇設備並創建句柄,打開設備 2. 將相機屬性導出到文件中 3. 從文件中導入相機屬性
python開發樣例(1) 獲取原始視頻流-無法opencv顯示
參考其SDK提供的流程圖我們可以看出,相機控制分成枚舉、打開、參數設置、關閉,銷毀句柄五個步驟
python開發樣例(2) 獲取原始視頻流-opencv顯示
1設置相機輸出像素格式
鏈接相機-屬性樹-Image Format Control-pixel format - RGB8
2設置相機分辨率
鏈接相機-屬性樹-Image Format Control- width max height max
保存
用戶設置保存-執行
斷開相機鏈接,不然占用導致后續無法程序連接
保險一點重新鏈接相機,查看默認參數是否為上次保存的。
創建和執行代碼
# -- coding: utf-8 -- import sys import threading import os import termios import time import cv2 import numpy as np from ctypes import * sys.path.append("../MvImport") from MvCameraControl_class import * g_bExit = False img_w=1920 img_h=1080 img_c=3 # 顯示圖像 def image_show(image): image = cv2.resize(image, (600, 400), interpolation=cv2.INTER_AREA) cv2.imshow('test', image) k = cv2.waitKey(1) & 0xff # 源程序-為線程定義一個函數 def work_thread(cam=0, pData=0, nDataSize=0): stFrameInfo = MV_FRAME_OUT_INFO_EX() memset(byref(stFrameInfo), 0, sizeof(stFrameInfo)) while True: ret = cam.MV_CC_GetOneFrameTimeout(pData, nDataSize, stFrameInfo, 1000) if ret == 0: print ("get one frame: Width[%d], Height[%d], PixelType[0x%x], nFrameNum[%d]" % (stFrameInfo.nWidth, stFrameInfo.nHeight, stFrameInfo.enPixelType,stFrameInfo.nFrameNum)) else: print ("no data[0x%x]" % ret) if g_bExit == True: break #opencv轉換顯示 def work_thread_rgb82bgr(cam=0, pData=0, nDataSize=0): stFrameInfo = MV_FRAME_OUT_INFO_EX() memset(byref(stFrameInfo), 0, sizeof(stFrameInfo)) while True: ret = cam.MV_CC_GetOneFrameTimeout(pData, nDataSize, stFrameInfo, 1000) if ret == 0: print ("get one frame: Width[%d], Height[%d], PixelType[0x%x], nFrameNum[%d]" % (stFrameInfo.nWidth, stFrameInfo.nHeight, stFrameInfo.enPixelType,stFrameInfo.nFrameNum)) print('----', stFrameInfo.enPixelType) #if stFrameInfo.enPixelType=='PixelType_Gvsp_RGB8_Packed': temp = np.asarray(pData) temp = temp.reshape((img_h, img_w, img_c)) temp = cv2.cvtColor(temp, cv2.COLOR_BGR2RGB) cv2.namedWindow("temp", cv2.WINDOW_NORMAL) cv2.imshow('temp',temp) cv2.waitKey(1) #else: #print("圖像輸出格式不是BGR8,請先使用MVS軟件設置相機默認輸出圖像格式為BGR8....") else: print ("no data[0x%x]" % ret) if g_bExit == True: break def press_any_key_exit(): fd = sys.stdin.fileno() old_ttyinfo = termios.tcgetattr(fd) new_ttyinfo = old_ttyinfo[:] new_ttyinfo[3] &= ~termios.ICANON new_ttyinfo[3] &= ~termios.ECHO #sys.stdout.write(msg) #sys.stdout.flush() termios.tcsetattr(fd, termios.TCSANOW, new_ttyinfo) try: os.read(fd, 7) except: pass finally: termios.tcsetattr(fd, termios.TCSANOW, old_ttyinfo) if __name__ == "__main__": SDKVersion = MvCamera.MV_CC_GetSDKVersion() print ("SDKVersion[0x%x]" % SDKVersion) deviceList = MV_CC_DEVICE_INFO_LIST() tlayerType = MV_GIGE_DEVICE | MV_USB_DEVICE # ch:枚舉設備 | en:Enum device ret = MvCamera.MV_CC_EnumDevices(tlayerType, deviceList) if ret != 0: print ("enum devices fail! ret[0x%x]" % ret) sys.exit() if deviceList.nDeviceNum == 0: print ("find no device!") sys.exit() print ("Find %d devices!" % deviceList.nDeviceNum) for i in range(0, deviceList.nDeviceNum): mvcc_dev_info = cast(deviceList.pDeviceInfo[i], POINTER(MV_CC_DEVICE_INFO)).contents if mvcc_dev_info.nTLayerType == MV_GIGE_DEVICE: print ("\ngige device: [%d]" % i) strModeName = "" for per in mvcc_dev_info.SpecialInfo.stGigEInfo.chModelName: strModeName = strModeName + chr(per) print ("device model name: %s" % strModeName) nip1 = ((mvcc_dev_info.SpecialInfo.stGigEInfo.nCurrentIp & 0xff000000) >> 24) nip2 = ((mvcc_dev_info.SpecialInfo.stGigEInfo.nCurrentIp & 0x00ff0000) >> 16) nip3 = ((mvcc_dev_info.SpecialInfo.stGigEInfo.nCurrentIp & 0x0000ff00) >> 8) nip4 = (mvcc_dev_info.SpecialInfo.stGigEInfo.nCurrentIp & 0x000000ff) print ("current ip: %d.%d.%d.%d\n" % (nip1, nip2, nip3, nip4)) elif mvcc_dev_info.nTLayerType == MV_USB_DEVICE: print ("\nu3v device: [%d]" % i) strModeName = "" for per in mvcc_dev_info.SpecialInfo.stUsb3VInfo.chModelName: if per == 0: break strModeName = strModeName + chr(per) print ("device model name: %s" % strModeName) strSerialNumber = "" for per in mvcc_dev_info.SpecialInfo.stUsb3VInfo.chSerialNumber: if per == 0: break strSerialNumber = strSerialNumber + chr(per) print ("user serial number: %s" % strSerialNumber) if sys.version >= '3': nConnectionNum = input("please input the number of the device to connect:") else: nConnectionNum = raw_input("please input the number of the device to connect:") if int(nConnectionNum) >= deviceList.nDeviceNum: print ("intput error!") sys.exit() # ch:創建相機實例 | en:Creat Camera Object cam = MvCamera() # ch:選擇設備並創建句柄| en:Select device and create handle stDeviceList = cast(deviceList.pDeviceInfo[int(nConnectionNum)], POINTER(MV_CC_DEVICE_INFO)).contents ret = cam.MV_CC_CreateHandle(stDeviceList) if ret != 0: print ("create handle fail! ret[0x%x]" % ret) sys.exit() # ch:打開設備 | en:Open device ret = cam.MV_CC_OpenDevice(MV_ACCESS_Exclusive, 0) if ret != 0: print ("open device fail! ret[0x%x]" % ret) sys.exit() # ch:探測網絡最佳包大小(只對GigE相機有效) | en:Detection network optimal package size(It only works for the GigE camera) if stDeviceList.nTLayerType == MV_GIGE_DEVICE: nPacketSize = cam.MV_CC_GetOptimalPacketSize() if int(nPacketSize) > 0: ret = cam.MV_CC_SetIntValue("GevSCPSPacketSize",nPacketSize) if ret != 0: print ("Warning: Set Packet Size fail! ret[0x%x]" % ret) else: print ("Warning: Get Packet Size fail! ret[0x%x]" % nPacketSize) # ch:設置觸發模式為off | en:Set trigger mode as off ret = cam.MV_CC_SetEnumValue("TriggerMode", MV_TRIGGER_MODE_OFF) if ret != 0: print ("set trigger mode fail! ret[0x%x]" % ret) sys.exit() # ch:獲取數據包大小 | en:Get payload size stParam = MVCC_INTVALUE() memset(byref(stParam), 0, sizeof(MVCC_INTVALUE)) ret = cam.MV_CC_GetIntValue("PayloadSize", stParam) if ret != 0: print ("get payload size fail! ret[0x%x]" % ret) sys.exit() nPayloadSize = stParam.nCurValue # ch:開始取流 | en:Start grab image ret = cam.MV_CC_StartGrabbing() if ret != 0: print ("start grabbing fail! ret[0x%x]" % ret) sys.exit() #將PayloadSize的uint數據轉為可供numpy處理的數據,后面就可以用numpy將其轉化為numpy數組格式。 data_buf = (c_ubyte * nPayloadSize)() try: #有些代碼可能會在data_buf前面加上byteref,如果這樣做的話,就會將數據轉為浮點型, # 而opencv需要的是整型,會報錯,所以這里就不需要轉化了 #hThreadHandle = threading.Thread(target=work_thread_rgb82bgr, args=(cam, byref(data_buf), nPayloadSize)) hThreadHandle = threading.Thread(target=work_thread_rgb82bgr, args=(cam, data_buf, nPayloadSize)) hThreadHandle.start() hThreadHandle.start() except: print ("error: unable to start thread") print ("press a key to stop grabbing.") press_any_key_exit() g_bExit = True hThreadHandle.join() # ch:停止取流 | en:Stop grab image ret = cam.MV_CC_StopGrabbing() if ret != 0: print ("stop grabbing fail! ret[0x%x]" % ret) del data_buf sys.exit() # ch:關閉設備 | Close device ret = cam.MV_CC_CloseDevice() if ret != 0: print ("close deivce fail! ret[0x%x]" % ret) del data_buf sys.exit() # ch:銷毀句柄 | Destroy handle ret = cam.MV_CC_DestroyHandle() if ret != 0: print ("destroy handle fail! ret[0x%x]" % ret) del data_buf sys.exit() del data_buf
注意
0 修改代碼中湘囧分辨率
img_w=1920 img_h=1080 img_c=3
1 導入SDK路徑
因為需要用到SDK的接口函數,所以需要導入相應的庫,官方的路徑是這樣的,這是因為這個包在程序的同一個文件夾下,所以前面的都可以省略,但我們使用的時候,最好把它的絕對路徑給寫上,我的路徑是這樣的,可以參考
sys.path.append("../MvImport") #導入相應SDK的庫,實際安裝位置絕對路徑 #/opt/MVS/Samples/64/Python/MvImport
2 原始數據轉化成numpy
data_buf = (c_ubyte * nPayloadSize)()這一句話將PayloadSize的uint數據轉為可供numpy處理的數據,后面就可以用numpy將其轉化為numpy數組格式。
# ch:開始取流 | en:Start grab image ret = cam.MV_CC_StartGrabbing() if ret != 0: print ("start grabbing fail! ret[0x%x]" % ret) sys.exit() #將PayloadSize的uint數據轉為可供numpy處理的數據,后面就可以用numpy將其轉化為numpy數組格式。 data_buf = (c_ubyte * nPayloadSize)()
3 線程調用
try: #有些代碼可能會在data_buf前面加上byteref,如果這樣做的話,就會將數據轉為浮點型, # 而opencv需要的是整型,會報錯,所以這里就不需要轉化了 #hThreadHandle = threading.Thread(target=work_thread_rgb82bgr, args=(cam, byref(data_buf), nPayloadSize)) hThreadHandle = threading.Thread(target=work_thread_rgb82bgr, args=(cam, data_buf, nPayloadSize)) hThreadHandle.start()