Первый:
Я работаю над программой слежения за микроскопом в темном поле. Эта программа старая (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;
}
Я не настолько знаком с gtk2, но я предполагаю, что вы должны передать указатель image
из main
в качестве пользовательского параметра в draw_call
и обновить это изображение новым pixbuf.
gtk_image_set_from_pixbuf
попробую. Что касается _unref (pix)
после возвращения, я увидел его в другом посте и просто попробовал. Для функции data_call
почему это void
я не знал, что еще использовать. Идею с указателем image
попробую.
Тогда этот другой код был неправильным. Основная цель return
— немедленно покинуть текущую функцию и предоставить значение вызывающей стороне. Если вы покинете функцию, весь оставшийся код станет мертвым кодом. Также обработчик таймера не будет знать, что делать с вашим возвращаемым значением.
Обновление изображений запускается обратным вызовом expose_event
, который draw_call
находится в вашем коде, подробнее см. Как передать веб-камеру в окно GTK?
Вы знаете, что в OpenCV реализовано отслеживание? https://docs.opencv.org/3.4/d2/d0a/tutorial_introduction_to_tracker.html
Вы также можете закодировать захват изображения в OpenCV.
OpenCV - Получение изображения с веб-камеры по умолчанию в C/C++ - Проблемы с GTK
В GUVCVIEWER реализован тот функционал, который вам нужен и возможно вы сможете портировать исходники, если ваша камера использует uvc
драйвер https://github.com/jaswdr/guvcview/blob/master/gview_v4l2core/v4l2_core.c
Да, я все это знаю, но это не работает, потому что OpenCV и другие 6 программ захвата, которые я пробовал, не могут использовать мою камеру. Если бы я мог просто использовать API захвата, у меня не было бы этой проблемы.
guvcviewer тоже нет? Какой модуль ядра драйвера использует микроскоп?
проверить с помощью i.e. dmesg
Я собираю для Windows, но я проверил dmesg
на ПК с Linux, и он говорит, что он использует ehci-pci, это то, что вам нужно?
Для Windows я этого не знаю. Существует ли /dev/video0? Убедитесь, что ваш вывод dmesg
похож на раздел «Загрузка» в wiki.archlinux.org/index.php/webcam_setup. Важен материал v4l2
Я проверил еще раз, но у меня не работает ни одна программа захвата, вероятно, потому, что компания камеры изменила команды, как вызывается камера. Спасибо, в любом случае. (Программа работает благодаря вкладу Герхарда)
У вас несколько проблем:
У вашей функции рисования нет правильной подписи для использования в g_timer_add
. Он должен вернуть TRUE
, чтобы продолжить работу, и он должен принимать другие параметры.
У вас есть некоторый код после возврата из этой функции, который никогда не может быть выполнен.
Вы возвращаете указатель на GtkImage
из обработчика таймера, который неверен. Он должен вернуться 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, и он обновляет изображение при каждом вызове обработчика таймера.
Спасибо за помощь, все работает! Но у меня это уже работало, проблема, почему я думал, что это не работает, заключалась в том, что команды от компании-производителя камеры были плохо написаны, поэтому я поместил слишком много информации в буфер, поэтому изображение было черным. Получив ваш пример кода с фиктивными данными, я узнал, что мне нужно было изменить в командах камеры. Еще раз большое спасибо.
У вас уже есть изображение, и вы хотите обновить содержимое. Как насчет gtk_image_set_from_pixbuf вместо
gtk_image_new_from_pixbuf
? Это не имеет никакого смысла по двум причинамreturn image; gtk_widget_unref (pix);
: 1) функцияdata_call
имеет тип возвращаемого значенияvoid
и 2) после оператораreturn
код больше недоступен. Кроме того, кто все равно должен использовать это возвращаемое значение?