GTK 中来自相机的实时图像
Live Image from camera in GTK
第一个:
我正在研究暗场显微镜跟踪程序。这个程序是旧的(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;
}
图像的更新是由代码中 draw_call
的 expose_event
回调触发的,有关详细信息,请参阅
您知道 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
您有多个问题:
您的绘图函数没有在 g_timer_add
中使用的正确签名。它必须 return 一个 TRUE
才能继续,并且它必须采用其他参数。
从该函数 returning 后,您有一些代码永远无法执行。
您 return 从计时器处理程序指向 GtkImage
的指针不正确。它必须 return TRUE/FALSE
。计时器包装器不知道如何处理这样的指针。
您没有自己更新任何小部件。我将在示例中展示这一点。
你一次又一次地创建图像,而你只需要更新现有的图像。
我已经使用更新功能扩展了您之前问题的示例:
// 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 上进行了测试,它会在每次调用计时器处理程序时更新图像。
第一个:
我正在研究暗场显微镜跟踪程序。这个程序是旧的(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;
}
图像的更新是由代码中 draw_call
的 expose_event
回调触发的,有关详细信息,请参阅
您知道 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
您有多个问题:
您的绘图函数没有在
g_timer_add
中使用的正确签名。它必须 return 一个TRUE
才能继续,并且它必须采用其他参数。从该函数 returning 后,您有一些代码永远无法执行。
您 return 从计时器处理程序指向
GtkImage
的指针不正确。它必须 returnTRUE/FALSE
。计时器包装器不知道如何处理这样的指针。您没有自己更新任何小部件。我将在示例中展示这一点。
你一次又一次地创建图像,而你只需要更新现有的图像。
我已经使用更新功能扩展了您之前问题的示例:
// 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 上进行了测试,它会在每次调用计时器处理程序时更新图像。