Skip to content

Commit c7b87df

Browse files
committed
initial
0 parents  commit c7b87df

11 files changed

+510
-0
lines changed

Diff for: .gitignore

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
*.o
2+
a.out
3+
*.user
4+
bin/
5+
build/

Diff for: QtYOLOv9.pro

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
2+
TARGET = QtYOLOv9
3+
TEMPLATE = app
4+
QT += core gui widgets
5+
6+
# ビルド結果はbinディレクトリに出力されます
7+
DESTDIR = $$PWD/bin
8+
# 実行ファイルと同じ場所にモデルファイル(yolov9.onnx)をコピーしておきます
9+
10+
INCLUDEPATH += $$PWD/src
11+
LIBS += -lonnxruntime
12+
13+
SOURCES += \
14+
src/ImageView.cpp \
15+
src/MainWindow.cpp \
16+
src/YOLOv9Detector.cpp \
17+
src/main.cpp
18+
19+
FORMS += \
20+
src/MainWindow.ui
21+
22+
HEADERS += \
23+
src/ImageView.h \
24+
src/MainWindow.h \
25+
src/YOLOv9Detector.h

Diff for: docs/QtYOLOv9.png

649 KB
Loading

Diff for: src/ImageView.cpp

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#include "ImageView.h"
2+
3+
#include <QPainter>
4+
5+
/**
6+
* @brief コンストラクタ
7+
*/
8+
ImageView::ImageView(QWidget *parent)
9+
: QWidget{parent}
10+
{
11+
12+
}
13+
14+
/**
15+
* @brief 画像を設定
16+
*/
17+
void ImageView::setImage(const QImage &image)
18+
{
19+
image_ = image;
20+
update(); // 再描画
21+
}
22+
23+
/**
24+
* @brief 描画
25+
*/
26+
void ImageView::paintEvent(QPaintEvent *)
27+
{
28+
QPainter painter(this);
29+
int x = (width() - image_.width()) / 2;
30+
int y = (height() - image_.height()) / 2;
31+
painter.drawImage(QPoint(x, y), image_);
32+
}

Diff for: src/ImageView.h

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#ifndef IMAGEVIEW_H
2+
#define IMAGEVIEW_H
3+
4+
#include <QWidget>
5+
6+
/**
7+
* @brief 画像表示ウィジェット
8+
*/
9+
class ImageView : public QWidget {
10+
Q_OBJECT
11+
private:
12+
QImage image_;
13+
protected:
14+
void paintEvent(QPaintEvent *);
15+
public:
16+
explicit ImageView(QWidget *parent = nullptr);
17+
void setImage(const QImage& image);
18+
};
19+
20+
#endif // IMAGEVIEW_H

Diff for: src/MainWindow.cpp

+113
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
#include "MainWindow.h"
2+
#include "ui_MainWindow.h"
3+
#include "YOLOv9Detector.h"
4+
#include <QFileDialog>
5+
#include <QMessageBox>
6+
#include <QPainter>
7+
8+
/**
9+
* @brief MainWindow のプライベート実装
10+
*/
11+
struct MainWindow::Private {
12+
YOLOv9Detector detector;
13+
QImage image;
14+
};
15+
16+
/**
17+
* @brief コンストラクタ
18+
*/
19+
MainWindow::MainWindow(QWidget *parent)
20+
: QMainWindow(parent)
21+
, ui(new Ui::MainWindow)
22+
, m(new Private)
23+
{
24+
ui->setupUi(this);
25+
}
26+
27+
/**
28+
* @brief デストラクタ
29+
*/
30+
MainWindow::~MainWindow()
31+
{
32+
delete ui;
33+
delete m;
34+
}
35+
36+
/**
37+
* @brief YOLOv9モデルが読み込まれているかどうか
38+
*/
39+
bool MainWindow::isModelReady() const
40+
{
41+
return m->detector;
42+
}
43+
44+
/**
45+
* @brief YOLOv9モデルを読み込む
46+
*/
47+
bool MainWindow::loadModel()
48+
{
49+
// 実行ファイルと同じ場所に yolov9.onnx が必要
50+
return m->detector.loadModel("yolov9.onnx");
51+
}
52+
53+
/**
54+
* @brief ファイルを開く
55+
*/
56+
void MainWindow::on_action_file_open_triggered()
57+
{
58+
// 開くファイルを選択
59+
QString path = QFileDialog::getOpenFileName(this, "Open Image");
60+
if (path.isEmpty()) return;
61+
62+
// 画像を読み込み
63+
QImage image = QImage(path);
64+
if (image.isNull()) {
65+
QMessageBox::critical(this, "Error", "Failed to load image");
66+
return;
67+
}
68+
69+
m->image = image;
70+
71+
// YOLOモデルの準備がまだなら読み込む
72+
if (!isModelReady()) {
73+
if (!loadModel()) {
74+
QMessageBox::critical(this, "Error", "Failed to load model");
75+
close();
76+
return;
77+
}
78+
}
79+
80+
// 物体検出
81+
auto bboxes = m->detector.inference(m->image); // inference() は std::optional を返す
82+
if (bboxes) {
83+
// 検出結果が有効ならバウンディングボックスを描画する
84+
QPainter painter(&m->image);
85+
for (auto const &bbox : *bboxes) {
86+
// バウンディングボックスのラベル
87+
QString label = QString::number(bbox.index); // とりあえずクラスIDを文字列にする
88+
89+
// TODO: クラスIDをラベルに変換する処理を追加
90+
// ラベルは data/coco.yaml に定義されている
91+
92+
QString text = QString("[%1] %2").arg(label).arg(bbox.score, 0, 'f', 2);
93+
94+
// バウンディングボックスを描画
95+
{
96+
painter.setPen(Qt::cyan); // 矩形の色
97+
painter.setBrush(Qt::NoBrush); // 塗りつぶさない
98+
painter.drawRect(bbox.rect); // 矩形を描画
99+
}
100+
// ラベルを描画
101+
{
102+
painter.setPen(Qt::black); // 文字の色
103+
QRect r = painter.fontMetrics().boundingRect(text).translated(bbox.rect.topLeft());
104+
painter.fillRect(r, Qt::cyan); // 背景を塗る;
105+
painter.drawText(bbox.rect.topLeft(), text); // ラベルを描画
106+
}
107+
}
108+
}
109+
110+
// 画像を表示
111+
ui->centralwidget->setImage(m->image);
112+
}
113+

Diff for: src/MainWindow.h

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#ifndef MAINWINDOW_H
2+
#define MAINWINDOW_H
3+
4+
#include <QMainWindow>
5+
6+
namespace Ui {
7+
class MainWindow;
8+
}
9+
10+
/**
11+
* @brief メインウィンドウ
12+
*/
13+
class MainWindow : public QMainWindow {
14+
Q_OBJECT
15+
private:
16+
Ui::MainWindow *ui;
17+
struct Private;
18+
Private *m;
19+
20+
bool isModelReady() const;
21+
bool loadModel();
22+
public:
23+
explicit MainWindow(QWidget *parent = nullptr);
24+
~MainWindow();
25+
private slots:
26+
void on_action_file_open_triggered();
27+
};
28+
29+
#endif // MAINWINDOW_H

Diff for: src/MainWindow.ui

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<ui version="4.0">
3+
<class>MainWindow</class>
4+
<widget class="QMainWindow" name="MainWindow">
5+
<property name="geometry">
6+
<rect>
7+
<x>0</x>
8+
<y>0</y>
9+
<width>800</width>
10+
<height>600</height>
11+
</rect>
12+
</property>
13+
<property name="windowTitle">
14+
<string>MainWindow</string>
15+
</property>
16+
<widget class="ImageView" name="centralwidget"/>
17+
<widget class="QMenuBar" name="menubar">
18+
<property name="geometry">
19+
<rect>
20+
<x>0</x>
21+
<y>0</y>
22+
<width>800</width>
23+
<height>28</height>
24+
</rect>
25+
</property>
26+
<widget class="QMenu" name="menu_File">
27+
<property name="title">
28+
<string>&amp;File</string>
29+
</property>
30+
<addaction name="action_file_open"/>
31+
</widget>
32+
<addaction name="menu_File"/>
33+
</widget>
34+
<widget class="QStatusBar" name="statusbar"/>
35+
<action name="action_file_open">
36+
<property name="text">
37+
<string>&amp;Open...</string>
38+
</property>
39+
<property name="shortcut">
40+
<string>Ctrl+O</string>
41+
</property>
42+
</action>
43+
</widget>
44+
<customwidgets>
45+
<customwidget>
46+
<class>ImageView</class>
47+
<extends>QWidget</extends>
48+
<header>ImageView.h</header>
49+
<container>1</container>
50+
</customwidget>
51+
</customwidgets>
52+
<resources/>
53+
<connections/>
54+
</ui>

0 commit comments

Comments
 (0)