【问题标题】:Live Image from camera in GTK来自 GTK 中相机的实时图像
【发布时间】:2020-12-16 12:54:53
【问题描述】:

第一:
我正在研究一个暗场显微跟踪程序。这个程序是旧的(2012 年),我们有一个新相机,但这个相机不能用捕捉程序捕捉。所以我需要用相机公司的SDK(软件开发工具包)为这个相机编写一个“捕捉程序”。

跟踪程序是用C和GTK 2编写的,所以我也想用C和GTK 2编写“捕获程序”,所以我可以把“捕获程序”放在我的跟踪程序中。我可以在“抓拍程序”里面拍照,显示为gtk_image_new_from_pixbuf

问题:
能够拍照后发现暗视野显微镜无法让你用眼睛为相机设置焦距。所以现在我需要捕捉“实时图像”、视频或者你想怎么称呼它。
我的想法是使用一个计时器,这样相机就会每秒拍摄一张照片并将其显示为图像,因此程序必须删除旧图像并显示新图像。 但这不会发生我很确定相机没有问题,因为它显示了第一张图像。我的猜测是 pixbuf 没有被清除,导致没有显示新图像。
“捕获程序”不必保留为 C/Gtk2 程序,但由于我不是计算机科学家,我只是不知道如果图像不同,如何将图像输入跟踪程序。

代码:
我知道gdk_pixbuf_new_from_data 的星号是width*1 而不是width*3,这没问题。

#include <gtk/gtk.h>
#include <stdlib.h>

unsigned short *buffer = NULL;
long imageSize = 0;

void draw_call (GtkWidget *window, GdkEvent *event, gpointer data){

    (void)event; (void)data;
    GdkPixbuf *pix;
    GtkWidget* image;
    image = gtk_image_new();

    free (buffer);
    long result = NOERR;


//camera commands had to be changed 
    result = getImageSizeFromCamera( &imageSize);

    result = SetBitsPerPixel(8);

    buffer = (unsigned short *) malloc( imageSize*2);

    result = takePicture(camera, buffer, imageSize/2, NULL, NULL);

    result = stopTakingPicture (camera);
//end of camera commands

    pix = gdk_pixbuf_new_from_data ((unsigned int *) buffer, GDK_COLORSPACE_RGB,FALSE, 8,
               1936, 1460, 1936*1, pixbuf_free, NULL);

    image = gtk_image_new_from_pixbuf(pix);


    return image;
gtk_widget_unref (pix);
}

void pixbuf_free(guchar *pixels, gpointer data)
{
    g_free(pixels) ;
    fprintf(stderr, "pixbuf data freed\n") ;
}

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

    GdkPixbuf *pixbuf;


    // GTK

    GtkWidget *window;
    GtkWidget* image;

    image = gtk_image_new();


    gtk_init (&argc, &argv);

    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);


    gtk_window_set_title (GTK_WINDOW (window), "Image Viewer");

    g_signal_connect (window, "destroy", G_CALLBACK (Deinit), NULL);
    g_signal_connect (window, "expose-event",G_CALLBACK (draw_call), NULL);


    g_timeout_add (1000, draw_call, NULL);

    gtk_widget_set_app_paintable(window, TRUE);
    gtk_widget_set_double_buffered(window, FALSE);


    gtk_container_add(GTK_CONTAINER (window), image);

    gtk_widget_show_all (window);

    gtk_main ();


    return 0;
}

【问题讨论】:

  • 您已经有一张图片,并且想要更新内容。 gtk_image_set_from_pixbuf 而不是 gtk_image_new_from_pixbuf 呢?这没有任何意义 return image; gtk_widget_unref (pix); 有两个原因:1)函数 data_call 具有返回类型 void 和 2)在 return 语句之后没有更多代码可以访问。还有谁应该使用该返回值?
  • 我对 gtk2 不太熟悉,但我认为您应该将 image 指针作为用户参数从 main 传递给 draw_call,并使用新的 pixbuf 更新该图像。跨度>
  • gtk_image_set_from_pixbuf 我会试试的。对于返回后的_unref (pix),我在其他帖子中看到了它并尝试了一下。对于函数data_call 为什么它是void 我不知道还能用什么。我会尝试使用image 指针的想法。
  • 那么其他代码是错误的。 return 的主要目的是立即离开当前函数并为调用者提供一个值。如果您离开该功能,所有剩余的代码都是死代码。计时器处理程序也不知道如何处理您的返回值。

标签: c image gtk gtk2


【解决方案1】:

你有多个问题:

  1. 您的绘图函数没有在g_timer_add 中使用的正确签名。它必须返回一个TRUE 才能继续运行,并且它必须采用其他参数。

  2. 从该函数返回后,您有一些永远无法执行的代码。

  3. 您从计时器处理程序返回一个指向GtkImage 的指针,这是不正确的。它必须返回TRUE/FALSE。计时器包装器不知道如何处理这样的指针。

  4. 您自己不会更新任何小部件。我将在一个例子中展示这一点。

  5. 您一次又一次地创建图像,而您只需要更新现有的图像。

我已使用更新功能扩展了您之前问题的示例:

// build:
// gcc -o test `pkg-config --cflags gtk+-3.0` -Wall -Wextra test.c `pkg-config --libs gtk+-3.0`


#include <stdlib.h>
#include <stdint.h>
#include <gtk/gtk.h>

typedef struct {
  uint8_t r;
  uint8_t g;
  uint8_t b;
} rgb;


int basecolour = 0;


void pixbuf_free(guchar *pixels, gpointer data)
{
  g_free(pixels) ;
  (void)data;    
  fprintf(stderr, "pixbuf data freed\n") ;
}

gboolean draw_call(gpointer user_data)
{
    GtkImage *image = (GtkImage *) user_data;
    
  size_t Width  = 1936;
  size_t Height = 1280;
  size_t Stride_rgb = Width; // Might need rounding up

  // Put raw image data from the camera in the buffer.     
  rgb *buffer_rgb = malloc(Stride_rgb * Height * sizeof(rgb));

  for (size_t x = 0; x < Width; x++)
    for (size_t y = 0; y < Height; y++)
    {
      // Convert 1 byte greyscale in 3 byte RGB:
      uint8_t grey = (basecolour + x+y) & 0xFF;
      buffer_rgb[Stride_rgb*y + x].r = grey;
      buffer_rgb[Stride_rgb*y + x].g = grey;
      buffer_rgb[Stride_rgb*y + x].b = grey;
    }
    basecolour += 5;

  GdkPixbuf *pixbuf_rgb = gdk_pixbuf_new_from_data((guchar*)buffer_rgb, GDK_COLORSPACE_RGB,FALSE, 8,
              Width, Height, Stride_rgb*3, pixbuf_free, NULL);
  gtk_image_set_from_pixbuf(image, pixbuf_rgb);
  g_object_unref(pixbuf_rgb);

  return TRUE;  
}

int main (int argc, char *argv[])
{
    size_t Width  = 1936;
    size_t Height = 1280;
    size_t Stride_8 = Width;   // Might need rounding up
    size_t Stride_rgb = Width; // Might need rounding up

    //Due to lack of camera data, lets use some dummy data...
    uint8_t *buffer_8 = malloc(Stride_8*Height);
    for (size_t x = 0; x < Width; x++)
      for (size_t y = 0; y < Height; y++)
        buffer_8[Stride_8*y + x] = (x+y) & 0xFF;

    /*code to take raw image data from camera*/

    // Put raw image data from the camera in the buffer.     
    rgb *buffer_rgb = malloc(Stride_rgb * Height * sizeof(rgb));

    for (size_t x = 0; x < Width; x++)
      for (size_t y = 0; y < Height; y++)
      {
        // Convert 1 byte greyscale in 3 byte RGB:
        uint8_t grey = buffer_8[Stride_8*y + x];
        buffer_rgb[Stride_rgb*y + x].r = grey;
        buffer_rgb[Stride_rgb*y + x].g = grey;
        buffer_rgb[Stride_rgb*y + x].b = grey;
        }

    // GTK
    gtk_init(&argc, &argv);
    GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_set_title(GTK_WINDOW (window), "test");
    g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);

    GdkPixbuf *pixbuf_rgb = gdk_pixbuf_new_from_data((guchar*)buffer_rgb, GDK_COLORSPACE_RGB,FALSE, 8,
               Width, Height, Stride_rgb*3, pixbuf_free, NULL);
    GtkWidget *image = gtk_image_new_from_pixbuf(pixbuf_rgb);
    g_object_unref(pixbuf_rgb);  

    gtk_container_add(GTK_CONTAINER(window), image);
    gtk_widget_show_all(window);

    g_timeout_add (1000, draw_call, image);
    gtk_main();
    
    return 0;
}

再次,我添加了一些虚拟代码来替换您的图像捕获部分。 我已经在 Linux 上进行了测试,它会在每次调用计时器处理程序时更新图像。

【讨论】:

  • 感谢您的帮助,它正在工作!但是我已经有这个工作了,我认为它没有醒来的问题是因为来自相机公司的命令写得不好,所以我在缓冲区中放入了太多信息,所以图片是黑色的。在获得带有虚拟数据的示例代码后,我发现了我必须在相机命令中更改的内容。再次非常感谢您。
【解决方案2】:

图片的更新是由代码中的draw_callexpose_event回调触发的,详情见How to get webcam feed to GTK window?

您知道 OpenCV 中实现了跟踪吗? https://docs.opencv.org/3.4/d2/d0a/tutorial_introduction_to_tracker.html

您还可以在 OpenCV 中编写图像捕获代码

OpenCV - Getting picture from default webcam in C/C++ - GTK Issues

GUVCVIEWER中实现了您需要的功能,如果您的相机使用uvc驱动程序https://github.com/jaswdr/guvcview/blob/master/gview_v4l2core/v4l2_core.c,您可能可以移植源代码

【讨论】:

  • 是的,我知道所有这些,但它不起作用,因为我尝试过的 OpenCV 和其他 6 个捕获程序无法使用我的相机。如果我可以只使用捕获 api,我就不会遇到这个问题。
  • guvcviewer 也不行吗?显微镜用什么驱动内核模块?
  • 检查dmesg
  • 我正在为 Windows 构建,但我在 Linux PC 上检查了dmesg,它说它使用 ehci-pci 是你需要的吗?。
  • 对于 Windows,我不知道这一点。 /dev/video0 是否存在?检查您的dmesg 输出是否类似于wiki.archlinux.org/index.php/webcam_setup 中的“加载”部分。重要的是 v4l2 的东西
猜你喜欢
  • 2017-05-23
  • 1970-01-01
  • 1970-01-01
  • 2013-05-14
  • 1970-01-01
  • 2015-06-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多