#define VERSIONE_PROGRAMMA "Webcam Viewer v0.01.01"
#include <cstdlib>
#include <iostream>
#include <windows.h>
#include <string.h>
#include <math.h>
#include <time.h>
using namespace std;
//webcam
#include <Vfw.h>
#pragma comment(lib,"Vfw32.lib")
//gtk+
#include <gtk/gtk.h>
#pragma comment(lib,"atk-1.0.lib")
#pragma comment(lib,"cairo.lib")
#pragma comment(lib,"gio-2.0.lib")
#pragma comment(lib,"glib-2.0.lib")
#pragma comment(lib,"gmodule-2.0.lib")
#pragma comment(lib,"gobject-2.0.lib")
#pragma comment(lib,"gthread-2.0.lib")
#pragma comment(lib,"gailutil.lib")
#pragma comment(lib,"gdk_pixbuf-2.0.lib")
#pragma comment(lib,"gdk-win32-2.0.lib")
#pragma comment(lib,"gtk-win32-2.0.lib")
#pragma comment(lib,"pango-1.0.lib")
#pragma comment(lib,"pangocairo-1.0.lib")
#pragma comment(lib,"pangoft2-1.0.lib")
#pragma comment(lib,"pangowin32-1.0.lib")
//macro
inline char char_conversion(int c){ return ( (c)<255) ? (c) : 255; }
//variabili
GtkWidget *finestra1;
GtkWidget *draw_area, *draw_area_sobel;
GtkWidget *area_box;
PangoLayout *testo_draw_area;
long frame_count = 0;
int global_frame_width;
int global_frame_row_size;
char *video_text;
clock_t global_time_start, global_time_current;
guchar * bit24format;
guchar * bit24format_sobel;
long bit24format_size;
unsigned char ****tabella_yuy2_rgb;
//funzioni
int webcam();
gboolean expose_event_callback (GtkWidget *widget, GdkEventExpose *event, gpointer data); //callback per drawing area
LRESULT FrameCallbackProc(HWND hWnd, LPVIDEOHDR lpVHdr); //callback per cap
int main(int argc, char *argv[])
{
GError ** thread_error;
thread_error = NULL;
if( ! g_thread_supported() )
g_thread_init( NULL );
gtk_init (&argc, &argv);
//********** FINESTRA1 *************//
finestra1 = gtk_window_new(GTK_WINDOW_TOPLEVEL); //creo la finestra principale
gtk_window_set_title(GTK_WINDOW(finestra1), VERSIONE_PROGRAMMA); //setto il titolo della finestra principale
gtk_container_set_border_width(GTK_CONTAINER(finestra1), 3); //setto il bordo della finestra principale
gtk_window_set_resizable(GTK_WINDOW(finestra1), FALSE); //rendo non resizable la finestra principale
g_signal_connect(G_OBJECT(finestra1), "delete_event", G_CALLBACK(gtk_main_quit), NULL);
//box
area_box = gtk_hbox_new(FALSE, 1);
draw_area = gtk_drawing_area_new();
gtk_widget_set_size_request(draw_area, 640, 400);
gtk_box_pack_start(GTK_BOX(area_box), draw_area, TRUE, TRUE, 0);
g_signal_connect (G_OBJECT (draw_area), "expose_event", G_CALLBACK (expose_event_callback), NULL);
testo_draw_area = gtk_widget_create_pango_layout(draw_area, "PangoLayout");
draw_area_sobel = gtk_drawing_area_new();
gtk_widget_set_size_request(draw_area_sobel, 640, 400);
gtk_box_pack_start(GTK_BOX(area_box), draw_area_sobel, TRUE, TRUE, 0);
g_signal_connect (G_OBJECT (draw_area_sobel), "expose_event", G_CALLBACK (expose_event_callback), NULL);
gtk_container_add(GTK_CONTAINER(finestra1), area_box);
gtk_widget_show_all(finestra1);
g_thread_create((GThreadFunc) webcam, NULL, 0, thread_error);
gtk_main();
return EXIT_SUCCESS;
}
int webcam(){
long x,y,z,h;
CAPSTATUS status;
LPBITMAPINFO video_format;
DWORD dwSize;
HWND hwnd = capCreateCaptureWindow("Explorer", WS_ICONIC, 0, 0, 640, 400, NULL, 0);
capDriverConnect(hwnd, 0);
capPreviewRate(hwnd, 66); // rate, in milliseconds
capPreview(hwnd, TRUE); // starts preview
capSetCallbackOnFrame(hwnd, FrameCallbackProc);
//video format
dwSize = capGetVideoFormatSize(hwnd);
video_format = (LPBITMAPINFO) malloc (dwSize * sizeof(char));
video_text = (char *) malloc(200 * sizeof(char));
capGetVideoFormat(hwnd, video_format, dwSize);
printf("video format: bit per pixel: %d compressione: %d\n", video_format->bmiHeader.biBitCount, video_format->bmiHeader.biCompression);
if(video_format->bmiHeader.biBitCount != 16 || video_format->bmiHeader.biCompression != 844715353){
printf("Video format non compatibile.\n");
printf("formati supportati:\n");
printf("1 - 16bit con compressione 844715353\n");
return 0;
}
//cap status
capGetStatus(hwnd, &status, sizeof(CAPSTATUS));
printf("cap status: %dx%d preview_status: %d\n", status.uiImageWidth, status.uiImageHeight, status.fLiveWindow);
bit24format_size = status.uiImageWidth*status.uiImageHeight*3;
bit24format = new guchar[bit24format_size];
bit24format_sobel = new guchar[bit24format_size];
global_frame_width = status.uiImageWidth;
global_frame_row_size = status.uiImageWidth*2;
//creazione tabella di conversione yuy2 to rgb
printf("preparazione tabella yuy2 to rgb... ");
tabella_yuy2_rgb = new unsigned char ***[3];
for(h=0;h<3;h++){
tabella_yuy2_rgb[h] = new unsigned char **[256];
for(x=0;x<256;x++){
tabella_yuy2_rgb[h][x] = new unsigned char *[256];
for(y=0;y<256;y++)
tabella_yuy2_rgb[h][x][y] = new unsigned char[256];
}
}
for(x=0;x<256;x++)
for(y=0;y<256;y++)
for(z=0;z<256;z++){
tabella_yuy2_rgb[0][x][y][z] = char_conversion(abs( x + 1.371*(y - 128) ));
tabella_yuy2_rgb[1][x][y][z] = char_conversion(abs( x - 0.698*(y - 128) - 0.336*(z - 128) ));
tabella_yuy2_rgb[2][x][y][z] = char_conversion(abs( x + 1.732*(z - 128) ));
}
printf("fatto!\n");
//inizio visualizzazione immagini
global_time_start = clock();
for(x=0;x<1000;x++){
capGrabFrameNoStop(hwnd);
//Sleep(5);
}
capCaptureStop(hwnd);
capSetCallbackOnFrame(hwnd, NULL);
capDriverDisconnect(hwnd);
return 1;
}
gboolean expose_event_callback(GtkWidget *widget, GdkEventExpose *event, gpointer data)
{
gdk_draw_arc (widget->window,
widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
TRUE,
0, 0, widget->allocation.width, widget->allocation.height,
0, 64 * 360);
return TRUE;
}
LRESULT FrameCallbackProc(HWND hWnd, LPVIDEOHDR frame) {
register long x,y=0, dietro=0;
int Y1, Y2, Cb, Cr;
int vsobel, hsobel;
unsigned char sobel;
float angolo;
global_time_current = clock()-global_time_start;
sprintf(video_text, "frame count: %d\ntime: %d ms\navarage frame rate: %.2f",
frame_count, global_time_current, (float)frame_count*1000/global_time_current);
for(x=0;x<bit24format_size;){ //frame->lpData[y]
Y1 = frame->lpData[y++];
Cb = frame->lpData[y++];
Y2 = frame->lpData[y++];
Cr = frame->lpData[y++];
//***** normal video part
bit24format[x++] = tabella_yuy2_rgb[0][Y1][Cr][Cb]; //red
bit24format[x++] = tabella_yuy2_rgb[1][Y1][Cr][Cb]; //green
bit24format[x++] = tabella_yuy2_rgb[2][Y1][Cr][Cb]; //blue
bit24format[x++] = tabella_yuy2_rgb[0][Y2][Cr][Cb]; //red
bit24format[x++] = tabella_yuy2_rgb[1][Y2][Cr][Cb]; //green
bit24format[x++] = tabella_yuy2_rgb[2][Y2][Cr][Cb]; //blue
//****** sobel part
if(y > global_frame_row_size && y < frame->dwBytesUsed-global_frame_row_size){
x -= 6;
//algoritmo di sobel
hsobel = (int)
frame->lpData[y-6-global_frame_row_size]
- frame->lpData[y-2-global_frame_row_size]
+ frame->lpData[y-6] + frame->lpData[y-6]
- frame->lpData[y-2] - frame->lpData[y-2]
+ frame->lpData[y-6+global_frame_row_size]
- frame->lpData[y-2+global_frame_row_size]
;
vsobel = (int)
frame->lpData[y-6-global_frame_row_size]
+ frame->lpData[y-4-global_frame_row_size] + frame->lpData[y-4-global_frame_row_size]
+ frame->lpData[y-2-global_frame_row_size]
- frame->lpData[y-6+global_frame_row_size]
- frame->lpData[y-4+global_frame_row_size] - frame->lpData[y-4+global_frame_row_size]
- frame->lpData[y-2+global_frame_row_size]
;
sobel = char_conversion(abs(hsobel) + abs(vsobel));
bit24format_sobel[x++] = sobel;
bit24format_sobel[x++] = sobel;
bit24format_sobel[x++] = sobel;
hsobel = (int)
frame->lpData[y-4-global_frame_row_size]
- frame->lpData[y-global_frame_row_size]
+ frame->lpData[y-4] + frame->lpData[y-4]
- frame->lpData[y] - frame->lpData[y]
+ frame->lpData[y-4+global_frame_row_size]
- frame->lpData[y+global_frame_row_size]
;
vsobel = (int)
frame->lpData[y-4-global_frame_row_size]
+ frame->lpData[y-2-global_frame_row_size] + frame->lpData[y-2-global_frame_row_size]
+ frame->lpData[y-global_frame_row_size]
- frame->lpData[y-4+global_frame_row_size]
- frame->lpData[y-2+global_frame_row_size] - frame->lpData[y-2+global_frame_row_size]
- frame->lpData[y+global_frame_row_size]
;
sobel = char_conversion(abs(hsobel) + abs(vsobel));
bit24format_sobel[x++] = sobel;
bit24format_sobel[x++] = sobel;
bit24format_sobel[x++] = sobel;
}
}
gdk_draw_rgb_image(draw_area->window,
draw_area->style->fg_gc[GTK_WIDGET_STATE(draw_area)],
0, 0, 640, 400, GDK_RGB_DITHER_NORMAL,
bit24format, 640 * 3);
gdk_draw_rgb_image(draw_area_sobel->window,
draw_area_sobel->style->fg_gc[GTK_WIDGET_STATE(draw_area_sobel)],
0, 0, 640, 400, GDK_RGB_DITHER_NORMAL,
bit24format_sobel, 640 * 3);
pango_layout_set_text(testo_draw_area, video_text, strlen(video_text));
gdk_draw_layout(draw_area->window, draw_area->style->fg_gc[GTK_WIDGET_STATE(draw_area)], 10, 10, testo_draw_area);
frame_count++;
return (LRESULT) TRUE ;
}