0、需求
需求:找到符合要求的像素点,并且在将该像素点打上红色的掩膜
注意:
1.符号要求的像素点是一个区间,因此需要有Slinder(滑块槽)和SpinBox(旋钮)组件。Slinder组件用于进行粗调,SpinBox组件用于微调,因此还需要一个联动装置。
2.Slinder-SpinBox联动的范围为(-1)-(255)。这和RGB三通道的取值范围有一些不一样,由于RGB三通道的取值范围为0-255,设置一个-1是为了多一个选择,当输入出现-1是认为输出的是原始图像,不打掩膜。
3.Qt的格式和OPencv的格式不一样,因此在编写代码是要注意。
1、界面设计
Qt设计师设计界面如下:
编译以后界面如下:
2.实现
代码文件格式如下:
2.1 界面代码:
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QFile> // 文件
#include <QFileDialog> // 文件对话框
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
void imshow(QString filepath);
private slots:
void on_openImage_clicked();
void on_pushButton_clicked();
private:
Ui::MainWindow *ui;
QString filepath; // 读取的图片路径
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "addrgb.h"
#include <opencv2/opencv.hpp>
#include <QFile> // 文件
#include <QFileDialog> // 文件对话框
#include <QGraphicsView> // 读取图片
#include <QGraphicsScene>
#include <QPixmap>
#include <QGraphicsPixmapItem>
#include <QDebug>
#include <QtWidgets>
#include <QString>
#include <string>
using namespace cv;
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
// textLabel绘制边框
ui->inputLabel->setFrameShape(QFrame::Box);
ui->outputLabel->setFrameShape(QFrame::Box);
// SpinBox和Slider联动
// Rmin 滑块和选值框对应的改变
QObject::connect(ui->RMinSlider,SIGNAL(valueChanged(int)),
ui->RMinBox,SLOT(setValue(int)));
QObject::connect(ui->RMinBox,SIGNAL(valueChanged(int)),
ui->RMinSlider,SLOT(setValue(int)));
// Rmax
QObject::connect(ui->RMaxSlider,SIGNAL(valueChanged(int)),
ui->RMaxBox,SLOT(setValue(int)));
QObject::connect(ui->RMaxBox,SIGNAL(valueChanged(int)),
ui->RMaxSlider,SLOT(setValue(int)));
// Gmin
QObject::connect(ui->GMinSlider,SIGNAL(valueChanged(int)),
ui->GMinBox,SLOT(setValue(int)));
QObject::connect(ui->GMinBox,SIGNAL(valueChanged(int)),
ui->GMinSlider,SLOT(setValue(int)));
// Gmax
QObject::connect(ui->GMaxSlider,SIGNAL(valueChanged(int)),
ui->GMaxBox,SLOT(setValue(int)));
QObject::connect(ui->GMaxBox,SIGNAL(valueChanged(int)),
ui->GMaxSlider,SLOT(setValue(int)));
// Bmin
QObject::connect(ui->BMinSlider,SIGNAL(valueChanged(int)),
ui->BMinBox,SLOT(setValue(int)));
QObject::connect(ui->BMinBox,SIGNAL(valueChanged(int)),
ui->BMinSlider,SLOT(setValue(int)));
// Bmax
QObject::connect(ui->BMaxSlider,SIGNAL(valueChanged(int)),
ui->BMaxBox,SLOT(setValue(int)));
QObject::connect(ui->BMaxBox,SIGNAL(valueChanged(int)),
ui->BMaxSlider,SLOT(setValue(int)));
}
MainWindow::~MainWindow()
{
delete ui;
}
// 显示图片
void MainWindow::on_openImage_clicked()
{
filepath = QFileDialog::getOpenFileName(this);
QImage *img = new QImage;
img->load(filepath);
ui->inputLabel->setPixmap(QPixmap::fromImage(*img));
}
void MainWindow::on_pushButton_clicked()
{
//qDebug()<<filepath<<endl;
//qDebug()<<ui->BMaxBox->value()<<endl;
//QImage *add_img = new QImage;
//add_img->load(filepath);
//ui->outputLabel->setPixmap(QPixmap::fromImage(*add_img));
int Rmin=ui->RMinBox->value();
int Rmax=ui->RMaxBox->value();
int Gmin=ui->GMinBox->value();
int Gmax=ui->GMaxBox->value();
int Bmin=ui->BMinBox->value();
int Bmax=ui->BMaxBox->value();
String new_path = filepath.toStdString();
Mat input_img = imread(new_path);
//namedWindow("ori",WINDOW_FREERATIO);
//cv::imshow("ori",test_img);
Need N;
Mat add_img = N.AddRBG(input_img,Rmin,Rmax,
Gmin,Gmax,Bmin,Bmax);
// 注意:opencv下的图像通道是BGR,因此在转换过程中选择QImage::Format_BGR888
QImage after_add_img=QImage((const unsigned char*)
(add_img.data),add_img.cols,add_img.rows,add_img.step,QImage::Format_BGR888);
ui->outputLabel->setPixmap(QPixmap::fromImage(after_add_img));
}
2.2 OpenCV代码
addrgb.h
#ifndef ADDRGB_H
#define ADDRGB_H
#endif // ADDRGB_H
#include <opencv2/opencv.hpp>
//using namespace cv;
using namespace std;
class Need
{
public:
// 给图像打掩膜
cv::Mat AddRBG(cv::Mat &img, int rmin, int rmax,
int gmin, int gmax, int bmin, int bmax);
};
addrgb.cpp
#include <stdio.h>
#include <opencv2/opencv.hpp>
#include "addrgb.h"
using namespace cv;
using namespace std;
Mat Need::AddRBG(Mat &img, int rmin, int rmax,
int gmin, int gmax, int bmin, int bmax)
{
// img:输入图像
// rmin:R通道符合要求的最小值
// rmax:R通道符合要求的最大值
// gmin:G通道符合要求的最小值
// gmax:G通道符合要求的最大值
// bmin:B通道符合要求的最小值
// bmax:B通道符合要求的最大值
// 输出:打掩膜以后的图像
Mat add_img;
img.copyTo(add_img);
int h = img.rows;
int w = img.cols;
int dims = img.channels();
if(rmin==-1 || rmax==-1 || gmin==-1 || gmax==-1 ||
bmin==-1 || bmax==-1){
// 如果最大值和最小值为-1,就认为传入参数错误,因此输出原图
add_img = img;
}
else if(rmin>rmax || gmin>gmax || bmin>bmax)
{
// 如果min>max,就认为传入参数错误,因此输出原图
add_img = img;
}
else if(dims==1)
{
// 如果输入通道为1,就认为传入参数错误,因此输出原图
add_img = img;
}
else
{
for(int row=0;row<h;row++){
for(int col=0;col<w;col++){
// 输入图像正常
if((img.at<Vec3b>(row,col)[0]>=bmin && img.at<Vec3b>(row,col)[0]<=bmax)
&& (img.at<Vec3b>(row,col)[1]>=gmin && img.at<Vec3b>(row,col)[1]<=gmax)
&& (img.at<Vec3b>(row,col)[2]>=rmin && img.at<Vec3b>(row,col)[2]<=rmax))
{
add_img.at<Vec3b>(row,col)[0]=0;
add_img.at<Vec3b>(row,col)[1]=0;
add_img.at<Vec3b>(row,col)[2]=255;
}
}
}
}
return add_img;
}