在前面一篇,已經可以基於gtk讀取圖像並顯示。更前面的一篇:基於GDI的imshow:使用stb_image讀取圖像並修正繪製,經過stb_image讀取圖像並經過GDI顯示圖像,實現了一個imshow。本篇則在這兩基礎上,利用stb_image讀取圖像,並利用gtk顯示,初步實現一個基於gtk的imshow。html
首先是找到一份代碼,從指定的buffer建立gtk的image並顯示(參考1)。而後用stb image讀取,先前我進行了封裝,獲得fc image是和opencv兼容的bgr格式。然而發現gtk須要的是rgb的順序,所以又作了一道轉化步驟:BGR to RGB,而後把對應的buffer傳給gtk去生成它的image。linux
完整的代碼須要 基於GDI的imshow:使用stb_image讀取圖像並修正繪製 這一篇blog中的代碼,以及本文新增的代碼gtk_show_image_v3.c
:算法
#include <gtk/gtk.h> #include <stdlib.h> #include <assert.h> #include "fc_image.h" void fc_bgr_to_rgb(FcImage* im) { if (im==NULL) return; if (im->c<=0 || im->h<=0 || im->w==0) return; assert(im->c==3); int num_pixel = im->c * im->h * im->w; unsigned char t; for(int i=0; i<num_pixel; i+=3) { t = im->data[i]; im->data[i] = im->data[i+2]; im->data[i+2] = t; } } int main (int argc, char *argv[]) { const char* im_pth = "/home/zz/work/libfc/imgs/fruits.jpg"; FcImage im = fc_load_image(im_pth); fc_bgr_to_rgb(&im); GtkWidget *window; GtkWidget* image; gtk_init (&argc, &argv); window = gtk_window_new (GTK_WINDOW_TOPLEVEL); GdkPixbuf *pixbuf = gdk_pixbuf_new_from_data (im.data, GDK_COLORSPACE_RGB, FALSE, 8, im.w, im.h, im.w*3, NULL, NULL); gtk_window_set_title (GTK_WINDOW (window), "Image Viewer"); g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL); image = gtk_image_new_from_pixbuf (pixbuf); gtk_container_add(GTK_CONTAINER (window), image); gtk_widget_show_all (window); gtk_main (); return 0; }
考慮到把原有的bgr順序的圖像buffer修改成rgb,就地修改確定是有問題的,影響到後續算法的使用。所以應當拷貝產生一個新的圖像數據。而且還須要把im和title做爲參數,封裝爲API,之後調用方便。修改後的代碼以下:ui
#include <gtk/gtk.h> #include <stdlib.h> #include <assert.h> #include "fc_image.h" void fc_copy_bgr_to_rgb(const FcImage* src, FcImage* dst) { if (src==NULL) return; if (dst==NULL) return; assert(src!=dst); assert(src->data!=NULL); assert(dst->data!=NULL); assert(src->data!=dst->data); assert(src->c>=0 && src->h>=0 && src->c==3); assert(src->c>=0 && src->h>=0 && src->c==3); assert(src->c==dst->c && src->h==dst->h && src->w==dst->w); int num_pixel = src->c * src->h * src->w; for(int i=0; i<num_pixel; i+=3) { dst->data[i] = src->data[i+2]; dst->data[i+1] = src->data[i+1]; dst->data[i+2] = src->data[i]; } } FcImage fc_make_image(int w, int h, int c) { FcImage out; out.w = w; out.h = h; out.c = c; out.data = (unsigned char*)calloc(h*w*c, sizeof(float)); return out; } void gtk_show_image_v3(const FcImage* im, const char* title) { FcImage im_rgb = fc_make_image(im->w, im->h, im->c); //?? check this dimensions fc_copy_bgr_to_rgb(im, &im_rgb); GtkWidget *window; GtkWidget* image; gtk_init (NULL, NULL); window = gtk_window_new (GTK_WINDOW_TOPLEVEL); GdkPixbuf *pixbuf = gdk_pixbuf_new_from_data (im_rgb.data, GDK_COLORSPACE_RGB, FALSE, 8, im_rgb.w, im_rgb.h, im_rgb.w*3, NULL, NULL); gtk_window_set_title (GTK_WINDOW (window), title); g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL); image = gtk_image_new_from_pixbuf (pixbuf); gtk_container_add(GTK_CONTAINER (window), image); gtk_widget_show_all (window); gtk_main (); } int main (int argc, char *argv[]) { const char* im_pth = "/home/zz/work/libfc/imgs/fruits.jpg"; FcImage im = fc_load_image(im_pth); const char* title = "fruits"; gtk_show_image_v3(&im, title); return 0; }
其餘注意
使用stb image.h的時候提示須要連接math庫,也就是CMakeLists.txt中target_link_libraries
時加上m
。this