最近需要做一个通过摄像头拍照的小程序,正好也来学习一下OpenCV。
因为拍照需要预览,程序肯定是多线程的(不然会卡死)。
先用单线程测试,打开摄像头、预览、拍照代码都很简单,没什么问题。然后把代码变成多线程,就开始各种R6010错误。
在网上到处找资料,看到有不少人说,要用CoInitialize、CoInitializeEx可以解决。开开心心的测试了一下,结果发现根本没用。也许在旧版本能行吧(我用的OPENCV3.0版本)
继续找,最后得到的结果居然是VideoCapture、namedWindow、imshow、waitKey这些个函数都只能在MainThread中使用,WorkerThread都不能使用。
实现无法理解那些OpenCV的大牛们是怎样活下来的(估计是有别的高深的方法,我不知道吧。)
最后还是要靠自己来,最终摸索出来的代码如下,简单测试了一下,能够工作了,留存一下(说不定哪天还能用上)。
使用环境是VS2012, opencv3.0版
完整示例代码如下:
#include <opencv2/opencv.hpp>
#include <iostream>
#include <thread>
using namespace cv;
using namespace std;
Mat frame;
string photoFileName = "photo1.jpg";
VideoCapture cap;
//打开摄像头
void showVideo()
{
//打开第一个摄像头
cap.open(0);
//打开视频文件
//cap.open("ad.avi");
//检查是否成功打开
if(!cap.isOpened())
{
cerr << "Can not open a camera or file." << endl;
return;
}
//创建窗口
namedWindow("edges");
for(;;)
{
//从 cap 中读一帧,存到 frame
cap >> frame;
//如果未读到图像
if(frame.empty())
break;
imshow("edges", frame);
//等待 30ms,如果按键则推出循环
waitKey(30);
}
//退出时会自动释放 cap 中占用资源
}
void takePhoto(string fileName)
{
if(!frame.empty())
{
imwrite(fileName, frame);
}
else
{
cout << "frame is empty" << endl;
}
}
void showImage(string fileName)
{
// 读入一张图片,图片来源OpenCV的数据 ...opencv\sources\samples\data\目录下
//Mat img = imread("lena.jpg");
Mat img = imread(fileName);
if (img.empty())
{
cout << "打开图像失败!" << endl;
return;
}
// 创建一个名为 "Demo"窗口
namedWindow("Demo");
// 在窗口中显示图片
imshow("Demo", img);
//等待3000 ms后窗口自动关闭
waitKey(3000);
//需要主动释放窗体,否则第二次窗口可能显示不出来
cv::destroyWindow("Demo");
}
void closeVideo()
{
if ( cap.isOpened() )
{
cap.release();
//需要主动释放窗体,否则第二次窗口可能显示不出来
cv::destroyAllWindows();
return;
}
}
int main(int argc, char **argv)
{
bool bRun = true;
while(bRun)
{
cout << "1:打开摄像头" << endl;
cout << "2:拍照" << endl;
cout << "3:显示图片" << endl;
cout << "4:关闭摄像头" << endl;
cout << "9:退出程序" << endl;
cout << "请选择" << endl;
int i = 0;
cin >> i;
switch (i)
{
case 1: //showvideo
{
std::thread t1(showVideo);
//如果不使用detach,会报R6010错误
t1.detach();
}
break;
case 2: //takePhoto
{
std::thread t1(takePhoto, photoFileName);
t1.detach();
}
break;
case 3: //showImage
{
std::thread t2(showImage, photoFileName);
t2.detach();
}
break;
case 4: //closeVideo
{
closeVideo();
}
break;
case 9:
bRun = false;
break;
default:
cout << "请重新输入" << endl;
break;
}
}
return 0;
}