vendredi 30 juin 2023

Using opencv processing (cv::imshow cv::cvtColor) in Gstreamer application (appsink)

I want to use appsink to extract the frames in the Gstbuffer in the pipeline, and then use opencv for image processing, I refer to the program in this link (Adding opencv processing to gstreamer application), but when I use imshow or cvtColor in the main function, there will be a core dump error, But in the new_sample function, I should have successfully extracted each frame in the buffer, and the map.size is also correct (BGR, width=100, height=100, map.size=30000).

opencv version:4.7.0

video/x-raw, format=(string)BGR, width=(int)100, height=(int)100, framerate=(fraction)30/1, multiview-mode=(string)mono, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive Erreur de segmentation (core dumped)

Gtk-Message: 17:04:05.146: Failed to load module "appmenu-gtk-module" frameSize: 30000 video/x-raw, format=(string)BGR, width=(int)100, height=(int)100, framerate=(fraction)30/1, multiview-mode=(string)mono, pixel-aspect-ratio=(fraction)1/1, interlace-mode=(string)progressive frameSize: 30000 Erreur de segmentation (core dumped)

#include <gst/gst.h>
#include <gst/app/app.h>
#include <gst/app/gstappsink.h>
#include <stdlib.h> 
#include <opencv2/opencv.hpp>
#include <opencv2/core.hpp>
#include <opencv2/videoio.hpp>
#include <opencv2/highgui.hpp>
using namespace cv;

// TODO: use synchronized deque
std::deque<Mat> frameQueue;

 

GstFlowReturn
new_preroll(GstAppSink *appsink, gpointer data) {
  g_print ("Got preroll!\n");
  return GST_FLOW_OK;
}

 

GstFlowReturn
new_sample(GstAppSink *appsink, gpointer data) {
  static int framecount = 0;
  framecount++;

 

  GstSample *sample = gst_app_sink_pull_sample(appsink);
  GstCaps *caps = gst_sample_get_caps(sample);
  GstBuffer *buffer = gst_sample_get_buffer(sample);
  const GstStructure *info = gst_sample_get_info(sample);

 

  // ---- Read frame and convert to opencv format ---------------
  GstMapInfo map;
  gst_buffer_map (buffer, &map, GST_MAP_READ);
  // convert gstreamer data to OpenCV Mat, you could actually
  // resolve height / width from caps...
  Mat frame(Size(320, 240), CV_8UC3, (char*)map.data, Mat::AUTO_STEP);
  int frameSize = map.size;
  g_print ("frameSize: %d\n",frameSize);
  // TODO: synchronize this....
  frameQueue.push_back(frame);
  gst_buffer_unmap(buffer, &map);

  // ------------------------------------------------------------
  // print dot every 30 frames
  if (framecount%30 == 0) {
    g_print (".");
  }

  // show caps on first frame
  if (framecount == 1) {
    g_print ("%s\n", gst_caps_to_string(caps));
  }
  gst_sample_unref (sample);
  return GST_FLOW_OK;
}

 

static gboolean
my_bus_callback (GstBus *bus, GstMessage *message, gpointer data) {
  g_print ("Got %s message\n", GST_MESSAGE_TYPE_NAME (message));
  switch (GST_MESSAGE_TYPE (message)) {
    case GST_MESSAGE_ERROR: {
      GError *err;
      gchar *debug;

 

      gst_message_parse_error (message, &err, &debug);
      g_print ("Error: %s\n", err->message);
      g_error_free (err);
      g_free (debug);    
      break;
    }
    case GST_MESSAGE_EOS:
      /* end-of-stream */
      break;
    default:
      /* unhandled message */
      break;
  }
  /* we want to be notified again the next time there is a message
   * on the bus, so returning TRUE (FALSE means we want to stop watching
   * for messages on the bus and our callback should not be called again)
   */
  return TRUE;
}

 

int
main (int argc, char *argv[])
{
  GError *error = NULL;

 

  gst_init (&argc, &argv);

 

  gchar *descr = g_strdup(
    "videotestsrc  pattern=ball ! "
    "video/x-raw,width=100,height=100,format=(string)BGR ! "
    "videoconvert ! "
    "appsink name=sink sync=true"
  );
  GstElement *pipeline = gst_parse_launch (descr, &error);

 

  if (error != NULL) {
    g_print ("could not construct pipeline: %s\n", error->message);
    g_error_free (error);
    exit (-1);
  }


  /* get sink */
  GstElement *sink = gst_bin_get_by_name (GST_BIN (pipeline), "sink");

  gst_app_sink_set_emit_signals((GstAppSink*)sink, true);
  gst_app_sink_set_drop((GstAppSink*)sink, true);
  gst_app_sink_set_max_buffers((GstAppSink*)sink, 1);
  GstAppSinkCallbacks callbacks = { NULL, new_preroll, new_sample };
  gst_app_sink_set_callbacks (GST_APP_SINK(sink), &callbacks, NULL, NULL);


  GstBus *bus;
  guint bus_watch_id;
  bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
  bus_watch_id = gst_bus_add_watch (bus, my_bus_callback, NULL);
  gst_object_unref (bus);

 
  gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_PLAYING);
  namedWindow("edges",1);
  while(1) {
    g_main_iteration(false);

      // TODO: synchronize...
    if (frameQueue.size() > 0) {
      // this lags pretty badly even when grabbing frames from webcam
      Mat frame = frameQueue.front();
      Mat edges;
      cvtColor(frame, edges, cv::COLOR_BGR2GRAY);
      //GaussianBlur(edges, edges, Size(7,7), 1.5, 1.5);
      //Canny(edges, edges, 0, 30, 3);
      //imshow("edges", edges);
      //cv::waitKey(30);
      frameQueue.clear();
    }
  }  

  gst_element_set_state (GST_ELEMENT (pipeline), GST_STATE_NULL);
  gst_object_unref (GST_OBJECT (pipeline));

I'm a newbie and would appreciate some help, many thanks!

Template queue with pre defined size

I want something like this: Queue<type, size> my_queue;. Here the typeis whatever I want. It can be an array, a structure or something else. Size is the maximum allowed elements that my_queue object can contain. From this thread I understand that I must have a wrapper class that allows me to set a size value and access to the actual queue through the wrapper class. But I also must be able to instantiate a Queue object with different types.

So I thought I can solve my problem by using templates. My only constraint is limiting the Queue size in order to limit the dynamically allocated memory by the std::queue. I thought I can inherit from the std::queue and simply create a class like this:

template<typename T>
class Queue final : public std::queue<T> {
public:
    Queue(T type, uint32_t size) : size_(size) { };

    virtual ~Queue() = default;

    bool push(T new_element) {
        if(this->size() < size_) {
            this->push(new_element);
            return 1;
        }
        return 0;
    }
    ;

private:
    const uint32_t size_ = 0;
};

This is compiling. But I know it is not correct. I do not know how can I do it. Also when I want to create an instance of Queue like Queue<uint8_t[5], 5> my_queue; it does not compile.

jeudi 29 juin 2023

Unexpected output when invoking overloaded functions with different rvalue reference types

I'm encountering an unexpected behavior in my code when calling overloaded functions with different rvalue reference types. The code snippet below demonstrates the issue:

#include <iostream>

void foo(int&& x)
{
    std::cout << "int Rvalue: " << x << std::endl;
}

void foo(float&& x)
{
    std::cout << "float Rvalue: " << x << std::endl;
}

int main()
{
    int int_x = 1;
    float float_x = 5.14f;

    foo(int_x);
    foo(float_x);
}

Output

float Rvalue: 1
int Rvalue: 5

Instead of getting the anticipated output, which should be "int Rvalue: 1" and "float Rvalue: 5", I observe the reverse order. I find this behavior perplexing and would appreciate insights into why this is happening.

I have made sure to understand the concept of rvalue references and how overloading works based on them. I have also tried to search for similar issues, but haven't found any that directly address this specific situation.

Any guidance or explanations would be greatly appreciated. Thank you in advance for your assistance!

multithread std::shared_ptr read / write with sigsegv

a global shared_ptr g_ptr=null; then in thread 1, call init() set g_ptr=make_shared();

after that, has other thread x use write()


void write()
{
   if(g_ptr)
   {
       g_ptr->dosomething();// g_ptr.get() has a std::FILE _fd;
    }
}

then the program end. the program is

in thread 1, the global g_ptr has destory. but in other thread, func write is doing,but the _fd is set to nullptr. so the program segmentaion fault.

both init() and write() are interface, called by customer.

how can i avoid this program? use the raw pointer and provide a close() api ,may be ok. except this, how can i resolve this program with use smart pointer。 thanks.

In Qt c QLabel::setText does not work but other fun can work

I wanted to display the specified content in the label (Client::saveData, a static variable),but I couldn't do it anyway. QMessageBox::information works, and qDebug() outputs the correct content, but it just doesn't show up on the label.

void S8524Widget::setTandHLabel()
{
    qDebug() << Client::saveData;

    QMessageBox::information(NULL,"OK","OK");
    ui->tempText->setAlignment(Qt::AlignCenter);
    QString tempdata(Client::saveData.left(2));
    ui->tempText->setText(tempdata);
    //ui->tempText->setProperty("text",tempdata);
    //ui->tempText->setStyleSheet("setProperty: TEST;");
    QString var = ui->tempText->text();

    QString humiditydata(Client::saveData.right(2));
    ui->humidityText->setText(humiditydata);
    QString vae = ui->humidityText->text();

    ui->ProgramNameText->setPlainText(tempdata);
    ui->TimeStatusText->setPlainText(tempdata);
    ui->StepStatusText->setPlainText(tempdata);

    qDebug() << var;
    qDebug() << vae;
}

Client::saveData prints correctly. If I put settext in the constructor, it works fine, but I need it to update the text dynamically. In this function, even setText (“Tempdata”) doesn't work. If you save Ui-> tempText as a variable, calling setText from the mainwindow won't work either.

mercredi 28 juin 2023

Use a Polygon in Boost RTree?

I'm using an RStar tree for a project and there is a need to move to a shape that is not axis aligned. The current implementation (and documentation example) uses box, which is defined by two points and so is always axis aligned. I still want boxes but they need to be able go diagonally through the space while being narrow. My first thought was to use polygon and specify the 8 vertices all manually. However, when I try and create a tree of this type it says Polygon is not indexable. I looked at the box documentation (and Point) and don't see the indexable property there so I'm not sure which objects have it or how to implement it myself. Has anyone else done this before?

RTree Example: https://www.boost.org/doc/libs/1_82_0/libs/geometry/doc/html/geometry/spatial_indexes/rtree_quickstart.html

Box Documentation (constructed via only two points): https://www.boost.org/doc/libs/1_82_0/libs/geometry/doc/html/geometry/reference/models/model_box.html

Polygon (that I want to use): https://www.boost.org/doc/libs/1_82_0/boost/geometry/geometries/polygon.hpp

Example code with parts that don't compile commented out (just to show the gist of what I want, the goal was to write code the performed exactly the same as the example but using a shape I had more control over):

#include <iostream>
#include <vector>
#include <boost/assign/std/vector.hpp>
#include <boost/geometry.hpp>
#include <boost/geometry/algorithms/area.hpp>
#include <boost/geometry/algorithms/assign.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/geometries/polygon.hpp>
#include <boost/geometry/io/dsv/write.hpp>

#include <boost/geometry/index/rtree.hpp>

int main()
{
    using namespace boost::assign;
    namespace bg = boost::geometry;
    namespace bgi = boost::geometry::index;

    typedef bg::model::d2::point_xy<float> point;
    typedef bg::model::polygon<point> polygon2d;
    typedef std::pair<polygon2d , unsigned> value;

    // create the rtree using default constructor
//    bgi::rtree< value, bgi::quadratic<16> > rtree;

    // create some values
    for ( unsigned i = 0 ; i < 10 ; ++i )
    {
        // create a polygon that's the same as the box in the online example
        // https://www.boost.org/doc/libs/1_72_0/libs/geometry/doc/html/geometry/spatial_indexes/rtree_quickstart.html
        std::vector<point> points;
        points +=
                point(i + 0.0f, i + 0.0f),
                point(i + 0.0f, i + 0.5f),
                point(i + 0.5f, i + 0.0f),
                point(i + 0.5f, i + 0.5f)
                ;

        polygon2d p;
        bg::assign_points(p, points);
//        // insert new value
//        rtree.insert(std::make_pair(p, i));
    }

    // find values intersecting some area defined by a box
    polygon2d query_box;
    std::vector<point> query_points;
    query_points +=
            point(0, 0),
            point(0, 5),
            point(5, 0),
            point(5, 5)
            ;
    bg::assign_points(query_box, query_points);
//    std::vector<value> result_s;
//    rtree.query(bgi::intersects(query_box), std::back_inserter(result_s));
//
//    // find 5 nearest values to a point
//    std::vector<value> result_n;
//    rtree.query(bgi::nearest(point(0, 0), 5), std::back_inserter(result_n));
//
//    // display results
//    std::cout << "spatial query box:" << std::endl;
//    std::cout << bg::wkt<box>(query_box) << std::endl;
//    std::cout << "spatial query result:" << std::endl;
//    BOOST_FOREACH(value const& v, result_s)
//    std::cout << bg::wkt<box>(v.first) << " - " << v.second << std::endl;
//
//    std::cout << "knn query point:" << std::endl;
//    std::cout << bg::wkt<point>(point(0, 0)) << std::endl;
//    std::cout << "knn query result:" << std::endl;
//    BOOST_FOREACH(value const& v, result_n)
//    std::cout << bg::wkt<box>(v.first) << " - " << v.second << std::endl;
}


mutable data member template constructor and trivially copy constructible

Example code could be found below or on godbolt. Say we have 4 classes:

  1. S<T>: holding a data member.

  2. SCtor<T>: holding a data member and has a template constructor.

  3. SCtorMutable<T>: holding a mutable data member and has a template constructor.

  4. SCtorDefault<T>: holding a member, has a template constructor, has defaulted copy/move constructors and defaulted copy/move assignment operators.

All compilers agree that these 4 classes are trivially copyable.

If there is a simple wrapper class W<T> holding any of the above class as a data member. The wrapper class W<S...<T>> is still trivially copyable.

If there is another wrapper class WMutable<T> holding any of the above class as a mutable data member.

  1. MSVC still believes WMutable<S...<T>> is trivially copyable.
  2. clang believes WMutable<S<T>> is trivially copyable. WMutable<SCtor...<T>> is not trivially copy constructible therefore not trivially copyable.
  3. gcc believes WMutable<S<T>> is trivially copyable. WMutable<SCtor...<T>> is not trivially copy constructible BUT trivially copyable.

Should WMutable<T> be trivially copyable?

#include <type_traits>
#include <utility>

template<typename T>
struct S {
    T m_t;
};

template<typename T>
struct SCtor {
    T m_t;
    template<typename... U>
    SCtor(U&&... u): m_t(std::forward<U>(u)...) {}
};

template<typename T>
struct SCtorMutable {
    mutable T m_t;
    template<typename... U>
    SCtorMutable(U&&... u): m_t(std::forward<U>(u)...) {}
};

template<typename T>
struct SCtorDefault {
    T m_t;
    template<typename... U>
    SCtorDefault(U&&... u): m_t(std::forward<U>(u)...) {}
    SCtorDefault(SCtorDefault const&) = default;
    SCtorDefault(SCtorDefault&&) = default;
    SCtorDefault& operator=(SCtorDefault const&) = default;
    SCtorDefault& operator=(SCtorDefault&&) = default;
};

template<typename T>
struct W {
    T m_t;
};

template<typename T>
struct WMutable {
    mutable T m_t;
};

static_assert(std::is_trivially_copyable<S<int>>::value);
static_assert(std::is_trivially_copy_constructible<S<int>>::value);
static_assert(std::is_trivially_move_constructible<S<int>>::value);
static_assert(std::is_trivially_copy_assignable<S<int>>::value);
static_assert(std::is_trivially_move_assignable<S<int>>::value);

static_assert(std::is_trivially_copyable<SCtor<int>>::value);
static_assert(std::is_trivially_copy_constructible<SCtor<int>>::value);
static_assert(std::is_trivially_move_constructible<SCtor<int>>::value);
static_assert(std::is_trivially_copy_assignable<SCtor<int>>::value);
static_assert(std::is_trivially_move_assignable<SCtor<int>>::value);

static_assert(std::is_trivially_copyable<SCtorMutable<int>>::value);
static_assert(std::is_trivially_copy_constructible<SCtorMutable<int>>::value);
static_assert(std::is_trivially_move_constructible<SCtorMutable<int>>::value);
static_assert(std::is_trivially_copy_assignable<SCtorMutable<int>>::value);
static_assert(std::is_trivially_move_assignable<SCtorMutable<int>>::value);

static_assert(std::is_trivially_copyable<SCtorDefault<int>>::value);
static_assert(std::is_trivially_copy_constructible<SCtorDefault<int>>::value);
static_assert(std::is_trivially_move_constructible<SCtorDefault<int>>::value);
static_assert(std::is_trivially_copy_assignable<SCtorDefault<int>>::value);
static_assert(std::is_trivially_move_assignable<SCtorDefault<int>>::value);

static_assert(std::is_trivially_copyable<W<S<int>>>::value);
static_assert(std::is_trivially_copy_constructible<W<S<int>>>::value);
static_assert(std::is_trivially_move_constructible<W<S<int>>>::value);
static_assert(std::is_trivially_copy_assignable<W<S<int>>>::value);
static_assert(std::is_trivially_move_assignable<W<S<int>>>::value);

static_assert(std::is_trivially_copyable<W<SCtor<int>>>::value);
static_assert(std::is_trivially_copy_constructible<W<SCtor<int>>>::value);
static_assert(std::is_trivially_move_constructible<W<SCtor<int>>>::value);
static_assert(std::is_trivially_copy_assignable<W<SCtor<int>>>::value);
static_assert(std::is_trivially_move_assignable<W<SCtor<int>>>::value);

static_assert(std::is_trivially_copyable<W<SCtorMutable<int>>>::value);
static_assert(std::is_trivially_copy_constructible<W<SCtorMutable<int>>>::value);
static_assert(std::is_trivially_move_constructible<W<SCtorMutable<int>>>::value);
static_assert(std::is_trivially_copy_assignable<W<SCtorMutable<int>>>::value);
static_assert(std::is_trivially_move_assignable<W<SCtorMutable<int>>>::value);

static_assert(std::is_trivially_copyable<W<SCtorDefault<int>>>::value);
static_assert(std::is_trivially_copy_constructible<W<SCtorDefault<int>>>::value);
static_assert(std::is_trivially_move_constructible<W<SCtorDefault<int>>>::value);
static_assert(std::is_trivially_copy_assignable<W<SCtorDefault<int>>>::value);
static_assert(std::is_trivially_move_assignable<W<SCtorDefault<int>>>::value);

static_assert(std::is_trivially_copyable<WMutable<S<int>>>::value);
static_assert(std::is_trivially_copy_constructible<WMutable<S<int>>>::value);
static_assert(std::is_trivially_move_constructible<WMutable<S<int>>>::value);
static_assert(std::is_trivially_copy_assignable<WMutable<S<int>>>::value);
static_assert(std::is_trivially_move_assignable<WMutable<S<int>>>::value);

static_assert(std::is_trivially_copyable<WMutable<SCtor<int>>>::value); // error with clang
static_assert(std::is_trivially_copy_constructible<WMutable<SCtor<int>>>::value); // error with clang/gcc
static_assert(std::is_trivially_move_constructible<WMutable<SCtor<int>>>::value);
static_assert(std::is_trivially_copy_assignable<WMutable<SCtor<int>>>::value);
static_assert(std::is_trivially_move_assignable<WMutable<SCtor<int>>>::value);

static_assert(std::is_trivially_copyable<WMutable<SCtorMutable<int>>>::value); // error with clang
static_assert(std::is_trivially_copy_constructible<WMutable<SCtorMutable<int>>>::value); // error with clang/gcc
static_assert(std::is_trivially_move_constructible<WMutable<SCtorMutable<int>>>::value);
static_assert(std::is_trivially_copy_assignable<WMutable<SCtorMutable<int>>>::value);
static_assert(std::is_trivially_move_assignable<WMutable<SCtorMutable<int>>>::value);

static_assert(std::is_trivially_copyable<WMutable<SCtorDefault<int>>>::value); // error with clang
static_assert(std::is_trivially_copy_constructible<WMutable<SCtorDefault<int>>>::value); // error with clang/gcc
static_assert(std::is_trivially_move_constructible<WMutable<SCtorDefault<int>>>::value);
static_assert(std::is_trivially_copy_assignable<WMutable<SCtorDefault<int>>>::value);
static_assert(std::is_trivially_move_assignable<WMutable<SCtorDefault<int>>>::value);