ROS のビデオ画像への OpenCV (opencv_apps) の適用 (ハリス コーナー ポイントの検出に焦点を当てる)

1 はじめに

opencv_appsを使用すると ROS で最も簡単な方法でOpenCV が提供する多くの関数を実行できます。
詳細を詳しく知りたい場合は、ソース コードをチェックしてください。これは、視覚的な操作に慣れるのに非常に役立ちます。
公式説明: http://wiki.ros.org/opencv_apps
github ソースコード: https://github.com/ros-perception/opencv_apps

2. 運転開始

2.1、opencv_apps.launch 

まず、カメラやその他の関連操作を開始するには、opencv_apps.launchファイルを開始する必要があります。 

gedit /home/jetson/workspace/catkin_ws/src/jetbot_ros/launch/opencv_apps.launch
<launch>
    <arg name="img_flip" default="False"/>
    <arg name="img_transform" default="True"/>
    <group if="$(arg img_transform)">
        <arg name="img_topic" default="/csi_cam_0/image_raw"/>
        <include file="$(find jetson_nano_csi_cam)/launch/jetson_csi_cam.launch"/>
        <node name="img_transform" pkg="jetbot_ros" type="img_transform.py" output="screen">
            <param name="img_flip" type="bool" value="$(arg img_flip)"/>
            <param name="img_topic" type="string" value="$(arg img_topic)"/>
        </node>
    </group>
</launch>

ここで、 <include>ノードには、 jetson_csi_cam.launchスタートアップ ファイルとimg_transformという名前のノードが含まれています。jetson_csi_cam.launchの内容を見てみましょう

cat /home/jetson/workspace/catkin_ws/src/jetson_nano_csi_cam_ros/launch/jetson_csi_cam.launch

これには、いくつかのカメラ パラメータ設定とカメラの起動が含まれています。GStreamerイメージストリームは、GSCAMオープン ソース パッケージを通じて ROS に導入され、 sensor_msgs/Image typeのイメージトピックに変換され、他のノードで使用できるように ROS に公開されます。

2.2、img_transform.py

次に、これらの操作を実行するノードがあり、そのソース コードを見てみましょう。 

gedit /home/jetson/workspace/catkin_ws/src/jetbot_ros/scripts/img_transform.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import rospy
import cv2 as cv
from cv_bridge import CvBridge
from sensor_msgs.msg import Image

def topic(msg):
    if not isinstance(msg, Image):
        return
    bridge = CvBridge()
    frame = bridge.imgmsg_to_cv2(msg, "bgr8")
    # Canonical input image size
    frame = cv.resize(frame, (640, 480))
    if img_flip == True: frame = cv.flip(frame, 1)
    # opencv mat ->  ros msg
    msg = bridge.cv2_to_imgmsg(frame, "bgr8")
    pub_img.publish(msg)

if __name__ == '__main__':
    rospy.init_node("pub_img", anonymous=False)
    img_topic = rospy.get_param("~img_topic", "/csi_cam_0/image_raw")
    img_flip = rospy.get_param("~img_flip", False)
    sub_img = rospy.Subscriber(img_topic, Image, topic)
    pub_img = rospy.Publisher("/image", Image, queue_size=10)
    rate = rospy.Rate(2)
    rospy.spin()

ここでは、pub_imgノードを定義し、CSI カメラに関連するトピックをサブスクライブし、他のノードで使用できるようにImageトピックを通じてそれらを公開します。このうち、rospy.get_param("~img_topic", "/csi_cam_0/image_raw") でパラメータを取得します。 ~img_topicで取得できない場合は、デフォルト値の/csi_cam_0/image_rawを使用します。同様に、rospy.get_param("~img_flip", False) は、 ~img_flipの値が取得されない場合、デフォルトでFalseになります。

2.3. カメラを開く

カメラの関連操作に慣れたら、次に示すように、いくつかの準備作業を行ってカメラをオンにします:
roslaunch Jetbot_ros opencv_apps.launch
表示モード: rqt_image_view :

または、Web ページrosrun web_video_server web_video_server
を表示し、次に示すように、IP+ポートを使用して表示します。

次に、内部のトピックをクリックすると、以下に示すようにカメラ ビデオが表示されます。

どのようなトピックが開かれているかを見てみましょう: rostopic リスト 

/csi_cam_0/camera_info
/csi_cam_0/image_raw
/csi_cam_0/image_raw/compressed
/csi_cam_0/image_raw/compressed/parameter_descriptions
/csi_cam_0/image_raw/compressed/parameter_updates
/csi_cam_0/image_raw/compressedDepth
/csi_cam_0/image_raw/compressedD epth/parameter_descriptions
/csi_cam_0/image_raw/compressedDepth /parameter_updates
/csi_cam_0/image_raw/theora
/csi_cam_0/image_raw/theora/parameter_descriptions
/csi_cam_0/image_raw/theora/parameter_updates
/image
/rosout
/rosout_agg 

これらは CSI カメラに関連するいくつかのトピックですが、次に、その中の多数の例をデモンストレーションします。 

3. ハリスコーナー

私たちはすべてopencv_appsパッケージ内にいるため、最初にワークスペース内のパッケージの起動ディレクトリに移動します。
どのような起動ファイルがあるかを確認します: ls /home/jetson/workspace/catkin_ws/src/opencv_apps/launch/

 add_images.launch hough_circles.launch
camshift.launch hough_lines.launch
contour_moments.launch hsv_color_filter.launch
convex_hull.launch lk_flow.launch Corner_harris.launch
people_detect.launch
discrete_fourier_transform.launch
Phase_corr.launchedge_detection.launch ピラミッド
s.launch face_detection.launch rgb_ color_filter.
顔認識を起動します。起動segment_objects.launch
fback_flow.launch simple_flow.launch
find_contours.launch smoothing.launch
general_contours.launch Threshold.launch
Goodfeature_track.launch Watershed_segmentation.launch
hls_color_filter.launch

ハフ円、ハフ線、輪郭モーメント、LKオプティカルフロー、ハリスコーナーポイント、エッジ、文字、顔認識など、画像加工のための機能がかなり充実していることがわかります。

3.1、corner_harris.launch

ある点が画像の角点であるかどうかを判断するために、ここでは対角点の検出に焦点を当てて説明します。基本的には次のノードが表示されます。
roslaunch opencv_apps Corner_harris.launch は
次のように開始され、チェッカーボード形式の画像を使用して認識されます。


画像内のコーナーポイントが多数の小さな丸でマークされていることがわかります。ここでのコーナーポイントの検出の数と精度は、上記のしきい値に依存します。それは自分で調整できます。値を小さくすると、コーナーポイントの数が増加します。コーナーポイントの数が多くなると相対的に精度が低下しますが、閾値を大きくするとその分コーナーポイントの数が減り、精度が高くなります。 

この起動ファイルの内容を見てみましょう。

cat  /home/jetson/workspace/catkin_ws/src/opencv_apps/launch/corner_harris.launch
<launch>
  <arg name="node_name" default="corner_harris" />

  <arg name="image" default="image" doc="The image topic. Should be remapped to the name of the real image topic." />

  <arg name="use_camera_info" default="false" doc="Indicates that the camera_info topic should be subscribed to to get the default input_frame_id. Otherwise the frame from the image message will be used." />
  <arg name="debug_view" default="true" doc="Specify whether the node displays a window to show image" />
  <arg name="queue_size" default="3" doc="Specigy queue_size of input image subscribers" />

  <arg name="threshold" default="200" doc="Threshold value of a circle around corners's norm" />

  <!-- corner_harris.cpp  -->
  <node name="$(arg node_name)" pkg="opencv_apps" type="corner_harris" >
    <remap from="image" to="$(arg image)" />
    <param name="use_camera_info" value="$(arg use_camera_info)" />
    <param name="debug_view" value="$(arg debug_view)" />
    <param name="queue_size" value="$(arg queue_size)" />
  </node>
</launch>

3.2、corner_harris.cpp

手前がいくつかのパラメータ設定、奥がノードノード部分ですが、このうちtype="corner_harris"はPythonで書くとtype=という形になるのでC++で書かれたことが分かります。もちろん、「corner_harris.py」もあります。 コメントでは、これがcorner_harris.cpp
のC++コードファイルのアドレスであると説明しています: ls /home/jetson/workspace/catkin_ws/build/opencv_apps
実際のコードを見てみましょうこの Harris コーナー:
gedit /home/jetson/workspace/catkin_ws/ build/opencv_apps/corner_harris.cpp 

/*********************************************************************
* Software License Agreement (BSD License)
*
*  Copyright (c) 2016, Kentaro Wada.
*  All rights reserved.
*
*  Redistribution and use in source and binary forms, with or without
*  modification, are permitted provided that the following conditions
*  are met:
*
*   * Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*   * Redistributions in binary form must reproduce the above
*     copyright notice, this list of conditions and the following
*     disclaimer in the documentation and/or other materials provided
*     with the distribution.
*   * Neither the name of the Kentaro Wada nor the names of its
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
*  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
*  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
*  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
*  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
*  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
*  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
*  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
*  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
*  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
*  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
*  POSSIBILITY OF SUCH DAMAGE.
*********************************************************************/

#include <ros/ros.h>
#include <nodelet/loader.h>

int main(int argc, char **argv)
{
    ros::init(argc, argv, "corner_harris", ros::init_options::AnonymousName);
    if (ros::names::remap("image") == "image") {
        ROS_WARN("Topic 'image' has not been remapped! Typical command-line usage:\n"
                 "\t$ rosrun image_rotate image_rotate image:=<image topic> [transport]");
    }

    // need to use 1 worker thread to prevent freezing in imshow, calling imshow from mutiple threads
    //nodelet::Loader manager(false);
    ros::param::set("~num_worker_threads", 1); // need to call   Loader(bool provide_ros_api = true);
    nodelet::Loader manager(true);
    nodelet::M_string remappings;
    nodelet::V_string my_argv(argv + 1, argv + argc);
    my_argv.push_back("--shutdown-on-close"); // Internal

    manager.load(ros::this_node::getName(), "opencv_apps/corner_harris", remappings, my_argv);

    ros::spin();
    return 0;
}

このコードは、 corner_harrisノードを初期化し画像トピックなどを再マップし、円を使用して角をマークするものです。この操作では、次に説明するプラグインを使用します。

3.3、corner_harris_nodelet.cpp

上記のコア コードはNodeletを使用します。このNodeletプラグインの説明:
ユーザーは ROS ノードにカスタム関数を追加できます。Nodelet を使用すると、開発者は複雑なコードを再利用可能なプラグインにカプセル化できます。これらのプラグインは他の ROS と同様に使用できますノードは同じ方法で展開して通信するため、開発者はよりモジュール化された保守しやすいコードを作成でき、ROS システムのスケーラビリティと再利用性が向上します。
より重要な問題は効率です。Nodelet は、複数のアルゴリズム プログラムが 1 つのプロセスで共有ポインターshared_ptr を使用してゼロコピー通信を実現し、コピーによる大きなデータ (イメージ ストリーム、点群など) の送信の必要性を軽減する方法を提供します。レイテンシの問題については、つまり、複数のノードを束ねて管理することで、同一マネージャ内のトピックのデータ送信が高速化されます。これは、ノード内でメッセージを配信する際のコピーによる効率の低下がないためです。プロセス。 

プラグイン ファイルを表示します: ls /home/jetson/workspace/catkin_ws/src/opencv_apps/src/nodelet
Harris Corner のプラグイン コードを開いて見てみましょう。

gedit /home/jetson/workspace/catkin_ws/src/opencv_apps/src/nodelet/corner_harris_nodelet.cpp

 

// -*- coding:utf-8-unix; mode: c++; indent-tabs-mode: nil; c-basic-offset: 2; -*-
/*********************************************************************
* Software License Agreement (BSD License)
*
*  Copyright (c) 2016, JSK Lab.
*  All rights reserved.
*
*  Redistribution and use in source and binary forms, with or without
*  modification, are permitted provided that the following conditions
*  are met:
*
*   * Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*   * Redistributions in binary form must reproduce the above
*     copyright notice, this list of conditions and the following
*     disclaimer in the documentation and/or other materials provided
*     with the distribution.
*   * Neither the name of the Kei Okada nor the names of its
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
*  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
*  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
*  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
*  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
*  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
*  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
*  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
*  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
*  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
*  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
*  POSSIBILITY OF SUCH DAMAGE.
*********************************************************************/
#include <ros/ros.h>
#include "opencv_apps/nodelet.h"
#include <image_transport/image_transport.h>
#include <sensor_msgs/image_encodings.h>
#include <cv_bridge/cv_bridge.h>

#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>

#include <dynamic_reconfigure/server.h>
#include "opencv_apps/CornerHarrisConfig.h"

// https://github.com/opencv/opencv/blob/master/samples/cpp/tutorial_code/TrackingMotion/cornerHarris_Demo.cpp
/**
 * @function cornerHarris_Demo.cpp
 * @brief Demo code for detecting corners using Harris-Stephens method
 * @author OpenCV team
 */

namespace opencv_apps
{
class CornerHarrisNodelet : public opencv_apps::Nodelet
{
  image_transport::Publisher img_pub_;
  image_transport::Subscriber img_sub_;
  image_transport::CameraSubscriber cam_sub_;
  ros::Publisher msg_pub_;

  boost::shared_ptr<image_transport::ImageTransport> it_;

  typedef opencv_apps::CornerHarrisConfig Config;
  typedef dynamic_reconfigure::Server<Config> ReconfigureServer;
  Config config_;
  boost::shared_ptr<ReconfigureServer> reconfigure_server_;

  int queue_size_;
  bool debug_view_;

  std::string window_name_;
  static bool need_config_update_;

  int threshold_;

  void reconfigureCallback(Config& new_config, uint32_t level)
  {
    config_ = new_config;
    threshold_ = config_.threshold;
  }

  const std::string& frameWithDefault(const std::string& frame, const std::string& image_frame)
  {
    if (frame.empty())
      return image_frame;
    return frame;
  }

  void imageCallbackWithInfo(const sensor_msgs::ImageConstPtr& msg, const sensor_msgs::CameraInfoConstPtr& cam_info)
  {
    doWork(msg, cam_info->header.frame_id);
  }

  void imageCallback(const sensor_msgs::ImageConstPtr& msg)
  {
    doWork(msg, msg->header.frame_id);
  }

  static void trackbarCallback(int /*unused*/, void* /*unused*/)
  {
    need_config_update_ = true;
  }

  void doWork(const sensor_msgs::ImageConstPtr& image_msg, const std::string& input_frame_from_msg)
  {
    // Work on the image.
    try
    {
      // Convert the image into something opencv can handle.
      cv::Mat frame = cv_bridge::toCvShare(image_msg, sensor_msgs::image_encodings::BGR8)->image;

      // Do the work
      cv::Mat dst, dst_norm, dst_norm_scaled;
      dst = cv::Mat::zeros(frame.size(), CV_32FC1);

      cv::Mat src_gray;

      if (frame.channels() > 1)
      {
        cv::cvtColor(frame, src_gray, cv::COLOR_BGR2GRAY);
      }
      else
      {
        src_gray = frame;
        cv::cvtColor(src_gray, frame, cv::COLOR_GRAY2BGR);
      }

      /// Detector parameters
      int block_size = 2;
      int aperture_size = 3;
      double k = 0.04;

      /// Detecting corners
      cv::cornerHarris(src_gray, dst, block_size, aperture_size, k, cv::BORDER_DEFAULT);

      /// Normalizing
      cv::normalize(dst, dst_norm, 0, 255, cv::NORM_MINMAX, CV_32FC1, cv::Mat());
      cv::convertScaleAbs(dst_norm, dst_norm_scaled);

      /// Drawing a circle around corners
      for (int j = 0; j < dst_norm.rows; j++)
      {
        for (int i = 0; i < dst_norm.cols; i++)
        {
          if ((int)dst_norm.at<float>(j, i) > threshold_)
          {
            cv::circle(frame, cv::Point(i, j), 5, cv::Scalar(0), 2, 8, 0);
          }
        }
      }

      /// Create window
      if (debug_view_)
      {
        cv::namedWindow(window_name_, cv::WINDOW_AUTOSIZE);
        const int max_threshold = 255;
        if (need_config_update_)
        {
          config_.threshold = threshold_;
          reconfigure_server_->updateConfig(config_);
          need_config_update_ = false;
        }
        cv::createTrackbar("Threshold:", window_name_, &threshold_, max_threshold, trackbarCallback);
      }

      if (debug_view_)
      {
        cv::imshow(window_name_, frame);
        int c = cv::waitKey(1);
      }

      // Publish the image.
      sensor_msgs::Image::Ptr out_img =
          cv_bridge::CvImage(image_msg->header, sensor_msgs::image_encodings::BGR8, frame).toImageMsg();
      img_pub_.publish(out_img);
    }
    catch (cv::Exception& e)
    {
      NODELET_ERROR("Image processing error: %s %s %s %i", e.err.c_str(), e.func.c_str(), e.file.c_str(), e.line);
    }
  }

  void subscribe()  // NOLINT(modernize-use-override)
  {
    NODELET_DEBUG("Subscribing to image topic.");
    if (config_.use_camera_info)
      cam_sub_ = it_->subscribeCamera("image", queue_size_, &CornerHarrisNodelet::imageCallbackWithInfo, this);
    else
      img_sub_ = it_->subscribe("image", queue_size_, &CornerHarrisNodelet::imageCallback, this);
  }

  void unsubscribe()  // NOLINT(modernize-use-override)
  {
    NODELET_DEBUG("Unsubscribing from image topic.");
    img_sub_.shutdown();
    cam_sub_.shutdown();
  }

public:
  virtual void onInit()  // NOLINT(modernize-use-override)
  {
    Nodelet::onInit();
    it_ = boost::shared_ptr<image_transport::ImageTransport>(new image_transport::ImageTransport(*nh_));

    pnh_->param("queue_size", queue_size_, 3);
    pnh_->param("debug_view", debug_view_, false);

    if (debug_view_)
    {
      always_subscribe_ = true;
    }

    window_name_ = "CornerHarris Demo";

    reconfigure_server_ = boost::make_shared<dynamic_reconfigure::Server<Config> >(*pnh_);
    dynamic_reconfigure::Server<Config>::CallbackType f =
        boost::bind(&CornerHarrisNodelet::reconfigureCallback, this, _1, _2);
    reconfigure_server_->setCallback(f);

    img_pub_ = advertiseImage(*pnh_, "image", 1);

    onInitPostProcess();
  }
};
bool CornerHarrisNodelet::need_config_update_ = false;
}  // namespace opencv_apps

namespace corner_harris
{
class CornerHarrisNodelet : public opencv_apps::CornerHarrisNodelet
{
public:
  virtual void onInit()  // NOLINT(modernize-use-override)
  {
    ROS_WARN("DeprecationWarning: Nodelet corner_harris/corner_harris is deprecated, "
             "and renamed to opencv_apps/corner_harris.");
    opencv_apps::CornerHarrisNodelet::onInit();
  }
};
}  // namespace corner_harris

#include <pluginlib/class_list_macros.h>
PLUGINLIB_EXPORT_CLASS(opencv_apps::CornerHarrisNodelet, nodelet::Nodelet);
PLUGINLIB_EXPORT_CLASS(corner_harris::CornerHarrisNodelet, nodelet::Nodelet);

主にコーナーポイントを検出する方法に焦点を当てます。

cv::cornerHarris(src_gray, dst, block_size, aperture_size, k, cv::BORDER_DEFAULT);

パラメータの説明は次のとおりです。

src_gray : 入力グレーマット行列または浮動小数点イメージ
dst : ソースイメージと同じサイズおよびタイプのハリスコーナー検出の結果を格納
block_size : 近傍のサイズ
aperture_size : ソーベルエッジ検出フィルターサイズ
k : ハリス中間パラメーター、経験的value 0.04~0.06
cv::BORDER_DEFAULT : 補間タイプ

また、パブリッシュおよびサブスクライブ時にポインターが使用されることもわかります。
出版時:

sensor_msgs::Image::Ptr out_img =cv_bridge::CvImage(image_msg->header, sensor_msgs::image_encodings::BGR8, frame).toImageMsg();
img_pub_.publish(out_img);

購読する場合:

Nodelet::onInit();
it_ = boost::shared_ptr<image_transport::ImageTransport>(new image_transport::ImageTransport(*nh_));

if (config_.use_camera_info)
      cam_sub_ = it_->subscribeCamera("image", queue_size_, &CornerHarrisNodelet::imageCallbackWithInfo, this);
    else
      img_sub_ = it_->subscribe("image", queue_size_, &CornerHarrisNodelet::imageCallback, this);

このように、メッセージを渡すときにポインタを渡すだけで済みます。もちろん、これは同じデバイスに対するプロセス間通信です。異なるデバイスの場合は、実際の送信内容を逆参照する必要があります。 ROS 分散ノードが通信するためのプロトコルはXML-RPCであり、本質的にはHTTPプロトコルですが、エンコード形式はXMLタイプであり、ノード間の送信では通信用のコンテンツをコピーする必要があります。

ノードの関係を表示します: rqt_graph . 以下に示すように、わかりやすくするためにここではデバッグ ノードを非表示にします。

CSI カメラの画像取得を変換し、最終的に/Imageトピックを介して処理するためにHarris コーナー アルゴリズムにリリースする必要があることがわかります。 

コーナー ポイントを識別する原理は、機能ウィンドウでグレースケールが大幅に変化した場合、それがコーナー ポイントであるとみなされるというだけです。興味がある場合は、harris.cpp を確認してください

4. ハフ線形検出

次のパートでは、上記のような分析は行わず、一般的に使用されるいくつかの関数について理解するだけです。
ハフ ラインの検出はコンピューター ビジョンや画像処理で広く使用されており、エッジ検出やライン検出などに使用できます。
実際のシーンでは、画像からエッジを検出し、直線または曲線を識別して接続して完全なオブジェクトを形成できます。
さらに、無人運転の開発は、道路や車線の自動検出などの用途にも広く使用されています。
起動ファイルを開始します。roslaunch opencv_apps hough_lines.launch は
、以下に示すように、私の体の衣服とその上にある「中国」のテキストを非常によく検出しました。

5. 画像輪郭モーメント

contour_moments.launchは画像の輪郭認識を開始するモーメント関数です. ここでの輪郭モーメントは輪郭の特徴として捉えることもできます.
対象認識: 物体の輪郭特徴の抽出などにも応用できます.画像内でターゲットを識別し、分類することができます。
ターゲット検出: オブジェクトの形状と輪郭を検出してターゲットの位置を決定します。
画像のセグメンテーション: さまざまな領域でターゲットを識別できるため、画像のセグメント化にも役立ちます。
医療分野:画像内の組織、臓器、患部を識別し、特徴を抽出し、医療診断を行うことができます。
以下に示すように、起動: roslaunch opencv_apps contour_moments.launch :

6.LKオプティカルフロー 

LK オプティカル フローは、ターゲットの動きを記述する方法であり、ターゲットを追跡することでターゲットの姿勢を知ることができます。
LK オプティカル フロー法の前提条件は次のとおりです。
一定の明るさ: ピクセルが時間の経過とともに変化しても、その明るさの値 (ピクセルのグレー値) は変化しません。
小さな動き: 時間の変化によって位置が急激に変化することはありません。このようにして、隣接するフレーム間の位置変化によって引き起こされるグレー値の変化を使用して、位置に関するグレー値の偏導関数を取得することができる。
空間的一貫性: 前のフレームの隣接ピクセルは次のフレームでも隣接します。これは、x 方向と y 方向の速度を解決するには、方程式系を確立する必要があり、空間的一貫性仮説は n を使用して確立できるためです。近傍のピクセル n 個の方程式。
以下に示すように、起動: roslaunch opencv_apps lk_flow.launch :

7. カメラの位相シフト

カメラの移動速度、または内部のターゲットの移動速度を検出します。以下に示すように、roslaunch opencv_appsphase_corr.launch
を起動します。

速く動けば動くほど円は大きくなる

一般的な紹介はここまでにします。興味がある場合は、OpenCV に関する他の記事をチェックしてください: OpenCV
独自の HAAR カスケード分類器による顔 (人間の顔、猫の顔など) の検出と認識
OpenCV の HSV 色空間 色認識のアプリケーション自動運転車の中で

おすすめ

転載: blog.csdn.net/weixin_41896770/article/details/134284539