该demo项目包含的知识:菜单栏设置,菜单栏图标设置,菜单栏打开新窗口(界面打开新窗口可以借鉴),以及将新窗口设置成表格,label各种设置,button各种设置,几种信号槽连接,打开图片,显示图片,状态栏,opencv图片转换(mat-Qimage),打开相机,以及处理图片的几种函数(灰度图,二值化,高斯滤波,边缘检测,像素输出)
可以将代码复制编译后在慢慢看。
interface_vs.h:
#pragma once
#include <QtWidgets/QMainWindow>
#include "ui_interface_vs.h"
#include <QMenuBar>
#include <QLabel>
#include <QPushButton>
#include <QSlider>
#include<opencv2/opencv.hpp>
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/videoio/videoio.hpp"
#include <QWidget>
#include "newWindowClass.h"
using namespace cv;
using namespace std;
#pragma once
#pragma execution_character_set("utf-8")
class interface_vs : public QMainWindow
{
Q_OBJECT
public:
interface_vs(QWidget *parent = nullptr);
~interface_vs();
//菜单栏
QMenuBar *pMenuBar;
//菜单项
QMenu *pMenuTest;
QMenu *pMenuTest1;
QMenu *pMenuTest2;
//子菜单
QAction *pActionTest;
QAction *pActionTest1;
QAction *pActionTest2;
QAction *pActionTest3;
QAction *pActionTest4;
QAction *pActionTest5;
QAction *pActionTest6;
QLabel *label;
QLabel *label1;
QLabel *label2;
QLabel *label3;
QPushButton * pButton;
QPushButton * pButton1;
QPushButton * pButton2;
QSlider *slider;
QPushButton * pButton3;
QPushButton * pButton4;
QPushButton * pButton5;
QPushButton * pButton6;
QPushButton * pButton7;
QPushButton *btn_language;
public slots:
//菜单响应函数
void OnActionTest();
void OnActionTest1();
void ClickButton();
void ClickButton1();
void ClickButton2();
void SliderChangeImageshow(int a);
void OpenCamera();
void print_px_value(Mat& im);
void ShowPoint();
void New_algorithm();
void cvt();
void vi();
void newWindow();
private:
newWindowClass * nw;
Ui::interface_vsClass ui;
};
interface_vs.cpp:
#include "interface_vs.h"
#include "opencv2/opencv.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/videoio/videoio.hpp"
#include <QDialog>
#include <QFileDialog>
#include <QDebug>
#include <QMessageBox>
#include <qvector.h>
#include <QHeaderView>
QString image_address;
Mat After_processing;//处理后的图片
interface_vs::interface_vs(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
//指定菜单栏
#ifdef USE_DEFAULT_MENU_BAR
//添加菜单栏(此处添加为的为QMainWindow自带的菜单)
pMenuBar = this->menuBar();
#else
//添加自定义菜单
pMenuBar = new QMenuBar(this);
#endif
//定义菜单项
//(&n)代表快捷方式,当窗口获得焦点时按alt+n即可打开“菜单”菜单项
pMenuTest = new QMenu("菜单", this);
pMenuTest1 = new QMenu("test1",this);
pMenuTest2 = new QMenu("test2",this);
//定义子菜单
//(&s)为子菜单快捷键,当打开该菜单项后,按下‘s’键即可响应
pActionTest = new QAction("打开新窗口", this);
//新建一个带图标的菜单项,图标使用资源文件中的资源
pActionTest1 = new QAction(QIcon("C:\\Users\\25125\\Desktop\\1.jpg"), "打开图片", this);
//pActionTest2 = new QAction("测试2",this);
pActionTest3 = new QAction("exit", this);
pActionTest4 = new QAction("测试", this);
pActionTest5 = new QAction("测试", this);
pActionTest6 = new QAction("测试", this);
//将菜单项添加到子菜单
pMenuTest->addAction(pActionTest);
pMenuTest->addAction(pActionTest1);
//在菜单项之间添加分割线
pMenuTest->addSeparator();
//pMenuTest->addAction(pActionTest2);
pMenuTest->addAction(pActionTest3);
pMenuTest1->addAction(pActionTest4);
pMenuTest2->addAction(pActionTest5);
pMenuTest2->addAction(pActionTest6);
//将子菜单添加到菜单栏
pMenuBar->addMenu(pMenuTest);
pMenuBar->addMenu(pMenuTest1);
pMenuBar->addMenu(pMenuTest2);
this->setMaximumSize(1600, 1200);
this->setMinimumSize(1200, 1000);
this->setWindowTitle("菜单项");
QToolBar *toolbar = new QToolBar(this);
addToolBar(Qt::TopToolBarArea, toolbar);
toolbar->addAction("新建");
toolbar->addSeparator();
toolbar->addAction("打开");
toolbar->addSeparator();
toolbar->addAction("关闭");
//显示图片label
label = new QLabel(this);
label->move(5, 100); //将标签移动到(0,100)位置
label->resize(200, 160); //设定标签大小
label->setStyleSheet("border:1px solid black");
//显示文字label
label1 = new QLabel(this);
label1->setText(tr("显示图片")); //文本label
label1->move(50, 280);
//setCentralWidget(label); label居中
//显示处理后图片的label
label2 = new QLabel(this); //处理后label显示
label2->move(500, 100);
label2->resize(200, 160);
label2->setStyleSheet("border:1px solid black");
label3 = new QLabel(this);
label3->move(800, 100);
label3->resize(200, 100);
label3->setStyleSheet("border:1px solid black");
//label3->setWordWrap(true);
//opencv高斯处理
pButton = new QPushButton(this);
pButton->move(220, 100);
pButton->setText("高斯处理");
//二值化
pButton1 = new QPushButton(this);
pButton1->move(220, 140);
pButton1->setText("二值化(80)");
//滑动条设置二值化值
slider = new QSlider(Qt::Horizontal, this); //Qt::Horizontal设置为水平的滑动条
//设置滑动条样式
slider->setStyleSheet("QSlider::groove:horizontal{height:12px; left:0px; right:0px; border:0px; border-radius:6px; background:rgb(242,242,242);} \
QSlider::handle:horizontal{width:24px; background:#1644B0; border-radius:12px; margin:-6px 0px;} \
QSlider::sub-page:horizontal{background:#4C85FB; border:0px; border-radius:6px;}");
slider->move(220, 180);//设置滑动条位置
slider->setRange(0, 255);//设置滑动条取值范围
slider->setFixedWidth(255);//设置滑动条长度
//opencv边缘检测
pButton2 = new QPushButton(this);
pButton2->move(220, 220);
pButton2->setText("canny");
//opencv打开相机
pButton3 = new QPushButton(this);
pButton3->setText("打开相机");
pButton3->move(5, 400);
//给按钮设置图案
QIcon icon(".\\ico\\U2.png"); //创建icon对象,保存相对应的图片路径。
btn_language = new QPushButton(this); //创建button对象
btn_language->move(120, 400);
btn_language->setFixedSize(100, 40); //设置按钮宽高
//btn_language->setIcon(icon);//将图片填充进按钮中
btn_language->setIcon(icon);//将图片填充进按钮中
btn_language->setIconSize(QSize(btn_language->width(), btn_language->height()));//让图片的尺寸和按钮对应
QImage image = QImage("C:\\MyGit\\mms_v2\\mms_v2\\mms_v2\\ico\\U2.png");
label->setPixmap(QPixmap::fromImage(image));
label->setScaledContents(true);//图片自适应大小
pButton4 = new QPushButton(this);
pButton4->move(220, 250);
pButton4->setText("显示像素");
pButton5 = new QPushButton(this);
pButton5->setText("New_algorithm");
pButton5->move(220, 300);
pButton5->adjustSize();
pButton6 = new QPushButton(this);
pButton6->setText("灰度图");
pButton6->move(220, 330);
pButton6->adjustSize();
pButton7 = new QPushButton(this);
pButton7->setText("暂计数");
pButton7->move(220, 370);
pButton7->adjustSize();
//QPixmap Images("C:/Users/25125/Pictures/Saved Pictures/hp/aa.jpg");
//QPalette Palette = this->palette();//设置背景图
//Palette.setBrush(QPalette::Background, Images);
//this->setPalette(Palette);
#ifndef USE_DEFAULT_MENU_BAR
//当不使用QMainWindow自带的菜单栏时,必须要加上此行
setMenuBar(pMenuBar);
#endif
//添加菜单响应函数
connect(pActionTest, &QAction::triggered, this, &interface_vs::newWindow);
connect(pActionTest3, &QAction::triggered, this, &interface_vs::OnActionTest);
connect(pActionTest1, &QAction::triggered, this, &interface_vs::OnActionTest1);
//按钮响应函数
connect(pButton, SIGNAL(clicked()), this, SLOT(ClickButton()));
connect(pButton1, SIGNAL(clicked()), this, SLOT(ClickButton1()));
connect(pButton2, SIGNAL(clicked()), this, SLOT(ClickButton2()));
//滑动条响应函数
connect(slider, SIGNAL(valueChanged(int)), this, SLOT(SliderChangeImageshow(int)));
connect(pButton3, SIGNAL(clicked()), this, SLOT(OpenCamera()));
connect(pButton4, SIGNAL(clicked()), this, SLOT(ShowPoint()));
connect(pButton5, SIGNAL(clicked()), this, SLOT(New_algorithm()));
connect(pButton6, SIGNAL(clicked()), this, SLOT(cvt()));
connect(pButton7, SIGNAL(clicked()), this, SLOT(vi()));
}
//菜单exit响应函数
void interface_vs::OnActionTest()
{
QApplication *app;
app->quit();
}
void interface_vs::newWindow() {
nw = new newWindowClass();
//设置几行几列
nw->setRowAndCol(3, 5);
//设置表格中每一行的表头
QStringList header;
header << "1" << "2" << "3" << "4" << "5";
nw->setHorizontalHeaderLabels(header);
//3行5列
for (int i = 0; i < 3; i++)
for (int j = 0; j < 5; j++)
{
QTableWidgetItem *item = new QTableWidgetItem(QIcon(":/image/search.png"), "td");
nw->setItem(i, j, item);
}
nw->setMinimumSize(600, 400);
nw->setWindowTitle("表格");
nw->show();
}
//灰度图
void interface_vs::cvt() {
Mat srcimage = imread(image_address.toStdString());//原始图片的路径来自于打开图片
//变为灰度图
cvtColor(srcimage, srcimage, COLOR_BGR2GRAY);
After_processing = srcimage;
QImage twoImage = QImage((const unsigned char*)(srcimage.data), srcimage.cols, srcimage.rows, QImage::Format_Grayscale8);
twoImage = twoImage.scaled(label2->width(), label2->height());
label2->setPixmap(QPixmap::fromImage(twoImage));
}
//该函数是之前项目设计算法时用到,可以不看
//遍历像素,连续的存入vector<int>中
void interface_vs::vi() {
Mat srcimage = imread(image_address.toStdString());//原始图片的路径来自于打开图片
Mat originImg;
//变为灰度图
cvtColor(srcimage, originImg, COLOR_BGR2GRAY);
vector<vector<int>> vv;
int t_count = 0;//暂存数
int rowNumber = originImg.rows; //行数
int colNumber = originImg.cols * originImg.channels(); //列数 x 通道数=每一行元素的个数
//双重循环,遍历所有的像素值
for (int i = 0; i < rowNumber; i++) //行循环
{
//每张图片进来都会先找自己的暂存数,所以可以另外写一个函数做下面的操作 需要的参数:i,originImg,colNumber,返回值是vector<vector<int>>类型
vector<int> ve;
uchar* data = originImg.ptr<uchar>(i); //获取第i行的首地址
for (int j = 0; j < colNumber; j++) //列循环
{
//data[j] = data[j] / div * div + div / 2;
int a = 0;
if ((int)data[j] >= 0 && (int)data[j] < 200) {//比较拿到黑色像素的
if (ve.empty()) {
ve.push_back(j);//记录位置而不是像素值
continue;
}
else {
for (int k = 0; k < ve.size(); k++) {
if (j == ve.at(k) + 1) {
ve.push_back(j);
a = 1;
}
}
if (a) {
a = 0;
continue;
}
vv.push_back(ve);
t_count++;//暂存计数
ve.clear();
ve.push_back(j);
}
}
} //行处理结束
}
//遍历vector
QString text;
for (int k = 0; k < vv.size(); k++) {
text += "(";
for (int t = 0;t<vv.at(k).size();t++) {
text += QString::number(vv.at(k).at(t));
}
text += ")";
}
label3->setText("暂计数:" + QString::number(t_count)+":"+ text);
label3->adjustSize();
}
void interface_vs::New_algorithm(){
Mat srcimage = imread(image_address.toStdString());//原始图片的路径来自于打开图片
Mat originImg, binaryImage;
//变为灰度图
cvtColor(srcimage, originImg, COLOR_BGR2GRAY);
QString text;
vector<int> ve;
vector<vector<int>> vv;
int count = 0;//计数
//遍历像素
int rowNumber = originImg.rows; //行数
int colNumber = originImg.cols * originImg.channels(); //列数 x 通道数=每一行元素的个数
//双重循环,遍历所有的像素值
for (int i = 0; i < rowNumber; i++) //行循环
{
uchar* data = originImg.ptr<uchar>(i); //获取第i行的首地址
for (int j = 0; j < 1; j++) //列循环
{
//data[j] = data[j] / div * div + div / 2;
if ((int)data[j] > 0 && (int)data[j] < 255) {//比较拿到黑色像素的
ve.push_back((int)data[j]);
count++;
}
} //行处理结束
}
//遍历vector
for (int k = 0; k < ve.size(); k++) {
text += QString::number(ve.at(k))+",";
}
label3->setText(QString::number((int)ve.size())+";"+QString::number(count)+":"+text);
label3->adjustSize();
}
//菜单打开图片响应函数
void interface_vs::OnActionTest1()
{
QString filename = QFileDialog::getOpenFileName(this, tr("Open Image"), QDir::homePath(), tr("(*.jpg)\n(*.bmp)\n(*.png)")); //打开图片文件,选择图片
image_address = filename;
qDebug() << "filename:" << filename;
QImage image = QImage(filename); //图片初始化
qDebug() << "image:" << image;
if (!image.isNull())
{
label->setPixmap(QPixmap::fromImage(image));
label->setScaledContents(true);//图片自适应大小
//label->show();
ui.statusBar->showMessage(tr("Open Image Success!"), 3000); //打开成功时显示的内容
}
else
{
ui.statusBar->showMessage(tr("Save Image Failed!"), 3000);
return;
}
// QDialog dlg;
// dlg.setWindowTitle("测试菜单响应");
// dlg.exec();
}
void interface_vs::print_px_value(Mat& im)
{
QString text;
int rowNumber = im.rows; //行数
int colNumber = im.cols * im.channels(); //列数 x 通道数=每一行元素的个数
text = QString::number(rowNumber) + "行;" + QString::number(colNumber)+"列";
//双重循环,遍历所有的像素值
for (int i = 0; i < rowNumber; i++) //行循环
{
uchar* data = im.ptr<uchar>(i); //获取第i行的首地址
text += "<br>"+QString::number(i) + ":";
for (int j = 0; j < colNumber; j++) //列循环
{
//data[j] = data[j] / div * div + div / 2;
text += QString::number((int)data[j])+",";
} //行处理结束
}
label3->setText(text);
label3->adjustSize(); //自适应大小
}
//高斯滤波按钮响应函数
void interface_vs::ClickButton() {
//读取原始图片
if (image_address == "") {
QMessageBox::critical(NULL, "警告", "未打开任何图片", QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
return ;
}
Mat srcimage = imread(image_address.toStdString());//原始图片的路径来自于打开图片
//Mat转QImage 颜色
cvtColor(srcimage, srcimage, COLOR_BGR2RGB);
//Mat转QImage 像素 oldlabel放置原图
QImage disimage = QImage(srcimage.data, srcimage.cols, srcimage.rows, srcimage.cols*srcimage.channels(), QImage::Format_RGB888);
Mat retimage;
//高斯模糊
GaussianBlur(srcimage, retimage, Size(3, 5), 0, 0);//高斯核的大小必须是奇数(size中两数的乘积必须为奇数)
//GaussianBlur(retimage, retimage, Size(9, 9), 0, 0);
After_processing = retimage;
//Mat转QImage 像素 newlabel放置图像处理后图片
QImage disimage2 = QImage(retimage.data, retimage.cols, retimage.rows, retimage.cols*retimage.channels(), QImage::Format_RGB888);
disimage2 = disimage2.scaled(label2->width(), label2->height());
label2->setPixmap(QPixmap::fromImage(disimage2));
}
//二值化
void interface_vs::ClickButton1() {
//读取原始图片
if (image_address == "") {
QMessageBox::critical(NULL, "警告", "未打开任何图片", QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
return;
}
Mat srcimage = imread(image_address.toStdString());//原始图片的路径来自于打开图片
Mat originImg, binaryImage;
cvtColor(srcimage, originImg, COLOR_BGR2GRAY);
//imshow("src",originImg);
// QImage orImg = QImage((const unsigned char*)(originImg.data),
// originImg.cols, originImg.rows, QImage::Format_Grayscale8);
//QImage orImg = QImage(originImg.data,originImg.cols,originImg.rows,originImg.cols*originImg.channels(),QImage::Format_RGB888);
threshold(originImg, binaryImage, 80, 255.0, THRESH_BINARY);
After_processing = binaryImage;
QImage twoImage = QImage((const unsigned char*)(binaryImage.data), binaryImage.cols, binaryImage.rows, QImage::Format_Grayscale8);
twoImage = twoImage.scaled(label2->width(), label2->height());
label2->setPixmap(QPixmap::fromImage(twoImage));
// //存储二值化后的图像
// Mat binaryImage;
// //-------初始的二值化阈值为80
// threshold(binaryImage, srcimage, 80, 255.0, THRESH_BINARY);
// //QImage twoImage = QImage((const unsigned char*)(binaryImage.data),binaryImage.cols, binaryImage.rows, QImage::Format_Grayscale8);
// QImage twoImage = QImage(binaryImage.data,binaryImage.cols,binaryImage.rows,binaryImage.cols*binaryImage.channels(),QImage::Format_RGB888);
// label2->setPixmap(QPixmap::fromImage(twoImage));
}
//滑动条控制二值化
void interface_vs::SliderChangeImageshow(int a) {
int thres = a;
qDebug() << thres;
if (image_address == "") {
QMessageBox::critical(NULL, "警告", "未打开任何图片", QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
return;
}
Mat srcimage = imread(image_address.toStdString());
Mat binaryImage;
cvtColor(srcimage, srcimage, COLOR_BGR2GRAY);
threshold(srcimage, binaryImage, thres, 255.0, THRESH_BINARY);
After_processing = binaryImage;
QImage twoImage = QImage((const unsigned char*)(binaryImage.data), binaryImage.cols, binaryImage.rows, QImage::Format_Grayscale8);
twoImage = twoImage.scaled(label2->width(), label2->height());
label2->setPixmap(QPixmap::fromImage(twoImage));
}
//边缘检测
void interface_vs::ClickButton2() {
if (image_address == "") {
QMessageBox::critical(NULL, "警告", "未打开任何图片", QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
return;
}
Mat srcimage = imread(image_address.toStdString());
Mat edgeImg;
Canny(srcimage, edgeImg, 30, 80);
After_processing = edgeImg;
QImage twoImage = QImage((const unsigned char*)(edgeImg.data), edgeImg.cols, edgeImg.rows, QImage::Format_Grayscale8);
label2->setPixmap(QPixmap::fromImage(twoImage));
}
//使用opencv调用摄像头
void interface_vs::OpenCamera() {
Mat frame;
VideoCapture cap(0);//摄像头调用
int race = 0;
while (cap.read(frame))
{
if (race == 1) {
break;
}
imshow("frame", frame);
race = 1;
waitKey(1000);
}
namedWindow("Vidio", 1);
}
//显示处理后图片的像素
void interface_vs::ShowPoint() {
if (After_processing.data == 0) {
QMessageBox::critical(NULL, "警告", "没有未处理后的图片", QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
return;
}
print_px_value(After_processing);
}
interface_vs::~interface_vs()
{}
newWindowClass.h:
#pragma once
#include <QWidget>
#include "ui_newWindowClass.h"
#include <QTableWidget>
#pragma execution_character_set("utf-8")
class newWindowClass : public QTableWidget
{
Q_OBJECT
public:
newWindowClass(QWidget *parent = nullptr);
~newWindowClass();
QTableWidget *tableWidget;
void setRowAndCol(int row, int col);
private:
Ui::newWindowClassClass ui;
};
newWindowClass.cpp
#include "newWindowClass.h"
#include <QMessageBox>
#include <QHeaderView>
#include <QMouseEvent>
#include <QDebug>
newWindowClass::newWindowClass(QWidget *parent)
: QTableWidget(parent)
{
this->setFont(QFont("微软雅黑", 12));
this->setShowGrid(false); //不显示网格线
this->setSelectionBehavior(QAbstractItemView::SelectRows); //设置整行选择
this->setMouseTracking(true); //开启捕获鼠标功能
this->setEditTriggers(QAbstractItemView::NoEditTriggers); //禁止编辑表格
this->verticalHeader()->setVisible(false);//纵向表头可视化
this->horizontalHeader()->setStyleSheet("QHeaderView::section {""background-color:#383838;}");
this->setStyleSheet("background-color:#1a1a1a;color:#fff;gridline-color: rgb(0, 0, 0)");//设置当前颜色
this->horizontalHeader()->setDefaultSectionSize(120); //设置默认宽度 不设置的话宽度也会平均分配 但不会按照窗口宽度分配
this->verticalHeader()->setDefaultSectionSize(30); //设置一行默认高度
// this->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);//自适应所有列,让它布满空间。设置了就列就不能拉伸
// this->horizontalHeader()->resizeSections(QHeaderView::Stretch);//列可以拉伸
this->horizontalHeader()->setStretchLastSection(true);//最后一列铺满
this->setAlternatingRowColors(true);// 设置隔行背景色
this->setPalette(QPalette(QColor(70, 70, 70)));//参数还可写成QPalette(Qt::blue) QPalette(QColor(36,36,36))
this->setStyleSheet("selection-background-color:#0e4b72"); //设置选中行颜色
// this->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOn);//设置水平滚动条
// this->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);//设置垂直滚动条
}
void newWindowClass::setRowAndCol(int row, int col) {
this->setRowCount(row); //设置行数为10
this->setColumnCount(col); //设置列数为5
}
newWindowClass::~newWindowClass()
{}
效果展示: