工作環境比較惡劣並且有較多干擾源的環境做視覺識別一般都使用工業相機,大恆水晶相機是比較常用的一種。比起來進口相機,雖然用起來會更麻煩,但好在價格便宜,各項指標也不低。
大恆水晶相機是提供SDK的方式跟OPENCV類的系統做集成,還做不到像很多進口相機一樣直接就有了系統級的驅動,這方面的資料還是不少的,下面是在網上摘的一個例子:(來源)
// test.cpp : 定義控制台應用程序的入口點。
//
#include "stdafx.h"
#include "GxIAPI.h"
#include "DxImageProc.h"
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
using namespace std;
using namespace cv;
GX_DEV_HANDLE m_hDevice; ///< 設備句柄
BYTE *m_pBufferRaw; ///< 原始圖像數據
BYTE *m_pBufferRGB; ///< RGB圖像數據,用於顯示和保存bmp圖像
int64_t m_nImageHeight; ///< 原始圖像高
int64_t m_nImageWidth; ///< 原始圖像寬
int64_t m_nPayLoadSize;
int64_t m_nPixelColorFilter; ///< Bayer格式
Mat test;
//圖像回調處理函數
static void GX_STDC OnFrameCallbackFun(GX_FRAME_CALLBACK_PARAM* pFrame)
{
//PrepareForShowImg();
if (pFrame->status == 0)
{
//對圖像進行某些操作
/*memcpy(m_pBufferRaw, pFrame->pImgBuf, pFrame->nImgSize);
// 黑白相機需要翻轉數據后顯示
for (int i = 0; i <m_nImageHeight; i++) {
memcpy(m_pImageBuffer + i*m_nImageWidth, m_pBufferRaw + (m_nImageHeight - i - 1)*m_nImageWidth, (size_t)m_nImageWidth);
}
IplImage* src;
src = cvCreateImage(cvSize(m_nImageWidth, m_nImageHeight), 8, 1);
src->imageData = (char*)m_pImageBuffer;
cvSaveImage("src.jpg", src);*/
memcpy(m_pBufferRaw, pFrame->pImgBuf, pFrame->nImgSize);
// RGB轉換
DxRaw8toRGB24(m_pBufferRaw
, m_pBufferRGB
, (VxUint32)(m_nImageWidth)
, (VxUint32)(m_nImageHeight)
, RAW2RGB_NEIGHBOUR
, DX_PIXEL_COLOR_FILTER(m_nPixelColorFilter)
, false);
// cv_Image->imageData = (char*)m_pBufferRGB;
// cvSaveImage("./test.bmp", cv_Image);
//test.data = m_pBufferRaw;
memcpy(test.data, m_pBufferRGB, m_nImageWidth*m_nImageHeight * 3);
imwrite("./test1.bmp", test);
namedWindow("test");
imshow("test", test);
waitKey(15);
}
return;
}
int main(int argc, char* argv[])
{
GX_STATUS emStatus = GX_STATUS_SUCCESS;
GX_OPEN_PARAM openParam;
uint32_t nDeviceNum = 0;
openParam.accessMode = GX_ACCESS_EXCLUSIVE;
openParam.openMode = GX_OPEN_INDEX;
openParam.pszContent = "1";
// 初始化庫
emStatus = GXInitLib();
if (emStatus != GX_STATUS_SUCCESS)
{
return 0;
}
// 枚舉設備列表
emStatus = GXUpdateDeviceList(&nDeviceNum, 1000);
if ((emStatus != GX_STATUS_SUCCESS) || (nDeviceNum <= 0))
{
return 0;
}
//打開設備
emStatus = GXOpenDevice(&openParam, &m_hDevice);
//設置采集模式連續采集
emStatus = GXSetEnum(m_hDevice, GX_ENUM_ACQUISITION_MODE, GX_ACQ_MODE_CONTINUOUS);
emStatus = GXSetInt(m_hDevice, GX_INT_ACQUISITION_SPEED_LEVEL, 1);
emStatus = GXSetEnum(m_hDevice, GX_ENUM_BALANCE_WHITE_AUTO, GX_BALANCE_WHITE_AUTO_CONTINUOUS);
bool bColorFliter = false;
// 獲取圖像大小
emStatus = GXGetInt(m_hDevice, GX_INT_PAYLOAD_SIZE, &m_nPayLoadSize);
// 獲取寬度
emStatus = GXGetInt(m_hDevice, GX_INT_WIDTH, &m_nImageWidth);
// 獲取高度
emStatus = GXGetInt(m_hDevice, GX_INT_HEIGHT, &m_nImageHeight);
test.create(m_nImageHeight, m_nImageWidth, CV_8UC3);
//判斷相機是否支持bayer格式
bool m_bColorFilter;
emStatus = GXIsImplemented(m_hDevice, GX_ENUM_PIXEL_COLOR_FILTER, &m_bColorFilter);
if (m_bColorFilter)
{
emStatus = GXGetEnum(m_hDevice, GX_ENUM_PIXEL_COLOR_FILTER, &m_nPixelColorFilter);
}
m_pBufferRGB = new BYTE[(size_t)(m_nImageWidth * m_nImageHeight * 3)];
if (m_pBufferRGB == NULL)
{
return false;
}
//為存儲原始圖像數據申請空間
m_pBufferRaw = new BYTE[(size_t)m_nPayLoadSize];
if (m_pBufferRaw == NULL)
{
delete[]m_pBufferRGB;
m_pBufferRGB = NULL;
return false;
}
//注冊圖像處理回調函數
emStatus = GXRegisterCaptureCallback(m_hDevice, NULL, OnFrameCallbackFun);
//發送開采命令
emStatus = GXSendCommand(m_hDevice, GX_COMMAND_ACQUISITION_START);
//---------------------
//
//在這個區間圖像會通過OnFrameCallbackFun接口返給用戶
Sleep(100000);
//
//---------------------
//發送停采命令
emStatus = GXSendCommand(m_hDevice, GX_COMMAND_ACQUISITION_STOP);
//注銷采集回調
emStatus = GXUnregisterCaptureCallback(m_hDevice);
if (m_pBufferRGB != NULL)
{
delete[]m_pBufferRGB;
m_pBufferRGB = NULL;
}
if (m_pBufferRaw != NULL)
{
delete[]m_pBufferRaw;
m_pBufferRaw = NULL;
}
emStatus = GXCloseDevice(m_hDevice);
emStatus = GXCloseLib();
return 0;
}
一般在工業設備上使用,需要進行監控及智能圖像識別的點往往會多於一個,這時候這種使用網絡進行數據傳輸的相機就顯示出來優勢了。
從大恆相機的開發手冊上可以查到,函數調用: status = GXUpdateDeviceList(&nDeviceNum, 1000);
返回的nDeviceNum就是當前網絡上存在的相機數量。
隨后可以使用相機的索引、序列號或者MAC地址方式來打開指定的相機。在網絡環境簡單的情況下,也可以使用IP地址打開指定相機,但通常這樣會增加額外的設備安裝時配置工作,所以並不建議。
//打開枚舉列表中的第一台設備。
//假設枚舉到了3台可用設備,那么用戶可設置stOpenParam參數的pszContent字段為1、2、3
stOpenParam.accessMode = GX_ACCESS_EXCLUSIVE;
stOpenParam.openMode = GX_OPEN_INDEX;
stOpenParam.pszContent = "1";
//通過序列號打開設備
stOpenParam.openMode = GX_OPEN_SN;
stOpenParam.pszContent = "EA00010002";
//通過IP地址打開設備
//stOpenParam.openMode = GX_OPEN_IP;
//stOpenParam.pszContent = "192.168.40.35";
//通過MAC地址打開設備
//stOpenParam.openMode = GX_OPEN_MAC;
//stOpenParam.pszContent = "54-04-A6-C2-7C-2F";
//根據打開方式選擇上面一種方式設置好參數后,可以使用下面函數打開相機
status = GXOpenDevice(&stOpenParam, &hDevice);
此外一個特別注意的小坑,SDK中提供了函數GXGetAllDeviceBaseInfo
來遍歷網絡所有設備的信息,可以從其中查詢相機的MAC地址、SN等各項信息。在實際工作中,可以使用這個函數獲取相機信息后保存起來供以后打開相機使用,千萬不能每次打開均使用此函數進行遍歷查詢,在一個網絡設備較多的環境中,這個調用速度會非常慢,從而導致程序掛起。