Qt Creator C++ , OpenCV

## 1.opencvのwindow同時表示

1.qt creatorでプロジェクト作成,ビルドシステムは`cmake`を使用
2.プログラムを以下の様に変更

```c++:main.cpp
#include "mainwindow.h"
#include <QApplication>

#include <opencv2/opencv.hpp> // 追加

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();

    cv::Mat_<cv::Vec3b> img(300, 300, cv::Vec3b(0,200,0)); // 追加
    cv::imshow("", img ); // 追加
        
    return a.exec();
}
```

```cmake:CMakeLists.txt
project(ddd LANGUAGES CXX)

set(CMAKE_INCLUDE_CURRENT_DIR ON)

set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# QtCreator supports the following variables for Android, which are identical to qmake Android variables.
# Check http://doc.qt.io/qt-5/deployment-android.html for more information.
# They need to be set before the find_package(Qt5 ...) call.

#if(ANDROID)
#    set(ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/android")
#    if (ANDROID_ABI STREQUAL "armeabi-v7a")
#        set(ANDROID_EXTRA_LIBS
#            ${CMAKE_CURRENT_SOURCE_DIR}/path/to/libcrypto.so
#            ${CMAKE_CURRENT_SOURCE_DIR}/path/to/libssl.so)
#    endif()
#endif()

find_package(Qt5 COMPONENTS Widgets REQUIRED)
find_package(OpenCV REQUIRED) #追加

# 追加
include_directories(
 ${OpenCV_INCLUDE_DIRS} 
)
# ここまで

if(ANDROID)
  add_library(ddd SHARED
    main.cpp
    mainwindow.cpp
    mainwindow.h
    mainwindow.ui
  )
else()
  add_executable(ddd
    main.cpp
    mainwindow.cpp
    mainwindow.h
    mainwindow.ui
  )
endif()

target_link_libraries(ddd PRIVATE Qt5::Widgets
  ${OpenCV_LIBRARIES} #追加
)
```

結果
標準のwindowに加え,単色画像のwindowが表示されます.
![Screenshot from 2022-01-12 19-25-21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/589906/fbe47670-c9de-9b44-dcaf-73f0c75a1186.png)

## 2.widget内でopencv関数を使用

1.qt creatorでプロジェクト作成,ビルドシステムは`cmake`を使用
2.ui上にlabelを配置
3.プログラムを以下のように変更

```c++:mainwindow.cpp
#include "mainwindow.h"
#include "./ui_mainwindow.h"

#include <opencv2/opencv.hpp> // 追加

#include <QPixmap> // 追加

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

    cv::Mat_<cv::Vec3b> mat(300, 300, cv::Vec3b(0,200,0)); // 追加

    ui->label->setPixmap(QPixmap::fromImage(QImage((unsigned char*) mat.data, mat.cols, mat.rows, QImage::Format_RGB888))); // 追加
}

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

```cmake:CMakeLists.txt
project(ddd LANGUAGES CXX)

set(CMAKE_INCLUDE_CURRENT_DIR ON)

set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# QtCreator supports the following variables for Android, which are identical to qmake Android variables.
# Check http://doc.qt.io/qt-5/deployment-android.html for more information.
# They need to be set before the find_package(Qt5 ...) call.

#if(ANDROID)
#    set(ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/android")
#    if (ANDROID_ABI STREQUAL "armeabi-v7a")
#        set(ANDROID_EXTRA_LIBS
#            ${CMAKE_CURRENT_SOURCE_DIR}/path/to/libcrypto.so
#            ${CMAKE_CURRENT_SOURCE_DIR}/path/to/libssl.so)
#    endif()
#endif()

find_package(Qt5 COMPONENTS Widgets REQUIRED)
find_package(OpenCV REQUIRED) #追加

# 追加
include_directories(
 ${OpenCV_INCLUDE_DIRS} 
)
# ここまで

if(ANDROID)
  add_library(ddd SHARED
    main.cpp
    mainwindow.cpp
    mainwindow.h
    mainwindow.ui
  )
else()
  add_executable(ddd
    main.cpp
    mainwindow.cpp
    mainwindow.h
    mainwindow.ui
  )
endif()

target_link_libraries(ddd PRIVATE Qt5::Widgets
  ${OpenCV_LIBRARIES} #追加
)
```

4.結果

mainwindow widget内に設置した.labelにopencvで生成したmatイメージが表示されました。

![Screenshot from 2022-01-12 20-48-33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/589906/d00f3efa-6287-7656-2a99-9a49d1f24838.png)

### 3.上のデモ画像の色をsliderから変化

1.上のデモuiに`Horizontal Slider`を追加(maximunの値を99から255に変更) + `valueChanged`のslotを作成

2.`mainwindow.cpp`内に生成されたslotの関数内に以下のように記載

```c++:slot関数
void MainWindow::on_horizontalSlider_valueChanged(int value)
{
    cv::Mat_<cv::Vec3b> mat(300, 300, cv::Vec3b(0,value,0)); // 追加
    ui->label->setPixmap(QPixmap::fromImage(QImage((unsigned char*) mat.data, mat.cols, mat.rows, QImage::Format_RGB888))); // 追加
}
```

結果

![opencvdemo.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/589906/0582e1aa-284f-2203-5ebf-9e6cf44e739c.gif)

ui設定でちゃんと配列.

![opencvdemo2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/589906/6a79f4a1-17d6-e1a9-bc95-35c60ad56635.gif)

## canny

テスト画像ダウンロード

```
wget wget https://github.com/hoshianaaa/TestFiles/raw/master/gears/template.jpg
```

画像読み込み->labelに配置

```
    cv::Mat mat = cv::imread( "/home/hoshina/template.jpg"); // add
    ui->label->setPixmap(QPixmap::fromImage(QImage((unsigned char*) mat.data, mat.cols, mat.rows, mat.step, QImage::Format_RGB888))); // 追加
```

GrayScaleで読んで配置

```
    cv::Mat mat = cv::imread( "/home/hoshina/template.jpg",0); // add
    ui->label->setPixmap(QPixmap::fromImage(QImage((unsigned char*) mat.data, mat.cols, mat.rows, mat.step, QImage::Format_Indexed8))); // 追加
```

### cannyの2つのパラメータをスライドバーから変更

1.画像をダウンロード

```
wget https://github.com/hoshianaaa/TestFiles/raw/master/gears/search2.jpg
```

2.uiにスライド2個目追加
3.プログラムを以下のように変更

```c++:mainwindow.cpp

#include "mainwindow.h"
#include "./ui_mainwindow.h"

#include <opencv2/opencv.hpp> // 追加

#include <QPixmap> // 追加

using namespace cv; // add

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    originalImg = cv::imread( "/home/hoshina/search2.jpg",0); // add
    cv::Canny(originalImg, mat, 50, 100);
    ui->label->setPixmap(QPixmap::fromImage(QImage((unsigned char*) mat.data, mat.cols, mat.rows, mat.step, QImage::Format_Indexed8))); // 追加

}

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

void MainWindow::on_horizontalSlider_valueChanged(int value)
{
    cannyLowVal = value;
    cv::Canny(originalImg, mat, cannyLowVal, cannyHighVal);
    ui->label->setPixmap(QPixmap::fromImage(QImage((unsigned char*) mat.data, mat.cols, mat.rows, mat.step, QImage::Format_Indexed8))); // 追加
}

void MainWindow::on_horizontalSlider_2_valueChanged(int value)
{
    cannyHighVal = value;
    cv::Canny(originalImg, mat, cannyLowVal, cannyHighVal);
    ui->label->setPixmap(QPixmap::fromImage(QImage((unsigned char*) mat.data, mat.cols, mat.rows, mat.step, QImage::Format_Indexed8))); // 追加
}

```


```c++:mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

#include <opencv2/opencv.hpp> // 追加

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
private slots:
    void on_horizontalSlider_valueChanged(int value);

    void on_horizontalSlider_2_valueChanged(int value);

private:
    Ui::MainWindow *ui;
    cv::Mat originalImg, mat;
    int cannyLowVal, cannyHighVal;
};
#endif // MAINWINDOW_H

```

![opencvdemo3.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/589906/3fc748c0-295f-7fe2-47f0-1d193fac0642.gif)


## マウスクリック位置に描画

1.画像を貼り付けるlabelの余白が出ないようにバネを使って以下のようにuiを設定

![Screenshot from 2022-01-24 18-24-13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/589906/74df53d3-71a1-6366-2441-2209d46f7188.png)

2.プログラムを以下のように変更

```cpp:mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
    void mousePressEvent(QMouseEvent *event); // add

private:
    Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H

```

```cpp:mainwindow.cpp
#include "mainwindow.h"
#include "./ui_mainwindow.h"

#include <opencv2/opencv.hpp> // 追加

#include <QPixmap> // 追加

#include <QMouseEvent> // add
#include <QtCore/QDebug> // add

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

    cv::Mat_<cv::Vec3b> mat(300, 500, cv::Vec3b(0,200,0)); // 追加

    ui->label->setPixmap(QPixmap::fromImage(QImage((unsigned char*) mat.data, mat.cols, mat.rows, QImage::Format_RGB888))); // 追加
}

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

void MainWindow::mousePressEvent(QMouseEvent *event)
{
        // get mouse pos:
        // 参考: https://www.qtcentre.org/threads/3073-How-to-get-mouse-s-position
        QPoint p = ui->label->mapFromGlobal(QCursor::pos());
        qDebug() << "press:" << p;

        cv::Mat_<cv::Vec3b> mat(300, 500, cv::Vec3b(0,200,0)); // 追加
        cv::drawMarker(mat, cv::Point(p.x(),p.y()), cv::Vec3b(200,0,0), cv::MARKER_CROSS);

        ui->label->setPixmap(QPixmap::fromImage(QImage((unsigned char*) mat.data, mat.cols, mat.rows, QImage::Format_RGB888))); // 追加

}
```

これで,qtでクリックした位置をopencvの画像位置に変換できました(pixmapのscaleが変割った場合の対応はできていない)

![Screenshot from 2022-01-24 18-31-31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/589906/6596a9ba-ce6a-ac51-7905-a66eef779872.png)