cimagegtkgtk2

Live Image from camera in GTK


First:
I am working on a dark-field microscopic tracking program. This program is old (2012), we got a new camera but this camera can´t be captured with a capture program. So I need to write a "capture program" for this camera with the SDK (Software development kit) from the company of the camera.

The tracking program is writen in C and GTK 2, so I would like to have the "capture program" in C and GTK 2 too, so I can just put the "capture program" in my tracking program. I can take a picture inside the "capture program" and show it as gtk_image_new_from_pixbuf.

Problem:
After being able to take pictures I found out that the dark-field microscope is not able to let you set the focus for the camera with your eyes. So now I need to capture a "live image", video or how ever you want to call it.
My idea was to use a timer so the camera will take a picture every second and display it as an image so the program has to delete the old image and show the new one. But that doesn´t happen I am pretty sure that there is no problem with the camera, because it shows the first image. My guess is that the pixbuf isn´t cleared and that causes that there is no new image shown.
The "capture program" doesn´t have to stay as a C/Gtk2 program but as I am not a computer scientist I just have no idea how to get the images into the tracking program if they are different.

Code:
I know that gdk_pixbuf_new_from_data has a starde of width*1 and not width*3 that is no problem.

#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;
}


Solution

  • You have multiple problems:

    1. Your drawing function does not have correct signature to be used in g_timer_add. It must return a TRUE to keep going and it must take other parameters.

    2. You have some code after returning from that function which can never bbe executed.

    3. You return a pointer to GtkImage from timer handler wich is not correct. It must return TRUE/FALSE. The timer wrapper does not know what to do with such a pointer.

    4. You do not update any widget yourself. I will show this in an example.

    5. You create images again and again while you only need to update the existing one.

    I have extended the sample for your previous question with update functionality:

    // 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;
    }
    

    Again, I have added some dummy code to replace your image capture part. I have tested on Linux and it updates the image with every call of the timer handler.