四角形・矩形を描く【道具としての OpenCV 画像認識】

# 本記事でできること
![Screenshot from 2024-03-03 15-24-21.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37698/7b105066-98da-f601-3aad-5b3d4627b9c3.png)


# 想定シーン
## ロボットをビジュアルフィードバック制御する
カメラを使ったロボットアームの制御方法を、ビジュアルフィードバック制御といいます。ここでは、ビジュアルフィードバック制御を使った自動化システムを開発する際に必要となる画像認識プログラムをまとめています。

## 四角形・矩形を描く
画像認識を使用してロボット制御をする場合に、認識対象物体について、カメラ画像内での位置と姿勢を描画したくなることがあります。特にロボットの手先にカメラを装備して制御する「ハンドアイ」構成の場合に多くあります。本記事では、回転を含む矩形（四角形）の描画と、回転を含まない矩形の描画を行うプログラムを掲載します。


# 実行環境
- OS：Ubuntu 22.04 LTS
- 言語：C++
- クルーボ：v5.1.0

## クルーボについて
ロボットアプリケーション開発には、株式会社チトセロボティクスのロボット制御ソフトウェア「クルーボ」を使用します。本記事のプログラムは、クルーボがインストールされた制御コンピュータ上で動作します。

- クルーボの製品サイト：https://chitose-robotics.com/product

## プログラム抜粋
```c++
cv::Mat draw_rectangle(
        const cv::Mat image,
        const cv::Point start,
        const cv::Point finish,
        const cv::Scalar color,
        const int thickness) {
    cv::Mat drawed_image = image.clone();
    cv::rectangle(drawed_image, start, finish, color, thickness, cv::LINE_4);
    return drawed_image;
}

cv::Mat draw_rotated_rectangle(
        const cv::Mat image, const cv::RotatedRect rotated_rect, const cv::Scalar color, const int thickness) {
    cv::Mat drawed_image = image.clone();
    cv::Point2f vertexes[4];
    rotated_rect.points(vertexes);
    for (int i = 0; i < 4; i++) {
        cv::line(drawed_image, vertexes[i], vertexes[i + 1 < 4 ? i + 1 : 0], color, thickness, cv::LINE_4);
    }
    return drawed_image;
}
```

## 全体プログラム
```c++
#include <iostream>
#include <opencv2/opencv.hpp>

cv::Mat draw_rectangle(
        const cv::Mat image,
        const cv::Point start,
        const cv::Point finish,
        const cv::Scalar color,
        const int thickness) {
    cv::Mat drawed_image = image.clone();
    cv::rectangle(drawed_image, start, finish, color, thickness, cv::LINE_4);
    return drawed_image;
}

cv::Mat draw_rotated_rectangle(
        const cv::Mat image, const cv::RotatedRect rotated_rect, const cv::Scalar color, const int thickness) {
    cv::Mat drawed_image = image.clone();
    cv::Point2f vertexes[4];
    rotated_rect.points(vertexes);
    for (int i = 0; i < 4; i++) {
        cv::line(drawed_image, vertexes[i], vertexes[i + 1 < 4 ? i + 1 : 0], color, thickness, cv::LINE_4);
    }
    return drawed_image;
}

int main(void) {
    const cv::Size image_size(1280, 960);
    const cv::Mat black_image = cv::Mat::zeros(image_size.height, image_size.width, CV_8UC3);

    cv::Mat drawed_image = black_image.clone();

    const cv::Point start_point = cv::Point(200, 300);
    const cv::Point finish_point = cv::Point(500, 700);
    const cv::Scalar rectangle_color = cv::Scalar(255, 180, 255);
    const int rectangle_thickness = 5;

    drawed_image = draw_rectangle(drawed_image, start_point, finish_point, rectangle_color, rectangle_thickness);

    const cv::RotatedRect rotated_rect = cv::RotatedRect(cv::Point2f(800.f, 500.f), cv::Size(180, 140), 30.f);
    const cv::Scalar rotated_rectangle_color = cv::Scalar(0, 0, 255);

    drawed_image = draw_rotated_rectangle(drawed_image, rotated_rect, rotated_rectangle_color, rectangle_thickness);

    cv::imshow("drawed_image", drawed_image);
    cv::waitKey(0);
}
```

## おわりに
人手作業をロボットアームで自動化するために、カメラを使ったロボット制御＝ビジュアルフィードバック制御が大切です。
ロボット制御用の画像認識でも中身のひとつひとつはシンプルなので、要素に分解して解説していきたいと思います。