Opencv缺省的VideoCapture模块对于一些需要配置crossbar的采集卡支持不好,无法配置或者配置后视频格式不对,需要对其函数功能进行补充和修正。以圆刚cv710卡为例:
该卡hdmi采集要正常工作需要配置crossbar如下图的属性
对opencv要做以下修改
1,增加crossbar的属性配置项
在videoio.hpp 中增加配置crossbar Input 属性,正好看到空了个31,先用上,当然加在最后也行。
CAP_PROP_ISO_SPEED =30,
CAP_CROSSBAR_INPIN_TYPE = 31, //!< Add CrossBar Setting For some kind of videocard by whm
CAP_PROP_BACKLIGHT =32,
2,增加对crossbar input pin 类型的支持
修改 cap_dshow.cpp中的setPhyCon, 原本该函数只支持前4种类型的 PhysicalConnectorType enumeration, 新增加
PhysConn_Video_YRYBY和PhysConn_Video_SerialDigital,圆刚的cv710 hdmi采集就用到SerialDigital类型作为input pin.
void videoInput::setPhyCon(int id, int conn){
switch(conn){
case 0:
VDList[id]->connection = PhysConn_Video_Composite;
break;
case 1:
VDList[id]->connection = PhysConn_Video_SVideo;
break;
case 2:
VDList[id]->connection = PhysConn_Video_Tuner;
break;
case 3:
VDList[id]->connection = PhysConn_Video_USB;
break;
case 4:
VDList[id]->connection = PhysConn_Video_1394;
break;
case 5:
VDList[id]->connection = PhysConn_Video_YRYBY;
break;
case 6:
VDList[id]->connection = PhysConn_Video_SerialDigital;
break;
default:
return; //if it is not these types don't set crossbar
break;
}
VDList[id]->storeConn = conn;
VDList[id]->useCrossbar = true;
}
然后修改
bool VideoCapture_DShow::setProperty(int propIdx, double propVal) 函数
对设置的CAP_CROSSBAR_INPIN_TYPE 响应
增加部分如下
case CAP_CROSSBAR_INPIN_TYPE:
if (cvFloor(propVal) < 0)
break;
g_VI.stopDevice(m_index);
g_VI.setupDevice(m_index, cvFloor(propVal));
break;
该部分函数会调用前面修改的setPhyCon函数设置crossbar的contype并enable crossbar选项,然后关闭dshow control 重建调用其
int videoInput::start(int deviceID, videoDevice *VD) 函数初始化采集
可以看到这里函数这里原有的
if(VD->useCrossbar)
{
DebugPrintOut("SETUP: Checking crossbar\n");
routeCrossbar(&VD->pCaptureGraph, &VD->pVideoInputFilter, VD->connection, CAPTURE_MODE);
}
部分将被激活并调用routeCrossbar选择匹配的input pin并连接找到的PhysConn_Video_VideoDecoder类型output PIN并自动连接,这样就设置好了采集卡的crossbar.
最后,需要修改
static bool setSizeAndSubtype(videoDevice * VD, int attemptWidth, int attemptHeight, GUID mediatype){
VIDEOINFOHEADER *pVih = reinterpret_cast<VIDEOINFOHEADER*>(VD->pAmMediaType->pbFormat); 这个函数,原来的函数有个问题会导致采集卡找不到可以工作的匹配MediaFormat.请注意新增的红色部分
//set new size:
//width and height
HEADER(pVih)->biWidth = attemptWidth;
HEADER(pVih)->biHeight = attemptHeight;
//set new src/dst rect
pVih->rcSource.top = pVih->rcSource.left = pVih->rcTarget.top =pVih->rcTarget.left=0;
pVih->rcSource.right = pVih->rcTarget.right= attemptWidth;
pVih->rcSource.bottom = pVih->rcTarget.bottom = attemptHeight;
原来的代码没有这一块设置,在圆刚cv710上的表现就是仍然使用缺省原有的640x480 rcSource和rcTarget,结果是 hr = VD->streamConf->SetFormat(VD->pAmMediaType); 一直失败导致无法找到合适的MediaType. 所以需要新增这段代码以使mediatype结构数据匹配。
所有部分修改完毕后编译opensource替换原有lib和dll.测试下新的模块,发现已经可以连接自己的cv710了,代码中设置CAP_CROSSBAR_INPIN_TYPE 参数为6,正是PhysConn_Video_SerialDigital的值
c++测试部分代码:
void CcvtestDlg::OnBnClickedButton1()
{
// TODO: 在此添加控件通知处理程序代码
VideoCapture cap(0);
cap.set(CAP_PROP_FRAME_WIDTH, 1920);
cap.set(CAP_PROP_FRAME_HEIGHT, 1080);
cap.set(CAP_CROSSBAR_INPIN_TYPE , 6);
Mat img;namedWindow("test", WINDOW_NORMAL);
resizeWindow("test", 960, 640);
while (1)
{
if (cap.read(img))
{
imshow("test", img);
if ('q' ==waitKey(1))
break;
}
}
destroyAllWindows();
cap.release();
}
Python3测试代码
import cv2
print("test cv")
cap=cv2.VideoCapture(0)
cap.set(5,60)
cap.set(3,1920)
cap.set(4,1080)
cap.set(31,6)
ret,img=cap.read()
cv2.namedWindow("cap",cv2.WINDOW_NORMAL)
cv2.resizeWindow("cap",960,640);
while True:
ret,img=cap.read()
if ret==False:
continue
cv2.imshow("cap",img)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
然后就可以愉快的进行opencv video其他的工作了!