gstreamer - 使用 gstreamercameraun Distor 插件计算畸变系数

标签 gstreamer distortion

如何使用失真系数 已经使用特定的Python代码(dist [[7.33183864e+03 1.52395233e-01 2.53983049e+00 2.20587897e+00 2.61869010e-06]] )和cameraun Distor插件计算出来。

我在文档中看到了以下示例管道:

gst-launch-1.0 -v v4l2src ! videoconvert ! cameraundistort settings=  !  autovideosink 

但是我不知道我应该给设置提供什么样的参数,是这样吗? 我应该把计算出的失真系数或矩阵放在哪里?

最佳答案

新答案:

我最终找到了如何从命令行执行此操作。您需要使用自己的矩阵值编辑 DATA 变量中的值:

在 Ubuntu 20.04 上测试。与运行标准 gst-launch-1.0 -vv videotestsrc ! videoconvert ! autovideosink 相比,您应该看到扭曲的 videotestsrc

DATA="<?xml version=\"1.0\"?><opencv_storage><cameraMatrix type_id=\"opencv-matrix\"><rows>3</rows><cols>3</cols><dt>f</dt><data>2.85762378e+03 0. 1.93922961e+03 0. 2.84566113e+03 1.12195850e+03 0. 0. 1.</data></cameraMatrix><distCoeffs type_id=\"opencv-matrix\"><rows>5</rows><cols>1</cols><dt>f</dt><data>-6.14039421e-01 4.00045455e-01 1.47132971e-03 2.46772077e-04 -1.20407566e-01</data></distCoeffs></opencv_storage>"

gst-launch-1.0 -vv videotestsrc ! videoconvert ! cameraundistort settings="$DATA" ! videoconvert ! autovideosink

原始分析:

我也在尝试寻找这个问题的答案。

基于此处的以下代码:https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/blob/324e55a3cdd7c6cef24356fd626deee5fba343df/ext/opencv/gstcameracalibrate.cpp

有一个片段:

/* set settings property */
g_free (calib->settings);
calib->settings =
camera_serialize_undistort_settings (calib->cameraMatrix,
calib->distCoeffs);

这将我们引向这个函数:https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/blob/324e55a3cdd7c6cef24356fd626deee5fba343df/ext/opencv/camerautils.cpp

gchar *
camera_serialize_undistort_settings (cv::Mat & cameraMatrix,
    cv::Mat & distCoeffs)
{
  cv::FileStorage fs (".xml", cv::FileStorage::WRITE + cv::FileStorage::MEMORY);
  fs << "cameraMatrix" << cameraMatrix;
  fs << "distCoeffs" << distCoeffs;
  std::string buf = fs.releaseAndGetString ();

  return g_strdup (buf.c_str ());
}

为了了解其输出,我编写了以下代码:

//
// g++ -o out main.cpp `pkg-config --cflags --libs opencv4 glib-2.0`
//
// https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/blob/324e55a3cdd7c6cef24356fd626deee5fba343df/ext/opencv/camerautils.cpp
//

#include <glib.h>
#include <opencv2/opencv.hpp>
#include <iostream>

gchar *
camera_serialize_undistort_settings (cv::Mat & cameraMatrix,
    cv::Mat & distCoeffs)
{
  cv::FileStorage fs (".xml", cv::FileStorage::WRITE + cv::FileStorage::MEMORY);
  fs << "cameraMatrix" << cameraMatrix;
  fs << "distCoeffs" << distCoeffs;
  std::string buf = fs.releaseAndGetString ();

  return g_strdup (buf.c_str ());
}

int main() {

    float camera_matrix_data[9] = { 2.8576236805989838e+03, 0.0, 1.9392296211154603e+03,
            0.0, 2.8456611938133528e+03, 1.1219585111073625e+03, 0.0,
            0.0, 1.0 };

    cv::Mat camera_matrix = cv::Mat(3, 3, CV_32F, camera_matrix_data);

    float dist_coefficients_data[5] = {-6.1403941690071129e-01, 4.0004545823187132e-01,
            1.4713297080556295e-03, 2.4677208656274745e-04,
            -1.2040756970288242e-01};

    cv::Mat dist_coefficients = cv::Mat(5, 1, CV_32F, dist_coefficients_data);
    
    std::cout << camera_serialize_undistort_settings(camera_matrix, dist_coefficients);

    return 0;
}

我得到了这个输出,据我所知,它对于 camera_deserialize_undistort_settings() 函数的使用是有效的:

<?xml version="1.0"?>
<opencv_storage>
<cameraMatrix type_id="opencv-matrix">
  <rows>3</rows>
  <cols>3</cols>
  <dt>f</dt>
  <data>
    2.85762378e+03 0. 1.93922961e+03 0. 2.84566113e+03 1.12195850e+03 0.
    0. 1.</data></cameraMatrix>
<distCoeffs type_id="opencv-matrix">
  <rows>5</rows>
  <cols>1</cols>
  <dt>f</dt>
  <data>
    -6.14039421e-01 4.00045455e-01 1.47132971e-03 2.46772077e-04
    -1.20407566e-01</data></distCoeffs>
</opencv_storage>

不幸的是,我无法克服将其输入命令行的最后一个障碍。

编辑:

非命令行解决方案:

希望以下内容能对某人有所帮助 - 由于时间限制,它有点被拼凑在一起。基本上我放弃了命令行并找到了如何通过代码运行 gstreamer 管道的示例。我侵入了管道并能够输入参数。

校准

//
// g++ play.cpp -o play `pkg-config --cflags --libs gstreamer-1.0 opencv4`
//

#include <gst/gst.h>
#include <opencv2/opencv.hpp>


//
// USB Webcam
//
const char *string2 = " \
gst-launch-1.0 -v v4l2src device=/dev/video0 ! videoconvert ! cameraundistort name=undist ! cameracalibrate name=cal ! ximagesink \
";


gchar *
camera_serialize_undistort_settings (cv::Mat & cameraMatrix,
    cv::Mat & distCoeffs)
{
  cv::FileStorage fs (".xml", cv::FileStorage::WRITE + cv::FileStorage::MEMORY);
  fs << "cameraMatrix" << cameraMatrix;
  fs << "distCoeffs" << distCoeffs;
  std::string buf = fs.releaseAndGetString ();

  return g_strdup (buf.c_str ());
}

int
main (int argc, char *argv[])
{

  gchar value[100] = {0};

  GstElement *pipeline;
  GstElement *filesrc;
  GstMessage *msg;
  GstBus *bus;
  GError *error = NULL;

  gst_init (&argc, &argv);

  pipeline = gst_parse_launch (string2, &error);



  if (!pipeline) {
    g_print ("Parse error: %s\n", error->message);
    exit (1);
  }



  gst_element_set_state (pipeline, GST_STATE_PLAYING);

  bus = gst_element_get_bus (pipeline);

  /* wait until we either get an EOS or an ERROR message. Note that in a real
   * program you would probably not use gst_bus_poll(), but rather set up an
   * async signal watch on the bus and run a main loop and connect to the
   * bus's signals to catch certain messages or all messages */
  msg = gst_bus_poll (bus, (GstMessageType) ( GST_MESSAGE_EOS | GST_MESSAGE_ERROR ), -1);

  switch (GST_MESSAGE_TYPE (msg)) {
    case GST_MESSAGE_EOS: {
      g_print ("EOS\n");
      break;
    }
    case GST_MESSAGE_ERROR: {
      GError *err = NULL; /* error to show to users                 */
      gchar *dbg = NULL;  /* additional debug string for developers */

      gst_message_parse_error (msg, &err, &dbg);
      if (err) {
          filesrc = gst_bin_get_by_name (GST_BIN (pipeline), "undist");

        gchar *val;

        g_object_get (filesrc, "settings", &val, NULL);
        
        g_print("Data:\n");

        g_print ("%s", val);

        g_object_unref (filesrc);

        g_print("\nDone\n");

        g_printerr ("ERROR: %s\n", err->message);
        g_error_free (err);
      }
      if (dbg) {
        g_printerr ("[Debug details: %s]\n", dbg);
        g_free (dbg);
      }
    }
    default:
      g_printerr ("Unexpected message of type %d", GST_MESSAGE_TYPE (msg));
      break;
  }
  gst_message_unref (msg);


  gst_element_set_state (pipeline, GST_STATE_NULL);
  gst_object_unref (pipeline);
  gst_object_unref (bus);

  return 0;
}

您可以按照 opencv 推荐的方式使用棋盘进行正常校准。

关闭时,这将给出如下输出:

<?xml version="1.0"?>
<opencv_storage>
<cameraMatrix type_id="opencv-matrix">
  <rows>3</rows>
  <cols>3</cols>
  <dt>d</dt>
  <data>
    3.3860583405334381e+02 0. 2.9082938038777263e+02 0.
    3.3860583405334381e+02 1.5389814447354675e+02 0. 0. 1.</data></cameraMatrix>
<distCoeffs type_id="opencv-matrix">
  <rows>5</rows>
  <cols>1</cols>
  <dt>d</dt>
  <data>
    -7.3120392823523372e-01 6.2624904277006888e-01
    -1.0205399762451621e-02 5.1857216532169093e-03
    -2.0130033675444331e-01</data></distCoeffs>
</opencv_storage>

然后您可以将其放入另一个程序并按如下方式加载:

正在运行

//
// g++ play.cpp -o play `pkg-config --cflags --libs gstreamer-1.0 opencv4`
//

#include <gst/gst.h>
#include <opencv2/opencv.hpp>


const char *string2 = " \
gst-launch-1.0 -v v4l2src device=/dev/video0 ! videoconvert ! cameraundistort name=undist1 ! ximagesink \
";


gchar *
camera_serialize_undistort_settings (cv::Mat & cameraMatrix,
    cv::Mat & distCoeffs)
{
  cv::FileStorage fs (".xml", cv::FileStorage::WRITE + cv::FileStorage::MEMORY);
  fs << "cameraMatrix" << cameraMatrix;
  fs << "distCoeffs" << distCoeffs;
  std::string buf = fs.releaseAndGetString ();

  return g_strdup (buf.c_str ());
}

int
main (int argc, char *argv[])
{

    float camera_matrix_data[9] = { 3.3860583405334381e+02, 0., 2.9082938038777263e+02, 0.,
    3.3860583405334381e+02, 1.5389814447354675e+02, 0., 0., 1. };

    cv::Mat camera_matrix = cv::Mat(3, 3, CV_32F, camera_matrix_data);

    float dist_coefficients_data[5] = {-7.3120392823523372e-01, 6.2624904277006888e-01,
    -1.0205399762451621e-02, 5.1857216532169093e-03,
    -2.0130033675444331e-01};

    cv::Mat dist_coefficients = cv::Mat(5, 1, CV_32F, dist_coefficients_data);

    gchar * dist = camera_serialize_undistort_settings(camera_matrix, dist_coefficients);

  GstElement *pipeline;
  GstElement *filesrc;
  GstMessage *msg;
  GstBus *bus;
  GError *error = NULL;

  gst_init (&argc, &argv);

  pipeline = gst_parse_launch (string2, &error);



  if (!pipeline) {
    g_print ("Parse error: %s\n", error->message);
    exit (1);
  }

  // Feed in our settings
  filesrc = gst_bin_get_by_name (GST_BIN (pipeline), "undist1");
  g_object_set (filesrc, "settings", dist, NULL);
  g_object_unref (filesrc);


  gst_element_set_state (pipeline, GST_STATE_PLAYING);

  bus = gst_element_get_bus (pipeline);

  /* wait until we either get an EOS or an ERROR message. Note that in a real
   * program you would probably not use gst_bus_poll(), but rather set up an
   * async signal watch on the bus and run a main loop and connect to the
   * bus's signals to catch certain messages or all messages */
  msg = gst_bus_poll (bus, (GstMessageType) ( GST_MESSAGE_EOS | GST_MESSAGE_ERROR ), -1);

  switch (GST_MESSAGE_TYPE (msg)) {
    case GST_MESSAGE_EOS: {
      g_print ("EOS\n");
      break;
    }
    case GST_MESSAGE_ERROR: {
      GError *err = NULL; /* error to show to users                 */
      gchar *dbg = NULL;  /* additional debug string for developers */

      gst_message_parse_error (msg, &err, &dbg);
      if (err) {
        g_printerr ("ERROR: %s\n", err->message);
        g_error_free (err);
      }
      if (dbg) {
        g_printerr ("[Debug details: %s]\n", dbg);
        g_free (dbg);
      }
    }
    default:
      g_printerr ("Unexpected message of type %d", GST_MESSAGE_TYPE (msg));
      break;
  }
  gst_message_unref (msg);

  gst_element_set_state (pipeline, GST_STATE_NULL);
  gst_object_unref (pipeline);
  gst_object_unref (bus);

  return 0;
}

关于gstreamer - 使用 gstreamercameraun Distor 插件计算畸变系数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66256368/

相关文章:

image-processing - 检索从变形图像中获取的像素的原始坐标

opencv - 从Leap运动摄像机接收到的原始图像不失真

audio - 使用gstreamer检测并删除音频文件中的静音

audio - 如何通过gstreamer将pcap转换为带有视频和音频的avi文件?

timestamp - 对于捕获的帧,GStreamer 时间戳 (PTS) 不会单调增加

android - 寻找快速图像失真算法

c - Gstreamer自定义插件注册问题

c - 当仅向视频管道提供音频时,Gstreamer 管道卡在预滚动状态

opencv - 逆透视映射 -> 何时不失真?

geometry - 创建任意扭曲的二维网格