Qt OpenCV 学习(六):kmeans聚类算法实现背景替换

1. mainwindow.h

cpp 复制代码
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <opencv2/opencv.hpp>

#include <QString>
#include <QPixmap>
#include <QDebug>
#include <QImage>
#include <QFileDialog>

using namespace cv;
using namespace std;

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow {
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

    void showImage(Mat &sendMat);

private slots:
    void on_btnOpn_clicked();

    void on_btnProcess_clicked();

private:
    Ui::MainWindow *ui;

    Mat srcImg;
};
#endif // MAINWINDOW_H

1. mainwindow.cpp

cpp 复制代码
#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) {
    ui->setupUi(this);
}

MainWindow::~MainWindow() {
    delete ui;
}

void MainWindow::showImage(Mat &sendMat) {
    Mat showImg = sendMat.clone();
    if (showImg.channels() == 1) {
        QImage showPic = QImage((const unsigned char*)(showImg.data), showImg.cols, showImg.rows, showImg.step, QImage::Format_Indexed8);
        ui->labelShow->setPixmap(QPixmap::fromImage(showPic.scaled(ui->labelShow->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation)));
    } else if (showImg.channels() == 3) {
        cvtColor(showImg, showImg, COLOR_BGR2RGB);
        QImage showPic = QImage((const unsigned char*)(showImg.data), showImg.cols, showImg.rows, showImg.step, QImage::Format_RGB888);
        ui->labelShow->setPixmap(QPixmap::fromImage(showPic.scaled(ui->labelShow->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation)));
    }
}

void MainWindow::on_btnOpn_clicked() {
    ui->lineEdit->clear();
    ui->labelShow->clear();
    QString filePath = QFileDialog::getOpenFileName(this, "open picture", ".", "picture (*.png *.jpg *.bmp)); All files (*.*)");
    ui->lineEdit->setText(filePath);

    srcImg = imread(filePath.toStdString());
    ui->labelShow->clear();
    showImage(srcImg);
}

void MainWindow::on_btnProcess_clicked() {
    Mat transfImg = srcImg.clone();
    Mat transfData = transfImg.reshape(3, transfImg.cols * transfImg.rows);

    transfData.convertTo(transfData, CV_32F);
    Mat bestLabels, centers;

    // 聚类的类别数,类别数越大则结果越接近原图像
    int K = 3;
    TermCriteria criteria = TermCriteria(TermCriteria::Type::COUNT + TermCriteria::Type::EPS, 10, 0.01);
    kmeans(transfData, K, bestLabels, criteria, 3, KMEANS_PP_CENTERS, centers);

    Mat kmeansImg = Mat::zeros(srcImg.size(), srcImg.type());
    Mat mask = Mat::zeros(srcImg.size(), CV_8UC1);

    // 获取左上角像素点的标签,作为背景像素点的标签
    int flag_label = bestLabels.at<int>(0, 0);
    for (int row = 0; row < transfImg.rows; row++) {
        for (int col = 0; col < transfImg.cols; col++) {
            int dataIndex = row * transfImg.cols + col;
            // 获取该像素点所属的类别标签
            int label = bestLabels.at<int>(dataIndex, 0);

            // 输出结果图中的每一个像素点,按照其所属的类别来改变其像素值
            if (label == flag_label) {
                mask.at<uchar>(row, col) = 255;
            }

            if (label == 0) {
                Vec3b bgr = {255, 0, 0};
                kmeansImg.at<Vec3b>(row, col) = bgr;
            } else if (label == 1) {
                Vec3b bgr = {0, 255, 0};
                kmeansImg.at<Vec3b>(row, col) = bgr;
            } else if (label == 2) {
                Vec3b bgr = {0, 0, 255};
                kmeansImg.at<Vec3b>(row, col) = bgr;
            }
        }
    }

    // 对图像进行闭操作:先膨胀后腐蚀,作用:消除 "闭合" 物体里面的孔洞
    // 开操作:先腐蚀后膨胀 作用:分离物体,消除小区域 特点:消除噪点,去除小的干扰块,而不影响原来的图像
    Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3));
    morphologyEx(mask, mask, MORPH_CLOSE, kernel, Point(-1, -1), 1, 0);

    Mat dstImg;
    dstImg = srcImg.clone();
    for (int row = 0; row < transfImg.rows; row++) {
        for (int col = 0; row < transfImg.cols; col++) {
            int flag = mask.at<uchar>(row, col);
            if (flag == 255) {
                Vec3b bgr = {255, 255, 255};
                dstImg.at<Vec3b>(row, col) = bgr;
            }
        }
    }

    showImage(dstImg);
}
相关推荐
孫治AllenSun10 分钟前
【算法】图相关算法和递归
windows·python·算法
格图素书1 小时前
数学建模算法案例精讲500篇-【数学建模】DBSCAN聚类算法
算法·数据挖掘·聚类
DashVector2 小时前
向量检索服务 DashVector产品计费
数据库·数据仓库·人工智能·算法·向量检索
AI纪元故事会2 小时前
【计算机视觉目标检测算法对比:R-CNN、YOLO与SSD全面解析】
人工智能·算法·目标检测·计算机视觉
夏鹏今天学习了吗2 小时前
【LeetCode热题100(59/100)】分割回文串
算法·leetcode·深度优先
卡提西亚2 小时前
C++笔记-10-循环语句
c++·笔记·算法
还是码字踏实2 小时前
基础数据结构之数组的双指针技巧之对撞指针(两端向中间):三数之和(LeetCode 15 中等题)
数据结构·算法·leetcode·双指针·对撞指针
Coovally AI模型快速验证4 小时前
当视觉语言模型接收到相互矛盾的信息时,它会相信哪个信号?
人工智能·深度学习·算法·机器学习·目标跟踪·语言模型
电院工程师5 小时前
SIMON64/128算法Verilog流水线实现(附Python实现)
python·嵌入式硬件·算法·密码学
轮到我狗叫了5 小时前
力扣.84柱状图中最大矩形 力扣.134加油站牛客.abb(hard 动态规划+哈希表)牛客.哈夫曼编码
算法·leetcode·职场和发展