OpenCv4.4.0+Qt:摄像头控制
简介
在上一篇中讲解了 OpenCv4.4.0+Qt5.12.2+OpenCv-Contrib-4.4.0 的 安装与测试例程,这篇中讲解摄像头的控制,摄像头列表的选择,参数控制,拍照,视频录制。
OpenCv中摄像头的相关的主要有两个模块, VideoCapture / VideoWrite 视频捕捉与视频写入模块。
思路
利用思路利用Qt自带的QCamera相关类以及QLabel,利用OpenCv 的 VideoCapture 和 VideoWriter 负责视频捕捉以及录制。
摄像头选择
利用QCameraInfo 类提供的接口获取摄像头列表,列表ID即为OpenCv摄像头ID号。博主本人测试过两个摄像头,未测试3个以上。获取摄像头列表后与QComBox绑定,来设置选择摄像头。
视频捕捉
利用VideoCapture 打开摄像头,read定时获取当前帧,输出到QLabel显示视频。
参数设置
QCamera与QCameraInfo获取摄像头支持分辨率,帧率,编码格式支持列表,与QComBox绑定,来设置相关参数。
利用get与set获取 清晰度,白平衡,对比度,亮度,色调,增益等相关属性值并进行设置。
拍照
利用QImage将当前帧保存。
录像
利用VideoWrite 将视频帧挨个写入视频文件。
API接口详解
只解释说明关键性接口。
OpenCv
/** @brief Opens a video file or a capturing device or an IP video stream for video capturing.
@overload
Parameters are same as the constructor VideoCapture(const String& filename, int apiPreference = CAP_ANY)
@return `true` if the file has been successfully opened
*/
CV_WRAP virtual bool open(const String& filename, int apiPreference = CAP_ANY);
上述接口,打开一个视频捕捉驱动或者视频流URL串。
/** @brief Opens a camera for video capturing
@overload
Parameters are same as the constructor VideoCapture(int index, int apiPreference = CAP_ANY)
@return `true` if the camera has been successfully opened.
*/
CV_WRAP virtual bool open(int index, int apiPreference = CAP_ANY);
上述接口。打开一个摄像头。其中Index为当摄像头设备接入PC时,底层驱动给做的一个设备排序。笔记本自带摄像头通常为 0,外接设备从1开始排序。通常大家都是使用DirtShow或者修改底层源码。在这里笔者使用了QCameraInfo来获取摄像头ID,笔者为笔记本,外接一个USB摄像头设备,驱动ID是正确的。三个及三个以上手头设备有限未做测试,留待以后。
/** @brief Closes video file or capturing device.
The method is automatically called by subsequent VideoCapture::open and by VideoCapture
destructor.
The C function also deallocates memory and clears \*capture pointer.
*/
CV_WRAP virtual void release();
上述接口,关闭摄像头驱动或者视频文件,也可以清除已使用内存和清除摄像头节点。
/** @brief Grabs, decodes and returns the next video frame.
@param [out] image the video frame is returned here. If no frames has been grabbed the image will be empty.
@return `false` if no frames has been grabbed
The method/function combines VideoCapture::grab() and VideoCapture::retrieve() in one call. This is the
most convenient method for reading video files or capturing data from decode and returns the just
grabbed frame. If no frames has been grabbed (camera has been disconnected, or there are no more
frames in video file), the method returns false and the function returns empty image (with %cv::Mat, test it with Mat::empty()).
@note In @ref videoio_c "C API", functions cvRetrieveFrame() and cv.RetrieveFrame() return image stored inside the video
capturing structure. It is not allowed to modify or release the image! You can copy the frame using
cvCloneImage and then do whatever you want with the copy.
*/
CV_WRAP virtual bool read(OutputArray image);
上述接口,用来读取下一个视频帧。如果视频帧为空则为获取失败或者返回false.
/** @brief Sets a property in the VideoCapture.
@param propId Property identifier from cv::VideoCaptureProperties (eg. cv::CAP_PROP_POS_MSEC, cv::CAP_PROP_POS_FRAMES, ...)
or one from @ref videoio_flags_others
@param value Value of the property.
@return `true` if the property is supported by backend used by the VideoCapture instance.
@note Even if it returns `true` this doesn't ensure that the property
value has been accepted by the capture device. See note in VideoCapture::get()
*/
CV_WRAP virtual bool set(int propId, double value);
上述接口,用来设置摄像头的一个相关属性。
/** @brief Returns the specified VideoCapture property
@param propId Property identifier from cv::VideoCaptureProperties (eg. cv::CAP_PROP_POS_MSEC, cv::CAP_PROP_POS_FRAMES, ...)
or one from @ref videoio_flags_others
@return Value for the specified property. Value 0 is returned when querying a property that is
not supported by the backend used by the VideoCapture instance.
@note Reading / writing properties involves many layers. Some unexpected result might happens
along this chain.
@code{.txt}
VideoCapture -> API Backend -> Operating System -> Device Driver -> Device Hardware
@endcode
The returned value might be different from what really used by the device or it could be encoded
using device dependent rules (eg. steps or percentage). Effective behaviour depends from device
driver and API Backend
*/
CV_WRAP virtual double get(int propId) const;
类比于ser,get使用来获取一个属性的当前的设置值。
/** @brief %VideoCapture generic properties identifier.
Reading / writing properties involves many layers. Some unexpected result might happens along this chain.
Effective behaviour depends from device hardware, driver and API Backend.
@sa videoio_flags_others, VideoCapture::get(), VideoCapture::set()
*/
enum VideoCaptureProperties {
CAP_PROP_POS_MSEC =0, //!< Current position of the video file in milliseconds.
CAP_PROP_POS_FRAMES =1, //!< 0-based index of the frame to be decoded/captured next.
CAP_PROP_POS_AVI_RATIO =2, //!< Relative position of the video file: 0=start of the film, 1=end of the film.
CAP_PROP_FRAME_WIDTH =3, //!< Width of the frames in the video stream.
CAP_PROP_FRAME_HEIGHT =4, //!< Height of the frames in the video stream.
CAP_PROP_FPS =5, //!< Frame rate.
CAP_PROP_FOURCC =6, //!< 4-character code of codec. see VideoWriter::fourcc .
CAP_PROP_FRAME_COUNT =7, //!< Number of frames in the video file.
CAP_PROP_FORMAT =8, //!< Format of the %Mat objects (see Mat::type()) returned by VideoCapture::retrieve().
//!< Set value -1 to fetch undecoded RAW video streams (as Mat 8UC1).
CAP_PROP_MODE =9, //!< Backend-specific value indicating the current capture mode.
CAP_PROP_BRIGHTNESS =10, //!< Brightness of the image (only for those cameras that support).
CAP_PROP_CONTRAST =11, //!< Contrast of the image (only for cameras).
CAP_PROP_SATURATION =12, //!< Saturation of the image (only for cameras).
CAP_PROP_HUE =13, //!< Hue of the image (only for cameras).
CAP_PROP_GAIN =14, //!< Gain of the image (only for those cameras that support).
CAP_PROP_EXPOSURE =15, //!< Exposure (only for those cameras that support).
CAP_PROP_CONVERT_RGB =16, //!< Boolean flags indicating whether images should be converted to RGB. <br/>
//!< *GStreamer note*: The flag is ignored in case if custom pipeline is used. It's user responsibility to interpret pipeline output.
CAP_PROP_WHITE_BALANCE_BLUE_U =17, //!< Currently unsupported.
CAP_PROP_RECTIFICATION =18, //!< Rectification flag for stereo cameras (note: only supported by DC1394 v 2.x backend currently).
CAP_PROP_MONOCHROME =19,
CAP_PROP_SHARPNESS =20,
CAP_PROP_AUTO_EXPOSURE =21, //!< DC1394: exposure control done by camera, user can adjust reference level using this feature.
CAP_PROP_GAMMA =22,
CAP_PROP_TEMPERATURE =23,
CAP_PROP_TRIGGER =24,
CAP_PROP_TRIGGER_DELAY =25,
CAP_PROP_WHITE_BALANCE_RED_V =26,
CAP_PROP_ZOOM =27,
CAP_PROP_FOCUS =28,
CAP_PROP_GUID =29,
CAP_PROP_ISO_SPEED =30,
CAP_PROP_BACKLIGHT =32,
CAP_PROP_PAN =33,
CAP_PROP_TILT =34,
CAP_PROP_ROLL =35,
CAP_PROP_IRIS =36,
CAP_PROP_SETTINGS =37, //!< Pop up video/camera filter dialog (note: only supported by DSHOW backend currently. The property value is ignored)
CAP_PROP_BUFFERSIZE =38,
CAP_PROP_AUTOFOCUS =39,
CAP_PROP_SAR_NUM =40, //!< Sample aspect ratio: num/den (num)
CAP_PROP_SAR_DEN =41, //!< Sample aspect ratio: num/den (den)
CAP_PROP_BACKEND =42, //!< Current backend (enum VideoCaptureAPIs). Read-only property
CAP_PROP_CHANNEL =43, //!< Video input or Channel Number (only for those cameras that support)
CAP_PROP_AUTO_WB =44, //!< enable/ disable auto white-balance
CAP_PROP_WB_TEMPERATURE=45, //!< white-balance color temperature
CAP_PROP_CODEC_PIXEL_FORMAT =46, //!< (read-only) codec's pixel format. 4-character code - see VideoWriter::fourcc . Subset of [AV_PIX_FMT_*](https://github.com/FFmpeg/FFmpeg/blob/master/libavcodec/raw.c) or -1 if unknown
CAP_PROP_BITRATE =47, //!< (read-only) Video bitrate in kbits/s
#ifndef CV_DOXYGEN
CV__CAP_PROP_LATEST
#endif
};
VideoCapture枚举属性列表。
/** @brief Initializes or reinitializes video writer.
The method opens video writer. Parameters are the same as in the constructor
VideoWriter::VideoWriter.
@return `true` if video writer has been successfully initialized
The method first calls VideoWriter::release to close the already opened file.
*/
CV_WRAP virtual bool open(const String& filename, int fourcc, double fps,
Size frameSize, bool isColor = true);
/** @overload
*/
CV_WRAP bool open(const String& filename, int apiPreference, int fourcc, double fps,
Size frameSize, bool isColor = true);
/** @overload
*/
CV_WRAP bool open(const String& filename, int fourcc, double fps, const Size& frameSize,
const std::vector<int>& params);
/** @overload
*/
CV_WRAP bool open(const String& filename, int apiPreference, int fourcc, double fps,
const Size& frameSize, const std::vector<int>& params);
设置视频保存属性-名称-帧率-编码-分辨率
/** @brief Concatenates 4 chars to a fourcc code
@return a fourcc code
This static method constructs the fourcc code of the codec to be used in the constructor
VideoWriter::VideoWriter or VideoWriter::open.
*/
CV_WRAP static int fourcc(char c1, char c2, char c3, char c4);
// FIXIT OpenCV 4.0: make inline
int VideoWriter::fourcc(char c1, char c2, char c3, char c4)
{
return (c1 & 255) + ((c2 & 255) << 8) + ((c3 & 255) << 16) + ((c4 & 255) << 24);
}
获取视频编码格式对应的枚举ID值
//! Macro to construct the fourcc code of the codec. Same as CV_FOURCC()
#define CV_FOURCC_MACRO(c1, c2, c3, c4) (((c1) & 255) + (((c2) & 255) << 8) + (((c3) & 255) << 16) + (((c4) & 255) << 24))
/** @brief Constructs the fourcc code of the codec function
Simply call it with 4 chars fourcc code like `CV_FOURCC('I', 'Y', 'U', 'V')`
List of codes can be obtained at [Video Codecs by FOURCC](http://www.fourcc.org/codecs.php) page.
FFMPEG backend with MP4 container natively uses other values as fourcc code:
see [ObjectType](http://mp4ra.org/#/codecs).
*/
CV_INLINE int CV_FOURCC(char c1, char c2, char c3, char c4)
{
return CV_FOURCC_MACRO(c1, c2, c3, c4);
}
//! (Windows only) Open Codec Selection Dialog
#define CV_FOURCC_PROMPT -1
//! (Linux only) Use default codec for specified filename
#define CV_FOURCC_DEFAULT CV_FOURCC('I', 'Y', 'U', 'V')
查看源代码**fourcc(char c1, char c2, char c3, char c4)**与 **CV_FOURCC(char c1, char c2, char c3, char c4)**相同,支持通用,建议还是不要设置为 -1,仅支持Windows,还是采用 返回值形式来设置编码格式。 例如:int fourcc = cv::VideoWriter::fourcc(‘M’, ‘J’, ‘P’, ‘G’)
Qt
QCameraInfo::availableCameras():返回位于本地所有有效的摄像头列表
[static] QList<QCameraInfo> QCameraInfo::availableCameras(QCamera::Position position = QCamera::UnspecifiedPosition)
Returns a list of available cameras on the system which are located at position.
If position is not specified or if the value is QCamera::UnspecifiedPosition, a list of all available cameras will be returned.
QList supportedViewfinderResolutions(const QCameraViewfinderSettings &settings = QCameraViewfinderSettings()) :返回摄像头支持分辨率列表。
QList<QSize> QCamera::supportedViewfinderResolutions(const QCameraViewfinderSettings &settings = QCameraViewfinderSettings()) const
Returns a list of supported viewfinder resolutions.
This is a convenience function which retrieves unique resolutions from the supported settings.
If non null viewfinder settings are passed, the returned list is reduced to resolutions supported with partial settings applied.
The camera must be loaded before calling this function, otherwise the returned list is empty.
QList supportedViewfinderFrameRateRanges(const QCameraViewfinderSettings &settings = QCameraViewfinderSettings()) :返回摄像头支持的帧率范围。
QList<QCamera::FrameRateRange> QCamera::supportedViewfinderFrameRateRanges(const QCameraViewfinderSettings &settings = QCameraViewfinderSettings()) const
Returns a list of supported viewfinder frame rate ranges.
This is a convenience function which retrieves unique frame rate ranges from the supported settings.
If non null viewfinder settings are passed, the returned list is reduced to frame rate ranges supported with partial settings applied.
The camera must be loaded before calling this function, otherwise the returned list is empty.
QList< QVideoFrame::PixelFormat> supportedViewfinderPixelFormats(const QCameraViewfinderSettings &settings = QCameraViewfinderSettings()):返回摄像头支持格式。
QList<QVideoFrame::PixelFormat> QCamera::supportedViewfinderPixelFormats(const QCameraViewfinderSettings &settings = QCameraViewfinderSettings()) const
Returns a list of supported viewfinder pixel formats.
This is a convenience function which retrieves unique pixel formats from the supported settings.
If non null viewfinder settings are passed, the returned list is reduced to pixel formats supported with partial settings applied.
The camera must be loaded before calling this function, otherwise the returned list is empty.
源码详解
摄像头列表
获取摄像头列表
void MainWindow::GetCameraList()
{
formatmeta = QMetaEnum::fromType<PixelFormat>();
cameras = QCameraInfo::availableCameras();
foreach(const QCameraInfo &cameraInfo, cameras)
{
ui->comboBox_name->addItem(cameraInfo.description());
GetCameraInfo(cameraInfo);
COUT << cameraInfo.description() <<cameraInfo.deviceName() << cameraInfo.orientation();
}
}
选择摄像头
connect(ui->comboBox_name,SIGNAL(activated(int)),this,SLOT(slot_SetIndexCaptureCamera(int))); //信号槽连接
void MainWindow::slot_SetIndexCaptureCamera(int index) //摄像头选择
{
if(cap.isOpened())
{
timer.stop();
cap.release();
}
cap.open(index,cv::CAP_DSHOW);
if(!cap.isOpened())
{
COUT << cameras.at(index).description() << "打开失败";
return;
}
SetComboxValue(index); //默认值显示
timer.start(20); //定时器启动
}
帧读取
void MainWindow::slot_CaptureImage()
{
cv::Mat frame,image;
cap.read(frame);
if(frame.empty())
return;
emit signal_MatImage(frame);
}
connect(&timer,&QTimer::timeout,this,&MainWindow::slot_CaptureImage); //定时器信号槽绑定
帧显示
connect(this,&MainWindow::signal_MatImage,this,&MainWindow::slot_LabelShowImg);
void MainWindow::slot_LabelShowImg(cv::Mat image)
{
cv::Mat out_image;
cv::cvtColor(image,out_image,cv::COLOR_BGR2RGB); //转为Qt显示RGB值
QImage qImg = QImage((const unsigned char*)(out_image.data),out_image.cols,out_image.rows,out_image.step,QImage::Format_RGB888); //转为QImage
ui->label_video->setPixmap(QPixmap::fromImage(qImg.mirrored(true,false)));
ui->label_video->resize(qImg.size());
ui->label_video->show();
//拍照相关设置
if(isSaveImage){
QString image_name = QString("%1.png").arg(QDateTime::currentDateTime().toString("yyyy-MM-dd_HH-mm-ss"));
if(qImg.save(image_name))
{
COUT << "拍照成功!" << image_name;
isSaveImage = false;
}
else {
COUT << "保存图片失败!" << image_name;
}
}
}
Qt支持相关属性列表
void MainWindow::GetCameraInfo(QCameraInfo info)
{
QCamera * camera = new QCamera(info);
camera->start();
GetCameraResolution(camera);
GetCameraFormat(camera);
GetCameraFrameRate(camera);
camera->stop();
delete camera;
camera = nullptr;
}
分辨率列表
void MainWindow::GetCameraResolution(QCamera *camera)
{
QStringList resolutions;
QList<QSize> resSize = camera->supportedViewfinderResolutions();
for(auto it : resSize)
{
resolutions.push_back(QString("%1X%2").arg(it.width()).arg(it.height()));
COUT << QString("%1X%2").arg(it.width()).arg(it.height());
}
camerasresolution.push_back(resolutions);
}
帧编码格式列表
void MainWindow::GetCameraFormat(QCamera *camera)
{
QStringList formats;
QList<QVideoFrame::PixelFormat> formatlist = camera->supportedViewfinderPixelFormats();
for(auto it : formatlist)
{
COUT << formatmeta.valueToKey(it) ;
formats.push_back(formatmeta.valueToKey(it));
}
camerasformat.push_back(formats);
}
帧率列表
void MainWindow::GetCameraFrameRate(QCamera *camera)
{
QStringList frames;
QList<QCamera::FrameRateRange> framerate = camera->supportedViewfinderFrameRateRanges();
for(auto it : framerate)
{
frames.push_back(QString("%1").arg(it.minimumFrameRate));
}
camerasframerate.push_back(frames);
}
参数设置
参数初始化设置
void MainWindow::SetComboxValue(int index)
{
ui->comboBox_resolution->clear();
ui->comboBox_resolution->addItems(camerasresolution.at(index));
QString resolution = QString("%1X%2").arg(cap.get(cv::CAP_PROP_FRAME_WIDTH)).arg(cap.get(cv::CAP_PROP_FRAME_HEIGHT));
ui->comboBox_resolution->setCurrentIndex(ui->comboBox_resolution->findText(resolution));
COUT << "resolution:" <<resolution;
ui->comboBox_format->clear();
ui->comboBox_format->addItems(camerasformat.at(index));
QString format = QString("%1").arg(cap.get(cv::CAP_PROP_FORMAT));
COUT << "format:" << format;
ui->comboBox_framerate->clear();
ui->comboBox_framerate->addItems(camerasframerate.at(index));
QString framerate = QString("%1").arg(cap.get(cv::CAP_PROP_FPS));
ui->comboBox_framerate->setCurrentIndex(ui->comboBox_framerate->findText(framerate));
COUT << "framerate:" << framerate;
QString pixelformat = QString("%1").arg(cap.get(cv::CAP_PROP_CODEC_PIXEL_FORMAT));
COUT << "pixelformat:" << pixelformat;
QString gain = QString("%1").arg(cap.get(cv::CAP_PROP_GAIN));
COUT << "gain:" << gain;
ui->spinBox_brightness->setValue(DoubleToInt(cap.get(cv::CAP_PROP_BRIGHTNESS))); //显示默认亮度
ui->spinBox_contrast->setValue(DoubleToInt(cap.get(cv::CAP_PROP_CONTRAST))); //显示默认对比度
ui->spinBox_exposure->setValue(DoubleToInt(cap.get(cv::CAP_PROP_EXPOSURE))); //显示默认曝光
ui->spinBox_hue->setValue(DoubleToInt(cap.get(cv::CAP_PROP_HUE))); //显示默认色调
ui->spinBox_saturation->setValue(DoubleToInt(cap.get(cv::CAP_PROP_SATURATION))); //显示默认饱和度
ui->spinBox_wb->setValue(DoubleToInt(cap.get(cv::CAP_PROP_WHITE_BALANCE_BLUE_U))); //显示默认白平衡
ui->spinBox_gain->setValue(DoubleToInt(cap.get(cv::CAP_PROP_GAIN))); //显示自动增益
ui->checkBox_autoexposure->setCheckState((cap.get(cv::CAP_PROP_AUTO_EXPOSURE))?Qt::CheckState::Checked:Qt::CheckState::Unchecked); //是否自动曝光
ui->checkBox_autowb->setCheckState((cap.get(cv::CAP_PROP_AUTO_WB))?Qt::CheckState::Checked:Qt::CheckState::Unchecked);
} //是否自动白平衡
参数设置相关信号槽绑定
connect(ui->comboBox_resolution,SIGNAL(activated(int)),this,SLOT(slot_SetIndexCameraResolution(int)));//分辨率
connect(ui->comboBox_framerate,SIGNAL(activated(int)),this,SLOT(slot_SetIndexCameraFrameRate(int)));//帧率
connect(ui->spinBox_brightness,SIGNAL(valueChanged(int)),this,SLOT(slot_SetCameraBrightness(int)));//亮度
connect(ui->spinBox_contrast,SIGNAL(valueChanged(int)),this,SLOT(slot_SetCameraContrast(int)));//对比度
connect(ui->spinBox_exposure,SIGNAL(valueChanged(int)),this,SLOT(slot_SetCameraExposure(int)));//曝光
connect(ui->spinBox_hue,SIGNAL(valueChanged(int)),this,SLOT(slot_SetCameraHue(int)));//色调
connect(ui->spinBox_saturation,SIGNAL(valueChanged(int)),this,SLOT(slot_SetCameraSaturation(int)));//饱和度
connect(ui->spinBox_gain,SIGNAL(valueChanged(int)),this,SLOT(slot_SetCameraGain(int)));//增益
connect(ui->spinBox_wb,SIGNAL(valueChanged(int)),this,SLOT(slot_SetCameraWhilteBalance(int)));//白平衡
connect(ui->checkBox_autoexposure,&QCheckBox::stateChanged,this,&MainWindow::slot_SetCameraAutoExposure);//自动曝光
connect(ui->checkBox_autowb,&QCheckBox::stateChanged,this,&MainWindow::slot_SetCameraAutoWb);//自动白平衡
connect(ui->pushButton_setting,&QPushButton::clicked,this,&MainWindow::slot_SetCameraPram);//OpenCv自带参数设置
分辨率
void MainWindow::slot_SetIndexCameraResolution(int index)
{
if(!cap.isOpened())
{
COUT << "摄像头设备未打开!";
return;
}
QString resolution = ui->comboBox_resolution->itemText(index);
double width = resolution.split("X").at(0).toDouble();
double height = resolution.split("X").at(1).toDouble();
COUT << cap.get(cv::CAP_PROP_FRAME_WIDTH) << cap.get(cv::CAP_PROP_FRAME_HEIGHT);
cap.set(cv::CAP_PROP_FRAME_WIDTH,width);
cap.set(cv::CAP_PROP_FRAME_HEIGHT,height);
}
帧率
void MainWindow::slot_SetIndexCameraFrameRate(int index)
{
if(!cap.isOpened())
{
COUT << "摄像头设备未打开!";
return;
}
QString framerate = ui->comboBox_framerate->itemText(index);
cap.set(cv::CAP_PROP_FPS,framerate.toDouble());
}
亮度
void MainWindow::slot_SetCameraBrightness(int value)
{
if(!cap.isOpened())
{
COUT << "摄像头设备未打开!";
return;
}
cap.set(cv::CAP_PROP_BRIGHTNESS,value);
}
饱和度
void MainWindow::slot_SetCameraSaturation(int value)
{
if(!cap.isOpened())
{
COUT << "摄像头设备未打开!";
return;
}
cap.set(cv::CAP_PROP_SATURATION,value);
}
色调
void MainWindow::slot_SetCameraHue(int value)
{
if(!cap.isOpened())
{
COUT << "摄像头设备未打开!";
return;
}
cap.set(cv::CAP_PROP_HUE,value);
}
曝光
void MainWindow::slot_SetCameraExposure(int value)
{
if(!cap.isOpened())
{
COUT << "摄像头设备未打开!";
return;
}
cap.set(cv::CAP_PROP_EXPOSURE,value);
COUT << "CAP_PROP_EXPOSURE:" << QString("%1").arg(cap.get(cv::CAP_PROP_EXPOSURE));
}
对比度
void MainWindow::slot_SetCameraContrast(int value)
{
if(!cap.isOpened())
{
COUT << "摄像头设备未打开!";
return;
}
cap.set(cv::CAP_PROP_CONTRAST,value);
}
增益
void MainWindow::slot_SetCameraGain(int value)
{
if(!cap.isOpened())
{
COUT << "摄像头设备未打开!";
return;
}
cap.set(cv::CAP_PROP_GAIN,value);
}
白平衡
void MainWindow::slot_SetCameraWhilteBalance(int value)
{
if(!cap.isOpened())
{
COUT << "摄像头设备未打开!";
return;
}
cap.set(cv::CAP_PROP_WHITE_BALANCE_BLUE_U,value);
}
自动白平衡
void MainWindow::slot_SetCameraAutoWb(int status)
{
if(!cap.isOpened())
{
COUT << "摄像头设备未打开!";
return;
}
cap.set(cv::CAP_PROP_AUTO_WB,(status == Qt::CheckState::Checked) ? -1 : cap.get(cv::CAP_PROP_EXPOSURE));
ui->spinBox_wb->setDisabled(status);
}
自动曝光
void MainWindow::slot_SetCameraAutoExposure(int status)
{
COUT << "设置自动曝光" << status;
if(!cap.isOpened())
{
COUT << "摄像头设备未打开!";
return;
}
if(status == Qt::CheckState::Checked)
{
cap.set(cv::CAP_PROP_AUTO_EXPOSURE,0);
cv::VideoCaptureProperties();
}
else
{
cap.set(cv::CAP_PROP_AUTO_EXPOSURE,1);
cap.set(cv::CAP_PROP_EXPOSURE,cap.get(cv::CAP_PROP_EXPOSURE));
}
ui->spinBox_exposure->setDisabled(status);
COUT << "自动曝光:" << cap.get(cv::CAP_PROP_AUTO_EXPOSURE);
COUT << "曝光:" << cap.get(cv::CAP_PROP_EXPOSURE);
}
设置参数属性-OpenCv
void MainWindow::slot_SetCameraPram()
{
COUT << "设置摄像头参数";
if(!cap.isOpened())
{
COUT << "摄像头设备未打开!";
return;
}
cap.set(cv::CAP_PROP_SETTINGS, 1);
COUT << "自动曝光:" << cap.get(cv::CAP_PROP_AUTO_EXPOSURE);
COUT << "曝光:" << cap.get(cv::CAP_PROP_EXPOSURE);
COUT << "自动白平衡:" << cap.get(cv::CAP_PROP_AUTO_WB);
COUT << "白平衡:" << cap.get(cv::CAP_PROP_WHITE_BALANCE_BLUE_U);
}
拍照
思路,按下拍照按钮时,将保存标志位置为True,将下一帧转为QImage类型,保存下一帧。
connect(ui->pushButton_photo,&QPushButton::clicked,this,&MainWindow::slot_Photograph);
void MainWindow::slot_Photograph()
{
if(!cap.isOpened())
{
COUT << "摄像头设备未打开!";
return;
}
isSaveImage = true; //当标志位为True时,启动保存当前帧
}
视频录制
connect(ui->pushButton_recordvideo,&QPushButton::clicked,this,&MainWindow::slot_RecordVideo);
connect(this,&MainWindow::signal_MatImage,this,&MainWindow::slot_SaveVideo);
void MainWindow::slot_RecordVideo()
{
if(!cap.isOpened())
{
COUT << "摄像头设备未打开!";
return;
}
if(!videorecord.isOpened() && isRecordVideo == false)
{
QString resolution = ui->comboBox_resolution->currentText();
int width = resolution.split("X").at(0).toInt();
int height = resolution.split("X").at(1).toInt();
COUT << "video size:" << width << " " << height;
cv::Size _size = cv::Size(width,height);
QString video_name = QString("%1.mp4").arg(QDateTime::currentDateTime().toString("yyyy-MM-dd_HH-mm-ss"));
videorecord.open(video_name.toStdString(),cv::VideoWriter::fourcc('M', 'J', 'P', 'G'),30,_size,true);//设置保存属性-编码-名字-分辨率
if(videorecord.isOpened())
{
isRecordVideo = true;
COUT << "开始视频录制";
ui->pushButton_recordvideo->setText("结束录制");
}
}
else if(videorecord.isOpened() && isRecordVideo)
{
ui->pushButton_recordvideo->setText("视频录制");
videorecord.release();
isRecordVideo = false;
COUT << "视频录制完成";
}
}
void MainWindow::slot_SaveVideo(cv::Mat image) //写入帧文件
{
if(isRecordVideo)
{
videorecord.write(image);
}
}
头文件
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QCamera>
#include <QCameraInfo>
#include <opencv2/opencv.hpp>
#include <QList>
#include <QTimer>
#include <QMetaEnum>
#include <QDebug>
#define COUT qDebug()<< __TIME__ << __FUNCTION__ << __LINE__ << " : " //日志输出,方便自己调试做的设置
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
enum PixelFormat
{
Format_Invalid,
Format_ARGB32,
Format_ARGB32_Premultiplied,
Format_RGB32,
Format_RGB24,
Format_RGB565,
Format_RGB555,
Format_ARGB8565_Premultiplied,
Format_BGRA32,
Format_BGRA32_Premultiplied,
Format_BGR32,
Format_BGR24,
Format_BGR565,
Format_BGR555,
Format_BGRA5658_Premultiplied,
Format_AYUV444,
Format_AYUV444_Premultiplied,
Format_YUV444,
Format_YUV420P,
Format_YV12,
Format_UYVY,
Format_YUYV,
Format_NV12,
Format_NV21,
Format_IMC1,
Format_IMC2,
Format_IMC3,
Format_IMC4,
Format_Y8,
Format_Y16,
Format_Jpeg,
Format_CameraRaw,
Format_AdobeDng,
};
Q_ENUM(PixelFormat)
private:
Ui::MainWindow *ui;
QList<QCameraInfo> cameras;
QList<QStringList> camerasresolution;
QList<QStringList> camerasformat;
QList<QStringList> camerasframerate;
QTimer timer;
QMetaEnum formatmeta;
cv::VideoCapture cap;
cv::VideoWriter videorecord;
bool isSaveImage;
bool isRecordVideo;
void CamerasInit();
void GetCameraList();
void GetCameraInfo(QCameraInfo info);
void GetCameraResolution(QCamera *camera);
void GetCameraFormat(QCamera *camera);
void GetCameraFrameRate(QCamera *camera);
void SetComboxValue(int index);
public slots:
void slot_SetIndexCaptureCamera(int index);
void slot_CaptureImage();
void slot_LabelShowImg(cv::Mat image);
void slot_SetIndexCameraResolution(int index);
void slot_SetIndexCameraFrameRate(int index);
void slot_SetCameraBrightness(int value);
void slot_SetCameraSaturation(int value);
void slot_SetCameraHue(int value);
void slot_SetCameraExposure(int value);
void slot_SetCameraContrast(int value);
void slot_SetCameraGain(int value);
void slot_SetCameraWhilteBalance(int value);
void slot_SetCameraAutoWb(int status);
void slot_SetCameraAutoExposure(int status);
void slot_SetCameraPram();
void slot_Photograph();
void slot_RecordVideo();
void slot_SaveVideo(cv::Mat image);
signals:
void signal_MatImage(cv::Mat);
};
#endif // MAINWINDOW_H
运行结果
UI界面
有点乱不想放图片的-----
运行界面
运行结果
源码
问题
OpenCv设置自动曝光是,取消自动曝光设置是成功的,但是设置为自动曝光没有生效。UI界面的自适应没有做很好,但是不想浪费精力还有代码的优化,还可以优化很多,但是都是工作量了,不做进一步改进。目前这个代码结构,基本的设置或者工程应用应该是足够的,更加复杂的场景,暂时没有涉及到也不做相关建议了。
UI自适应思路:根据Label大小,将窗口resize,来实现自动缩放。
代码优化:定时器时间设置:这一块不够严谨,应该时间设置为,1000/rate ,笔者设置为了固定值,20ms,相当于50帧,在时序比较严谨的场景中,会导致帧率错位或者帧时间不匹配的问题。还有视频录制相关。相关代码和分辨率设置差不多,也不做添加了。
自动曝光设置:准备查看源码,但是第一遍搜索的时候,没有找到相关,如果有建议,欢迎留言。
设置参数:摄像头没有打开时,所有设置参数属性控件都是可以点击的,可以默认为disable,在打开摄像头在设置为enable。在每次进行摄像头参数设置时,都有一个摄像头是否打开判断,其实没有必要,在外边随定时器进行判断就好,不好的点是浪费了性能,但是这样设置保证安全,但是代码有些冗余看个人选择了。
有其他问题,欢迎探讨。
下一章节
OpenCv 文字识别或者大家有什么建议吗?学习方向还是没整理好。
更新
2021.04.29
代码放在github了,之前没有想着放在git上边,就当自己随手写的一个小Demo,有点不规范。以后所有代码都会放在github上边。尽量会做到规范,