一、准备
本人的环境为 VS2015 & opencv4.1.1 & xzing二维码解码库
另opencv的库解压开需要放到环境变量中声明:比如 D:\Opencv_X64\x64\vc14\bin
二、新建工程
首先在qt的pro文件中添加入头文件及库信息,如下所示
#opencv
INCLUDEPATH += D:/Opencv_X64/include
LIBS += -LD:/Opencv_X64/x64/vc14/lib -lopencv_highgui411 \
-lopencv_video411 \
-lopencv_videoio411 \
-lopencv_core411 \
-lopencv_imgproc411 \
-lopencv_imgcodecs411
#zxing
unix|win32: LIBS += -L$$PWD/zxing_lib/ -llibzxing
INCLUDEPATH += $$PWD/zxing
DEPENDPATH += $$PWD/zxing
三、程序编写
1、获取摄像头数量,采取最简单的方法,轮流打开摄像头,获取到摄像头的数量,
代码如下所示:
//获取相机及摄像头信息
void Thread_OpenCV::GetCamaraInfo()
{
cv::VideoCapture temp_camera;
int maxTested = 10;
for (int i = 0; i < maxTested; i++)
{
cv::VideoCapture temp_camera(i);
bool res = (!temp_camera.isOpened());
temp_camera.release();
//cv::destroyAllWindows();
if (res)
{
CameraInfo.CamaraCnt = i;
emit this->Sig_Camera_Update(CameraInfo); //摄像头数量更新 用于外部调用 统计显示数量
break;
}
}
}
2、获取摄像头数据
result = cap.read(src_image); //读mat
3、将mat数据转成QImage,供图片显示
//Mat转成QImage
QImage Thread_OpenCV::MatImageToQt(const cv::Mat &src)
{
//CV_8UC1 8位无符号的单通道---灰度图片
if(src.type() == CV_8UC1)
{
//使用给定的大小和格式构造图像
//QImage(int width, int height, Format format)
QImage qImage(src.cols,src.rows,QImage::Format_Indexed8);
//扩展颜色表的颜色数目
qImage.setColorCount(256);
//在给定的索引设置颜色
for(int i = 0; i < 256; i ++)
{
//得到一个黑白图
qImage.setColor(i,qRgb(i,i,i));
}
//复制输入图像,data数据段的首地址
uchar *pSrc = src.data;
//
for(int row = 0; row < src.rows; row ++)
{
//遍历像素指针
uchar *pDest = qImage.scanLine(row);
//从源src所指的内存地址的起始位置开始拷贝n个
//字节到目标dest所指的内存地址的起始位置中
memcmp(pDest,pSrc,src.cols);
//图像层像素地址
pSrc += src.step;
}
return qImage;
}
//为3通道的彩色图片
else if(src.type() == CV_8UC3)
{
//得到图像的的首地址
const uchar *pSrc = (const uchar*)src.data;
//以src构造图片
QImage qImage(pSrc,src.cols,src.rows,src.step,QImage::Format_RGB888);
//在不改变实际图像数据的条件下,交换红蓝通道
return qImage.rgbSwapped();
}
//四通道图片,带Alpha通道的RGB彩色图像
else if(src.type() == CV_8UC4)
{
const uchar *pSrc = (const uchar*)src.data;
QImage qImage(pSrc, src.cols, src.rows, src.step, QImage::Format_ARGB32);
//返回图像的子区域作为一个新图像
return qImage.copy();
}
else
{
return QImage();
}
}
4、将获取到的QImage转成灰度图像,用于zxing提取二维码
//灰度转换
cv::cvtColor(src, matGray, CV_BGR2GRAY);
5、zxing解码,并获取到二维码信息
try
{
//初始化
zxing::Ref<zxing::LuminanceSource> source = MatSource::create(matGray);
// /*int width = source->getWidth();
// int height = source->getHeight();*/
// /*fprintf(stderr, "image width: %d, height: %d\n", width, height);*/
zxing::Ref<zxing::Reader> reader;
reader.reset(new zxing::MultiFormatReader);
zxing::Ref<zxing::Binarizer> binarizer(new zxing::GlobalHistogramBinarizer(source));
zxing::Ref<zxing::BinaryBitmap> bitmap(new zxing::BinaryBitmap(binarizer));
//开始解码
zxing::Ref<zxing::Result> result(reader->decode(bitmap, zxing::DecodeHints(zxing::DecodeHints::TRYHARDER_HINT)));
//获取解析结果
Temp_String = QString::fromStdString(result->getText()->getText());
//qDebug() << Temp_String;
emit this->Sig_Camera_Qrcode_Update(State,Temp_String); //信息发至主界面
}
catch (zxing::ReaderException& e)
{
qDebug() << e.what() << " (ReaderException)" << endl;
}
catch (zxing::IllegalArgumentException& e)
{
qDebug() << e.what() << " (IllegalArgumentException)" << endl;
}
catch (zxing::Exception& e)
{
qDebug() << e.what() << " (Exception)" << endl;
}
6、获取到摄像头数据并解析,可以定时获取,一般为30ms左右,可以保证图片不会有卡顿的现象。
//显示像素信息
void Thread_OpenCV::ReadCamara()
{
bool result;
cv::Mat matGray; //灰度值
result = cap.read(src_image); //读mat
if(result)
{
//发送数据到主线程 用于显示
QImage temp_image = MatImageToQt(src_image); //mat转换
emit this->Sig_Camera_Show_Image(temp_image);
//解析二维码
ZxingAnalysis(src_image);
}
// ZxingPictureQrcode("D:/Downloads/1569737649.png");
}
四、其它
附完整代码如下:
#include "thread_opencv.h"
#include <QImage>
#include <QPixmap>
#include <QDebug>
#include <opencv2/videoio.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/video.hpp>
#include <opencv2/video/video.hpp>
#include <opencv2/videoio/videoio_c.h>
#include <zxing/qrcode/QRCodeReader.h>
#include "zxing/LuminanceSource.h"
#include "zxing/Reader.h"
#include "zxing/common/GlobalHistogramBinarizer.h"
#include "zxing/DecodeHints.h"
#include "zxing/datamatrix/DataMatrixReader.h"
#include "zxing/BinaryBitmap.h"
#include "zxing/Binarizer.h"
#include "zxing/Exception.h"
#include "zxing/MatSource.h"
#include <zxing/MultiFormatReader.h>
#include "zxing/Exception.h"
#include "zxing/ReaderException.h"
_VAR_CAMERA CameraInfo;
//宏定义
#if CV_MAJOR_VERSION >= 4
#ifndef CV_CAP_PROP_FRAME_WIDTH
#define CV_CAP_PROP_FRAME_WIDTH cv::CAP_PROP_FRAME_WIDTH
#endif
#ifndef CV_CAP_PROP_FRAME_HEIGHT
#define CV_CAP_PROP_FRAME_HEIGHT cv::CAP_PROP_FRAME_HEIGHT
#endif
#ifndef CV_BGR2GRAY
#define CV_BGR2GRAY cv::COLOR_BGR2GRAY
#endif
#endif
Thread_OpenCV::Thread_OpenCV()
{
image = new QImage();
}
//运行
void Thread_OpenCV::run()
{
static bool first_cam = false;
for(;;)
{
if(!first_cam)
{
GetCamaraInfo();
first_cam = true;
}
//开关摄像头
if(CameraInfo.OpenCloseFlag)
{
CameraInfo.OpenCloseFlag = false;
//开关标记
if(CameraInfo.CameraOC)
{
GetCamaraInfo();
if(CameraInfo.CurrentID < CameraInfo.CamaraCnt)
{
cap.open(CameraInfo.CurrentID);
//检查摄像头是否打开
if (!cap.isOpened())
{
qDebug() << "CV cant open";
}
CameraInfo.isComOpen = true;
}
}
else
{
cap.release();
//cv::destroyAllWindows();
CameraInfo.isComOpen = false;
}
}
//读摄像头帧数据
if(CameraInfo.isComOpen)
{
ReadCamara(); //获取到摄像头信息
}
msleep(33); //延时
}
}
//显示像素信息
void Thread_OpenCV::ReadCamara()
{
bool result;
cv::Mat matGray; //灰度值
result = cap.read(src_image); //读mat
if(result)
{
//发送数据到主线程 用于显示
QImage temp_image = MatImageToQt(src_image); //mat转换
emit this->Sig_Camera_Show_Image(temp_image);
//解析二维码
ZxingAnalysis(src_image);
}
// ZxingPictureQrcode("D:/Downloads/1569737649.png");
}
//Mat转成QImage
QImage Thread_OpenCV::MatImageToQt(const cv::Mat &src)
{
//CV_8UC1 8位无符号的单通道---灰度图片
if(src.type() == CV_8UC1)
{
//使用给定的大小和格式构造图像
//QImage(int width, int height, Format format)
QImage qImage(src.cols,src.rows,QImage::Format_Indexed8);
//扩展颜色表的颜色数目
qImage.setColorCount(256);
//在给定的索引设置颜色
for(int i = 0; i < 256; i ++)
{
//得到一个黑白图
qImage.setColor(i,qRgb(i,i,i));
}
//复制输入图像,data数据段的首地址
uchar *pSrc = src.data;
//
for(int row = 0; row < src.rows; row ++)
{
//遍历像素指针
uchar *pDest = qImage.scanLine(row);
//从源src所指的内存地址的起始位置开始拷贝n个
//字节到目标dest所指的内存地址的起始位置中
memcmp(pDest,pSrc,src.cols);
//图像层像素地址
pSrc += src.step;
}
return qImage;
}
//为3通道的彩色图片
else if(src.type() == CV_8UC3)
{
//得到图像的的首地址
const uchar *pSrc = (const uchar*)src.data;
//以src构造图片
QImage qImage(pSrc,src.cols,src.rows,src.step,QImage::Format_RGB888);
//在不改变实际图像数据的条件下,交换红蓝通道
return qImage.rgbSwapped();
}
//四通道图片,带Alpha通道的RGB彩色图像
else if(src.type() == CV_8UC4)
{
const uchar *pSrc = (const uchar*)src.data;
QImage qImage(pSrc, src.cols, src.rows, src.step, QImage::Format_ARGB32);
//返回图像的子区域作为一个新图像
return qImage.copy();
}
else
{
return QImage();
}
}
//开关
void Thread_OpenCV::Open_Close_Camera(bool state, uint8_t id)
{
if(state)
{
CameraInfo.OpenCloseFlag = true;
CameraInfo.CameraOC = true;
CameraInfo.CurrentID = id;
}
else
{
CameraInfo.OpenCloseFlag = true;
CameraInfo.CameraOC = false;
CameraInfo.CurrentID = id;
}
}
//解码
void Thread_OpenCV::ZxingAnalysis(cv::Mat src)
{
bool State = true;
QString Temp_String;
cv::Mat matGray;
//灰度转换
cv::cvtColor(src, matGray, CV_BGR2GRAY);
try
{
//初始化
zxing::Ref<zxing::LuminanceSource> source = MatSource::create(matGray);
// /*int width = source->getWidth();
// int height = source->getHeight();*/
// /*fprintf(stderr, "image width: %d, height: %d\n", width, height);*/
zxing::Ref<zxing::Reader> reader;
reader.reset(new zxing::MultiFormatReader);
zxing::Ref<zxing::Binarizer> binarizer(new zxing::GlobalHistogramBinarizer(source));
zxing::Ref<zxing::BinaryBitmap> bitmap(new zxing::BinaryBitmap(binarizer));
//开始解码
zxing::Ref<zxing::Result> result(reader->decode(bitmap, zxing::DecodeHints(zxing::DecodeHints::TRYHARDER_HINT)));
//获取解析结果
Temp_String = QString::fromStdString(result->getText()->getText());
//qDebug() << Temp_String;
emit this->Sig_Camera_Qrcode_Update(State,Temp_String); //信息发至主界面
}
catch (zxing::ReaderException& e)
{
qDebug() << e.what() << " (ReaderException)" << endl;
}
catch (zxing::IllegalArgumentException& e)
{
qDebug() << e.what() << " (IllegalArgumentException)" << endl;
}
catch (zxing::Exception& e)
{
qDebug() << e.what() << " (Exception)" << endl;
}
}
//图片解码
void Thread_OpenCV::ZxingPictureQrcode(QString FileName)
{
cv::Mat FileInfo;
FileInfo = cv::imread(FileName.toStdString(),1);
//读取失败则返回
if (!FileInfo.data)
{
qDebug() << "error!!!";
}
ZxingAnalysis(FileInfo); //解析
}
//获取相机及摄像头信息
void Thread_OpenCV::GetCamaraInfo()
{
cv::VideoCapture temp_camera;
int maxTested = 10;
for (int i = 0; i < maxTested; i++)
{
cv::VideoCapture temp_camera(i);
bool res = (!temp_camera.isOpened());
temp_camera.release();
//cv::destroyAllWindows();
if (res)
{
CameraInfo.CamaraCnt = i;
emit this->Sig_Camera_Update(CameraInfo); //摄像头数量更新 用于外部调用 统计显示数量
break;
}
}
}