目录
1、结果展示
简单的拍照录像摄像头功能开发,实现了照片和录像水印功能和显示时间戳,以及照片和录像可以保存到本地文件夹,可以使用外界摄像头,这里我使用的是笔记本自带的摄像头。
拍照和录像后可以保存在指定目录文件夹中,并且可以查看图片和视频。
2、界面设计
主要构成很简单,一个Qlabel,三个按钮,注意命名。
Qlabel界面:capArea_lb
开始按钮:capture_bt
拍照:takephoto_bt
录制:takevideo_bt
3、代码展示
pro文件依赖:
#-------------------------------------------------
#
# Project created by QtCreator 2024-07-11T18:43:25
#
#-------------------------------------------------
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = camCapture
TEMPLATE = app
SOURCES += main.cpp\
menu.cpp
HEADERS += menu.h
FORMS += menu.ui
INCLUDEPATH += /usr/local/include
LIBS += -L/usr/local/lib/libopencv_highgui.so \
/usr/local/lib/libopencv_core.so \
/usr/local/lib/libopencv_imgproc.so \
/usr/local/lib/libopencv_imgcodecs.so \
/usr/local/lib/libopencv_face.so \
/usr/local/lib/libopencv_objdetect.so \
/usr/local/lib/libopencv_videoio.so
DISTFILES +=
RESOURCES += \
qimage.qrc
menu.h
#ifndef MENU_H
#define MENU_H
#include <QWidget>
#include<QTimer>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/core/core.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/objdetect.hpp>
#include<opencv2/videoio.hpp>
#include<opencv2/face.hpp>
#include <QElapsedTimer>
using namespace std;
using namespace cv;
namespace Ui {
class menu;
}
class menu : public QWidget
{
Q_OBJECT
public:
explicit menu(QWidget *parent = 0);
// 声明 QImageToCvMat 函数
cv::Mat QImageToCvMat(const QImage &image);
~menu();
private slots:
void CaptureOpen();
void on_capture_bt_clicked();
void on_takephoto_bt_clicked();
void on_takevideo_bt_clicked();
private:
Ui::menu *ui;
QTimer * capTimer;
VideoCapture cap;
Mat frame;
bool recording; // 新增:跟踪是否正在录制
VideoWriter videoWriter; // 新增:用于视频保存
QElapsedTimer elapsedTimer; // 添加QElapsedTimer
Mat watermark;
void addWatermark(Mat &frame, const Mat &watermark);
};
#endif // MENU_H
menu.cpp
#include "menu.h"
#include "ui_menu.h"
#include<QDateTime>
#include<QDebug>
menu::menu(QWidget *parent) :
QWidget(parent),
ui(new Ui::menu),
recording(false) // 初始化为未录制状态
{
ui->setupUi(this);
capTimer = new QTimer(this);
connect(capTimer,SIGNAL(timeout()),this,SLOT(CaptureOpen()));
cap.open(0);
// 加载水印图片
watermark = imread("/opt/aicTrain/camCapture/button/start.png", IMREAD_UNCHANGED);
if (watermark.empty()) {
qDebug() << "水印图片加载失败";
}
else
{
// 调整水印图片大小
int newWidth = 50; // 设置新的宽度
int newHeight = 50; // 设置新的高度
cv::resize(watermark, watermark, cv::Size(newWidth, newHeight));
}
}
menu::~menu()
{
delete ui;
}
void menu::CaptureOpen()
{
cap >> frame;
if (!watermark.empty())
{
addWatermark(frame, watermark);
}
Mat frame1;
cvtColor(frame,frame1,CV_BGR2RGB);
// 添加水印到实时显示的帧
// 如果正在录制,获取经过的时间并在帧上绘制时间戳
if (recording)
{
qint64 elapsedTime = elapsedTimer.elapsed(); // 获取经过的时间,单位为毫秒
int seconds = (elapsedTime / 1000) % 60;
int minutes = (elapsedTime / (1000 * 60)) % 60;
int hours = (elapsedTime / (1000 * 60 * 60)) % 24;
QString timeString = QString("%1:%2:%3")
.arg(hours, 2, 10, QChar('0'))
.arg(minutes, 2, 10, QChar('0'))
.arg(seconds, 2, 10, QChar('0'));
std::string timeText = timeString.toStdString();
// 在显示的帧上绘制时间戳
cv::putText(frame1, timeText, cv::Point(frame1.cols - 150, 30), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(255, 255, 255), 2);
}
// 右上角时间水印,获取当前日期和时间
QString currentDateTime = QDateTime::currentDateTime().toString("yyyy-MM-dd HH:mm:ss");
std::string dateTimeText = currentDateTime.toStdString();
// 在帧的左上角绘制当前日期和时间
cv::putText(frame1, dateTimeText, cv::Point(10, 30), cv::FONT_HERSHEY_SIMPLEX, 0.8, cv::Scalar(255, 255, 255), 2);
// 文件水印
cv::putText(frame, dateTimeText, cv::Point(10, 30), cv::FONT_HERSHEY_SIMPLEX, 0.8, cv::Scalar(255, 255, 255), 2);
QImage Qimage1 = QImage((const unsigned char *)(frame1.data),
frame1.cols,frame1.rows,
frame1.step,QImage::Format_RGB888);
ui->capArea_lb->setPixmap(QPixmap::fromImage(Qimage1));
ui->capArea_lb->resize(Qimage1.size());
ui->capArea_lb->show();
// 如果正在录制,将帧写入视频文件
if (recording && videoWriter.isOpened())
{
videoWriter.write(frame);
}
}
void menu::on_capture_bt_clicked()
{
ui->capture_bt->setText("捕获中");
capTimer->start(30);
}
void menu::on_takephoto_bt_clicked()
{
if (!frame.empty())
{
// 将当前帧转换为适合保存的格式
Mat frameBGR;
cvtColor(frame, frameBGR, CV_RGB2BGR);
// 获取当前时间戳作为文件名
QString timestamp = QDateTime::currentDateTime().toString("yyyyMMdd_HHmmss");
QString filePath = QCoreApplication::applicationDirPath() + "/" + timestamp + ".jpg";
// 将 Mat 对象转换为 QImage
QImage Qimage1 = QImage((const unsigned char *)(frameBGR.data),
frameBGR.cols, frameBGR.rows,
frameBGR.step, QImage::Format_RGB888);
// 保存图像到文件
if (Qimage1.save(filePath))
{
qDebug() << "照片保存成功:" << filePath;
}
else
{
qDebug() << "照片保存失败";
}
}
}
void menu::on_takevideo_bt_clicked()
{
if (recording)
{
// 停止录制
recording = false;
videoWriter.release();
ui->takevideo_bt->setText("开始录制");
qDebug() << "视频录制已停止";
}
else
{
// 开始录制
QString timestamp = QDateTime::currentDateTime().toString("yyyyMMdd_HHmmss");
QString filePath = QCoreApplication::applicationDirPath() + "/" + timestamp + ".avi";
int codec = VideoWriter::fourcc('M', 'J', 'P', 'G'); // 选择合适的编码器
double fps = 15.0; // 帧率
Size frameSize(frame.cols, frame.rows);
videoWriter.open(filePath.toStdString(), codec, fps, frameSize, true);
if (videoWriter.isOpened())
{
recording = true;
elapsedTimer.start(); // 启动计时器
ui->takevideo_bt->setText("停止录制");
qDebug() << "视频录制已开始,保存路径:" << filePath;
}
else
{
qDebug() << "无法打开视频文件进行录制";
}
}
}
void menu::addWatermark(Mat &frame, const Mat &watermark)
{
// 确保水印图片尺寸小于视频帧
int wmRows = watermark.rows;
int wmCols = watermark.cols;
// 获取水印图像ROI区域
Mat roi = frame(Rect(frame.cols - wmCols - 10, frame.rows - wmRows - 10, wmCols, wmRows));
// 将水印图像叠加到ROI上
for (int r = 0; r < wmRows; ++r)
{
for (int c = 0; c < wmCols; ++c)
{
Vec4b wmPixel = watermark.at<Vec4b>(r, c);
if (wmPixel[3] > 0) // 仅在水印像素不透明时进行叠加
{
Vec3b &roiPixel = roi.at<Vec3b>(r, c);
roiPixel[0] = wmPixel[0];
roiPixel[1] = wmPixel[1];
roiPixel[2] = wmPixel[2];
}
}
}
}
main.cpp
#include "menu.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
menu w;
w.show();
return a.exec();
}
如果你觉得这篇文章有用,请点赞收藏!后续会有一些拓展功能发出!