opencv无获取摄像头视频帧(YUV打开导致失败)

1 篇文章 0 订阅
1 篇文章 0 订阅

最近由于项目的原因,有一台工控机在没有打永恒之蓝补丁之前,应用程序使用opencv 3.4.1打开摄像头后显示视频内容都可以正常显示,但当安装完windows 7 x86永恒之蓝补丁后(KB4012215,KB4012212),应用程序无法正常显示摄像头的视频,表现为:OPENCV打开摄像头成功,但获取摄像头视频帧得到的数据为空,使用AMCAP2.exe进行测试摄像头,使用MJPG格式可以正常浏览,但把视频设置为YUV的格式后也无法预览。
于是想到把OPENCV设置为MJPG方式打开摄像头进行处理,却同样无法预览,测试代码如下:

int main(int argc, const char** argv)
{
    //if (!initLicense()) return -1;

    string assetFolder = "";
    string inputVideo = "";

    if (argc >= 2)
    {
        assetFolder = argv[1];
    }
    if (argc >= 3)
    {
        inputVideo = argv[2];
    }

    VideoCapture cap;
	cv::VideoWriter l_writer;
	int camid=0;
    if (!inputVideo.empty())
    {
        // open file
        cap.open(inputVideo);
    }
    else
    {
		cout<<" please input camera index:";
		cin>>camid;
		//设置图像宽度
        cap.set(CAP_PROP_FRAME_WIDTH,640);
        //设置图像高度
        cap.set(CAP_PROP_FRAME_HEIGHT,480);
        //设置帧率
        cap.set(CAP_PROP_FPS,30);
        //获取MJPE编码 这个值是固定的1196444237
        int fourcc= l_writer.fourcc('M','J','P','G');
        //设置编码格式,这里只能写在分辨率和帧率后面,否则无效
        cap.set(CAP_PROP_FOURCC,fourcc);
        // open camera
        cap.open(camid);
    }

    if (!cap.isOpened())
    {
        cerr << "can not open camera!" << endl;
        return -1;
    }

	//打印摄像头参数
	cout << "Cam :" << camid;
	cout << "宽度(width) =" << cap.get(CV_CAP_PROP_FRAME_WIDTH)<<endl; //宽度
	cout << "高度(height) =" << cap.get(CV_CAP_PROP_FRAME_HEIGHT)<<endl; //高度
	cout << "帧数(fbs) =" << cap.get(CV_CAP_PROP_FPS)<<endl;            //帧数
	cout << "亮度(brightness) =" << cap.get(CV_CAP_PROP_BRIGHTNESS)<<endl; //亮度
	cout << "对比度(contrast) =" << cap.get(CV_CAP_PROP_CONTRAST)<<endl; //对比度
	cout << "饱和度(saturation) =" << cap.get(CV_CAP_PROP_SATURATION)<<endl; //饱和度
	cout << "色调(hue) =" << cap.get(CV_CAP_PROP_HUE)<<endl; //色调
	cout << "曝光(exposure) =" << cap.get(CV_CAP_PROP_EXPOSURE)<<endl; //曝光
	int ex = static_cast<int>(cap.get(CV_CAP_PROP_FOURCC));//格式
	// Transform from int to char via Bitwise operators
	char EXT[] = { (char)(ex & 0XFF), (char)((ex & 0XFF00) >> 8), (char)((ex & 0XFF0000) >> 16), (char)((ex & 0XFF000000) >> 24), 0 };
	cout << "格式(fourcc) =" << EXT<<endl;

    string winName = "canvas";
    namedWindow(winName);
    moveWindow(winName, 10, 10);

    Mat frame;
    bool finish_get_faceimg = false;
    //Timer tmr;
    while (true)
    {
        //tmr.tic();
        cap >> frame;
		cap >> frame;
        if (frame.empty())
        {
            cerr << "frame empty!" << endl;
            break;
        }
        double fps = 0;//1000 / tmr.toc();
        putText(frame, "fps:" + std::to_string((long double)fps), Point(10, 20), FONT_HERSHEY_SIMPLEX, 0.6, CV_RGB(255, 0, 0), 1);

        imshow(winName, frame);
        if (waitKey(1) == 27)
            break;
    }

    cap.release();

    return 0;
}

经过多个版本的尝试依然没有解决问题,最终想到要不进行调试一步步进行跟进,就使用opencv3.0.0的debug版本进行调试(为什么使用opencv3.0.0,原因是由于这个版本比较老,原想这个问题会不会是新版本的问题,旧版本会不会没有这个问题呢),在调试过程中,终端程序在打开摄像头时发现输出信息显示" trying format YUV2…"等,后面就没有见到有mjpg格式了,心想明明是设置了mjpg,为什么还是使用yuv方式打开,进行翻查opencv代码,最终找到opencv在打开摄像头时会进行每一种编码方式尝试打开,并且是按顺序进行,当某一种方式打开成功后就不会再尝试别的方式打开,opencv打开摄像头的方式:

//-------------------------cap_dshow.cpp : int videoInput::start(int deviceID, videoDevice *VD)  getMediaSubtypeAsString(mediaSubtypes[i], guidStr);---------
       char guidStr[8];
            // try specified format and size
            getMediaSubtypeAsString(VD->tryVideoType, guidStr);
            DebugPrintOut("SETUP: trying specified format %s @ %ix%i\n", guidStr, VD->tryWidth, VD->tryHeight);

            if( setSizeAndSubtype(VD, VD->tryWidth, VD->tryHeight, VD->tryVideoType) ){
                VD->setSize(VD->tryWidth, VD->tryHeight);
                VD->videoType = VD->tryVideoType;
                foundSize = true;
            } else {
                // try specified size with all formats
                for(int i = 0; i < VI_NUM_TYPES; i++){

                    getMediaSubtypeAsString(mediaSubtypes[i], guidStr);

                    DebugPrintOut("SETUP: trying format %s @ %ix%i\n", guidStr, VD->tryWidth, VD->tryHeight);
                    if( setSizeAndSubtype(VD, VD->tryWidth, VD->tryHeight, mediaSubtypes[i]) ){
                        VD->setSize(VD->tryWidth, VD->tryHeight);
                        VD->videoType = mediaSubtypes[i];
                        foundSize = true;
                        break;
                    }
                }
            }
//-------------------------cap_dshow.cpp : videoInput::videoInput(){---------
	mediaSubtypes[0]     = MEDIASUBTYPE_RGB24;
    mediaSubtypes[1]     = MEDIASUBTYPE_RGB32;
    mediaSubtypes[2]     = MEDIASUBTYPE_RGB555;
    mediaSubtypes[3]     = MEDIASUBTYPE_RGB565;
    mediaSubtypes[4]     = MEDIASUBTYPE_YUY2;
    mediaSubtypes[5]     = MEDIASUBTYPE_YVYU;
    mediaSubtypes[6]     = MEDIASUBTYPE_YUYV;
    mediaSubtypes[7]     = MEDIASUBTYPE_IYUV;
    mediaSubtypes[8]     = MEDIASUBTYPE_UYVY;
    mediaSubtypes[9]     = MEDIASUBTYPE_YV12;
    mediaSubtypes[10]    = MEDIASUBTYPE_YVU9;
    mediaSubtypes[11]    = MEDIASUBTYPE_Y411;
    mediaSubtypes[12]    = MEDIASUBTYPE_Y41P;
    mediaSubtypes[13]    = MEDIASUBTYPE_Y211;
    mediaSubtypes[14]    = MEDIASUBTYPE_AYUV;
    mediaSubtypes[15]    = MEDIASUBTYPE_MJPG; // MGB   原位置

当YUV打开成功后,使用的摄像头的数据格式就会停止,因此就会使用yuv进行打开,但此时系统无法使用YUV读取摄像头数据,因而导致无法显示视频。
为了解决此问题,无法从windows 7 32位系统分析解决,因此使用修改opencv打开视频格式的方式解决了此问题,把打开的视频数据格式修改为以下顺序:mediaSubtypes[15] = MEDIASUBTYPE_MJPG;----- >mediaSubtypes[4] = MEDIASUBTYPE_MJPG;:

    mediaSubtypes[0]     = MEDIASUBTYPE_RGB24;
    mediaSubtypes[1]     = MEDIASUBTYPE_RGB32;
    mediaSubtypes[2]     = MEDIASUBTYPE_RGB555;
    mediaSubtypes[3]     = MEDIASUBTYPE_RGB565;
	mediaSubtypes[4]    = MEDIASUBTYPE_MJPG; // MGB   调整后的位置
    mediaSubtypes[5]     = MEDIASUBTYPE_YUY2;
    mediaSubtypes[6]     = MEDIASUBTYPE_YVYU;
    mediaSubtypes[7]     = MEDIASUBTYPE_YUYV;
    mediaSubtypes[8]     = MEDIASUBTYPE_IYUV;
    mediaSubtypes[9]     = MEDIASUBTYPE_UYVY;
    mediaSubtypes[10]     = MEDIASUBTYPE_YV12;
    mediaSubtypes[11]    = MEDIASUBTYPE_YVU9;
    mediaSubtypes[12]    = MEDIASUBTYPE_Y411;
    mediaSubtypes[13]    = MEDIASUBTYPE_Y41P;
    mediaSubtypes[14]    = MEDIASUBTYPE_Y211;
    mediaSubtypes[15]    = MEDIASUBTYPE_AYUV;

总结:
1.opencv存在一定的问题,无法通过接口设置其打开视频的格式
2.windows 7 32位更新永恒之蓝补丁后导致无法预览摄像头数据(YUV格式),找了两天都没有找到原因,此问题在另一个系统的windows 7 32下又没有问题(补丁更新的数量不一样,除了永恒之蓝补丁外,还更新了其他补丁),给我的感觉是由于永恒之蓝补丁导致当前系统的directx无法兼容所致,由于时间比较紧急,打过电话给微软,微软却说不是他们系统的问题,应该找一下设备应用程序开发商分析问题,工控机厂商也没有办法一时解决此问题。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值