目录
实验总结
代码大致分为两部分,建了两个UI窗口,一部分是图像处理并分割出疵点图像,第二部分使用SVM(之前做的)进行分类,在第一个UI中调用第二个UI。
代码
图像处理部分
.h
#pragma once
#include <QtWidgets/QMainWindow>
#include "ui_imgProcess.h"
#include <QLabel>
#include <QString>
#include <QFileDialog>
#include <QDir>
#include <QFile>
#include <QDebug>
#include <QImage>
class imgProcess : public QMainWindow
{
Q_OBJECT
private:
void initUI();
public:
imgProcess(QWidget *parent = Q_NULLPTR);
public slots:
void openImg();
void processImg();
void SVMDetect();
private:
Ui::imgProcessClass ui;
};
.cpp
#include "imgProcess.h"
#include<iostream>
#include<opencv2/opencv.hpp>
#include "img.h" //用于图像处理的类
#include "Widget.h"
using namespace cv;
using namespace std;
Mat cvimg; //用于QTImage 转换到 CVImage 进行图像处理
img imgP; // 进行类的声明
Mat QCTransfer(QImage image)
{
Mat dst;
dst = Mat(image.height(), image.width(), CV_8UC4, (void*)image.constBits(), image.bytesPerLine());
return dst;
}
void imgProcess::initUI()
{
}
imgProcess::imgProcess(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
initUI();
connect(ui.openButton, SIGNAL(clicked()), this, SLOT(openImg()));
connect(ui.imgButton, SIGNAL(clicked()), this, SLOT(processImg()));
connect(ui.detectButton, SIGNAL(clicked()), this, SLOT(SVMDetect()));
}
void imgProcess::openImg()//选择一张图片并打开
{
ui.originalImg->clear(); //清除已有的图片的操作
ui.processImg->clear();
QString fileName = QFileDialog::getOpenFileName(this, "OpenFile", QDir::currentPath());
if (fileName.isEmpty())
{
qDebug() << "error, please reselect" << endl;
return;
}
else {
//qDebug() << "img file: " << fileName << endl;
QImage qimg;
qimg.load(fileName);
//qimg = qimg.scaled(ui.originalImg->size());// 图片使用label尺寸,检测效果不好,改变了尺寸
cvimg = QCTransfer(qimg);//qt图像 转 opencv mat 矩阵
//qDebug() << qimg.format() << endl;
ui.originalImg->resize(qimg.size());
ui.originalImg->setPixmap(QPixmap::fromImage(qimg));
//imshow("test", cvimg);
//waitKey(0);
}
}
void imgProcess::processImg()
{
cvimg = imgP.to_gray(cvimg);
//cout << "cvimg format" << cvimg.channels() << endl; //输出为1,表示一个通道的灰度图
cvimg = imgP.img_process(cvimg);
imgP.img_get(cvimg);//将每个疵点保存到文件夹
//CV 图像 转 Qt 图像并在label 中显示
QImage Qtemp = QImage((const unsigned char*)(cvimg.data), cvimg.cols, cvimg.rows, cvimg.step, QImage::Format_Grayscale8);
Qtemp = QImage((const unsigned char*)(cvimg.data), cvimg.cols, cvimg.rows, cvimg.step, QImage::Format_Grayscale8);
//Qtemp = Qtemp.scaled(ui.processImg->size());// 图片使用label尺寸
ui.processImg->setPixmap(QPixmap::fromImage(Qtemp));
ui.processImg->resize(Qtemp.size()); // label 适应 image 尺寸
ui.processImg->show();
}
void imgProcess::SVMDetect()
{
Widget* w = new Widget();
w->show();
}
SVM分类部分
.h
#pragma once
#include <QtWidgets/QWidget>
#include "ui_Widget.h"
#include <QDir>
#include <QFileDialog>
#include <QStringList>
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget* parent = Q_NULLPTR);
void Ui_Init();
void SVM_Pre();//predict by SVM
private:
Ui::Form ui;
};
.cpp
#include "Widget.h"
#include<iostream>
#include<opencv2/opencv.hpp>
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include "opencv2/imgcodecs.hpp"
#include <opencv2/highgui.hpp>
#include <opencv2/ml.hpp>
#include "img.h"
using namespace cv;
using namespace std;
using namespace cv::ml;
//建立类
img imgSVM; // 进行类的声明
//检测SVM检测部分
void Widget::SVM_Pre()
{
Ptr<ml::SVM>svm = ml::SVM::load("svm.xml");
int class1= 0;//三个类别的数目统计,先初始化为0
int class2 = 0;
int class3 = 0;
// 使用CV 读取文件夹下的所有图片文件,尝试用qt 的方法,但是不太行
String imgpath = "E:\\QtCv\\detect\\*.jpg";//要检查的文件夹及其文件类型
vector<cv::String> image_files;
glob(imgpath, image_files, false);
cout << "cout : " << image_files.size() << endl;
//开始遍历并进行检测数据的统计
//cout << "file dir" <<image_files.at(0) << endl;
Mat testImg;
Mat testData(1, 3, CV_32F);//测试数据 1行 3列
int tastLabel;
for (int i = 0; i < image_files.size(); i++)
{
testImg = imread(image_files.at(i), 0);
testData.at<float>(0, 0) = imgSVM.get_Area(testImg);
testData.at<float>(0, 1) = imgSVM.get_wh(testImg);
testData.at<float>(0, 2) = imgSVM.get_DutyRation(testImg);
tastLabel = svm->predict(testData);
switch (tastLabel)
{
case 1: class1++; break;
case 2: class2++; break;
case 3: class3++; break;
}
}
QString c = QString::number(class1);
ui.class1Num->clear();
ui.class1Num->insertPlainText(c);
c = QString::number(class2);
ui.class2Num->clear();
ui.class2Num->insertPlainText(c);
c = QString::number(class3);
ui.class3Num->clear();
ui.class3Num->insertPlainText(c);
}
void Widget::Ui_Init() //UI界面初始化
{
QImage longg;
QImage point;
QImage big;
longg.load(":/Image/1.jpg");//加载长疵
ui.class1Show->setPixmap(QPixmap::fromImage(longg));
ui.class1Show->resize(longg.size()); // label 适应 image 尺寸
ui.class1Show->show();
//另外两个同理
point.load(":/Image/point.jpg");//加载点疵,点疵图片已经放入资源文件
//cout << point.format() << endl;
ui.class2Show->setPixmap(QPixmap::fromImage(point));
ui.class2Show->resize(point.size()); // label 适应 image 尺寸
ui.class2Show->show();
big.load(":/Image/2.jpg");//加载团疵
ui.class3Show->setPixmap(QPixmap::fromImage(big));
ui.class3Show->resize(big.size()); // label 适应 image 尺寸
ui.class3Show->show();
}
Widget::Widget(QWidget* parent)
: QWidget(parent)
{
ui.setupUi(this);
Ui_Init();
SVM_Pre();
}
类函数部分
.h
#pragma once
#include<opencv2/opencv.hpp>
#include<iostream>
using namespace cv;
using namespace std;
class img
{
public:
Mat to_gray(Mat& image);//图像灰度处理
Mat img_process(Mat& image);//预处理
Mat img_num(Mat& image);//返回计数一个疵点图
void img_get(Mat& image);//疵点保存文件夹
float get_Area(Mat& iamge);//统计白色像素点的个数
float get_wh(Mat& image);//宽高之比
float get_DutyRation(Mat& image);//返回疵点图像的占空比
private:
int w; // 图像的宽度,类内部的函数都可以调用
int h; //图像的高度
};
.cpp
#include "img.h"
//图像灰度处理
Mat img::to_gray(Mat& image)
{
Mat dst;
cvtColor(image,dst, COLOR_RGB2GRAY); //转为灰度
return dst;
}
//图像预处理
Mat img::img_process(Mat& image)
{
Mat dst;
GaussianBlur(image, dst, Size(3, 3), 0, 0);
threshold(dst, dst, 188, 255, THRESH_BINARY); // 阈值,手动调节bar获得
Mat element = getStructuringElement(MORPH_RECT, Size(2, 2));
morphologyEx(dst, dst, MORPH_OPEN, element);
return dst;
}
Mat img::img_num(Mat& image)
{
Mat dst;
dst = image;
vector<vector<Point> > contours;//检测到的轮廓,每条轮廓线都以点向量的形式存储
vector<Vec4i> hierarchy;//包含有关图像拓扑的信息
findContours(image, contours, hierarchy, RETR_TREE, CHAIN_APPROX_NONE, Point());
int i = 0;
int j = 1;
for (i = 0; i < contours.size(); i++) {
Rect fRect = boundingRect(contours[i]);
int x_pontl = fRect.x - 5;
int y_pontl = fRect.y - 5;
int x_pontr = fRect.x + fRect.width + 2;
int y_pontr = fRect.y + fRect.height + 2;
int area = fRect.height * fRect.width;
if (area >= 5) {
rectangle(dst, Point(x_pontl, y_pontl), Point(x_pontr, y_pontr), Scalar(255), 1);
string text = to_string(j);
putText(dst, text, Point(x_pontl, y_pontl), FONT_HERSHEY_SIMPLEX, 0.4, (255), 1);
j++;
}
}
return dst;
}
string imgfile = "E:\\Qt Cv\\detect\\";
string imgName;
//50*50 模板的尺寸
//图像融合 传入的图像与50*50 的进行融合
Mat img_resize(Mat& image, int& w, int& h)
{
Mat black_img = Mat::zeros(Size(50, 50), CV_8UC1);//黑色图像
Mat imgROI;
int x = 25 - (w / 2);
int y = 25 - (h / 2);
imgROI = black_img(Rect(x, y, w, h));
addWeighted(imgROI, 0.1, image, 0.9, 0, imgROI);
return black_img;
}
void img::img_get(Mat& image)
{
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
findContours(image, contours, hierarchy, RETR_EXTERNAL, CHAIN_APPROX_NONE, Point());
int i = 0;
int j = 1;
int w_roi, h_roi;
Mat roi;
Mat img_wr;
for (i = 0; i < contours.size(); i++) {
Rect frect = boundingRect(contours[i]); // 轮廓的面积
//坐标修改
int area = frect.height * frect.width;
if (area >= 10) {
Rect rec(frect.x, frect.y, frect.width, frect.height);
roi = image(rec);
w_roi = roi.cols;
h_roi = roi.rows;
cout << j << "尺寸" << w_roi << "*" << h_roi << endl;
//将其变为正确的尺寸
img_wr = img_resize(roi, w_roi, h_roi);
imgName = imgfile + to_string(j) + ".jpg";
j++;
imwrite(imgName, img_wr);
}
}
}
float img::get_Area(Mat& iamge)
{
threshold(iamge, iamge, 0, 255, THRESH_BINARY);
float area = 0.;
//通过迭代器访问图像的像素点
Mat_<uchar>::iterator itor = iamge.begin<uchar>();
Mat_<uchar>::iterator itorEnd = iamge.end<uchar>();
for (; itor != itorEnd; itor++) {
if ((*itor) > 254) {
//白色像素
area++;
}
}
return area;
}
float img::get_wh(Mat& image)
{
float w, h;
threshold(image, image, 0, 255, THRESH_BINARY);
float ration;// 返回的宽 高 之比, 长条形 宽大于高
Mat element = getStructuringElement(MORPH_RECT, Size(3, 3));
morphologyEx(image, image, MORPH_OPEN, element);
vector<vector<Point> > contours;//检测到的轮廓,每条轮廓线都以点向量的形式存储
vector<Vec4i> hierarchy;//包含有关图像拓扑的信息
findContours(image, contours, hierarchy, RETR_TREE, CHAIN_APPROX_NONE, Point());
for (int i = 0; i < contours.size(); i++) {
Rect rects = boundingRect(contours[i]);
int area = rects.width * rects.height;
if (area > 10) {//排除过小的噪声被当成轮廓
w = rects.width;
h = rects.height;
}
}
ration = w / h;
return ration;
}
float img::get_DutyRation(Mat& image)
{
float duty_ration;
int imageW = image.cols;
int imageH = image.rows;
float imageArea = imageW * imageH;
float foreArea = get_Area(image);//前景图像的面积,彩色像素的面积
duty_ration = foreArea / imageArea;
return duty_ration;
}
主函数部分
#include "imgProcess.h"
#include <QtWidgets/QApplication>
#include<opencv2/opencv.hpp>
#include<iostream>
#include<string.h>
using namespace cv;
using namespace std;
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
//创建窗口程序
imgProcess w;
w.show();
return a.exec();
}
效果
链接
百度网盘整个文件
链接:https://pan.baidu.com/s/13vNzjWO4Rv_rrDWVM2-0pw
提取码:g1lv