再次请教多线程的问题

karen99 2015-12-03 06:50:05
接着上一个问题,http://bbs.csdn.net/topics/391866033?page=1#post-400630961
这个程序有两个线程,一个捕获和显示图像,一个搜集用户输入,因为用了Opencv,必须显示图像才能搜集键盘输入,于是两个线程有两个图像窗口,现在想把这两个线程的图像显示在同一个窗口“ppp“,不知道为什么线程停留在 Capture_Display_Thread, 永远也不执行GUI_Thread()

再次谢谢大家了


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>

using namespace cv;
Mat frame;
Mat keyBoardInput = imread("keyboard_input.png",1);
Mat menu = imread("menu.png",1);
VideoCapture cap(0);
struct Para
{
Mat captureImage;
char keyInput;
char winName[3];
};

pthread_mutex_t dispwindow;
void *GUI_Thread(void * param)
{

//Mat keyBoardInput = imread("keyboard_input.png",1);
Para *p_data = (Para *)param;

while(p_data->captureImage.rows>0 && p_data->captureImage.cols>0)
{
pthread_mutex_lock (&dispwindow);
imshow("ppp",p_data->captureImage);

int key_input=cv::waitKey(30)%256;


if(key_input == 'q' || key_input == 'Q' )
{
p_data->keyInput = key_input;
break;
}
else if(key_input == 'd' || key_input == 'D' || key_input == 'L' || key_input == 'l'
|| key_input == 13 || key_input == 43)//13 enter; 43 +;
{
p_data->keyInput = key_input;
}

pthread_mutex_unlock (&dispwindow);
}

printf("GUI_Thread exited.\n");
pthread_exit(0);
return NULL;
}

void * Capture_Display_Thread(void * param)
{
Para *p_data = (Para *)param;


char key_input;
long exit_code = 0;

// VideoCapture cap(0);
if(!cap.isOpened()) // check if we succeeded
{
exit_code = -2;
}

//pthread_mutex_lock (&dispwindow);
while( p_data->keyInput != 'q' && p_data->keyInput != 'Q')
{
printf("\n displaying Video\n");
cap >> frame; // get a new frame from camera

if((frame.rows > 0) && (frame.cols > 0))
{
pthread_mutex_lock (&dispwindow);
Mat disp = frame.clone();

if(p_data->keyInput == 'd' || p_data->keyInput == 'D')
{
for(int i=100;i<200;i++)
{
for(int j=100;j<200;j++)
{
disp.at<Vec3b>(i,j)[0] = 255;
disp.at<Vec3b>(i,j)[1] = 255;
disp.at<Vec3b>(i,j)[2] = 255;
}
}

}

if(p_data->keyInput == 'l' ||p_data->keyInput == 'L')
{
//Mat menu = imread("menu.png",1);

menu.copyTo(disp(Rect(30,30,menu.cols,menu.rows)));
}

p_data->captureImage = disp.clone();

cv::imshow("ppp", disp);
pthread_mutex_unlock (&dispwindow);

}

waitKey(30);
}
//pthread_mutex_unlock (&dispwindow);
printf("stopped.\n");

pthread_exit((void *)exit_code);
return NULL;
}

int main(int argc, char * argv[])
{
Para mydata;

pthread_t display,gui;
void * exit_disp = NULL;
void * exit_gui = NULL;
pthread_mutex_init(&dispwindow, NULL);

printf("start...\n");
int rc = pthread_create(&gui, NULL, GUI_Thread, (void *)&mydata);

rc = pthread_create(&display, NULL, Capture_Display_Thread, (void *)&mydata);

if(0 != rc) return -1;

pthread_join(display, &exit_disp);


pthread_join(gui, &exit_gui);


// printf("gui = %c\n", mydata);

pthread_mutex_destroy(&dispwindow);
return 0;
}





...全文
252 5 打赏 收藏 转发到动态 举报
写回复
用AI写文章
5 条回复
切换为时间正序
请发表友善的回复…
发表回复
karen99 2015-12-30
  • 打赏
  • 举报
回复
对不起,这些宝贵的代码我也才刚刚看到,太感谢了! 回头一定好好试试!有了你的帮助,真让我信心大增,再次感谢:)
引用 3 楼 chehw_1 的回复:
写了一个用gtk界面来显示opencv图像的小程序 整体功能没写完整, 只是一个简单的不使用highgui库来显式图像/视频的示例 编译环境和使用的库: linux / gtk+2.24 、opencv-2.4.9 $ gcc -Wall -o "test3" "test3.c" -lpthread `pkg-config --cflags opencv` `pkg-config --libs opencv` `pkg-config --cflags gtk+-2.0` `pkg-config --libs gtk+-2.0`
chehw_1 2015-12-05
  • 打赏
  • 举报
回复
...


// 创建GUI窗口
GtkWidget * create_main_window()
{
	GtkWidget * window;
	GtkWidget * vbox;
	GtkWidget * table, * draw_area, * hruler, * vruler;
	
	GtkWidget * hbox;
	GtkWidget * button;
	GtkWidget * separator;
	
	GtkWidget * toggle, * checkbox;
	GSList * group;
	GtkWidget * radio;
	GtkWidget * hscale;
	
	
	// create toplevel window
	gui.window = window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
	gtk_window_set_title(GTK_WINDOW(window), "Video Capture");
	g_signal_connect(window, "destroy", G_CALLBACK(on_destroy), NULL);
	g_signal_connect(window, "delete-event", G_CALLBACK(on_quit_main), NULL);
	gtk_widget_set_size_request(window, 800, 600);
	
	// create a v-direction layout containter
	gui.vbox = vbox = gtk_vbox_new(FALSE, 5);
	gtk_container_set_border_width(GTK_CONTAINER(vbox), 5);
	
	// create drawing area (with ruler)
	table = gtk_table_new(3, 2, FALSE);
	gtk_box_pack_start(GTK_BOX(vbox), table, TRUE, TRUE, 5);
	
	
	gui.draw_area = draw_area = gtk_drawing_area_new();	
	
	gui.image = gtk_image_new();
	//~ gtk_widget_set_size_request(gui.image, 480, 320);
	//~ gtk_widget_set_size_request(draw_area, 600, 400);
	//~ 
	//~ gtk_container_set_border_width(GTK_CONTAINER(draw_area), 20);
	//~ gtk_container_add(GTK_CONTAINER(draw_area), gui.image);
	hbox = gtk_hbox_new(TRUE, 2);	
	gtk_table_attach(GTK_TABLE(table), hbox, 1, 2, 1, 2, (GTK_EXPAND|GTK_FILL), GTK_FILL, 0, 0);
	gtk_box_pack_start(GTK_BOX(hbox), gui.image, TRUE, TRUE, 0);
	gtk_box_pack_start(GTK_BOX(hbox), draw_area, FALSE, TRUE, 0);
	
	gtk_widget_set_events(draw_area, GDK_POINTER_MOTION_MASK|GDK_POINTER_MOTION_HINT_MASK);
	//~ g_signal_connect(draw_area, "expose_event", G_CALLBACK(on_expose_event), NULL);
	
	hruler = gtk_hruler_new();
	gtk_ruler_set_metric(GTK_RULER(hruler), GTK_PIXELS);
	gtk_ruler_set_range(GTK_RULER(hruler), 0.0, 300.0, 0.0, 20.0);
	g_signal_connect_swapped(draw_area, "motion_notify_event", 
			G_CALLBACK(GTK_WIDGET_GET_CLASS(hruler)->motion_notify_event), hruler);
	gtk_table_attach(GTK_TABLE(table), hruler, 1, 2, 0, 1, (GTK_EXPAND|GTK_SHRINK|GTK_FILL), GTK_FILL, 0, 0);
		
	separator = gtk_hseparator_new();
	gtk_box_pack_start(GTK_BOX(vbox), separator, FALSE, TRUE, 5);
	
	vruler = gtk_vruler_new();
	gtk_ruler_set_metric(GTK_RULER(vruler), GTK_PIXELS);
	gtk_ruler_set_range(GTK_RULER(vruler), 0.0, 200, 0.0, 200.0);
	g_signal_connect_swapped(draw_area, "motion_notify_event", 
			G_CALLBACK(GTK_WIDGET_GET_CLASS(vruler)->motion_notify_event), vruler);
	gtk_table_attach(GTK_TABLE(table), vruler, 0, 1, 1, 2, GTK_FILL, (GTK_EXPAND|GTK_SHRINK|GTK_FILL), 0, 0);
		
	//~ separator = gtk_hseparator_new();
	//~ gtk_box_pack_start(GTK_BOX(vbox), separator, FALSE, TRUE, 5);
	
	
	// create a h-direction layout container and pack onto bottom
	hbox = gtk_hbox_new(FALSE, 5);
	gtk_box_pack_end(GTK_BOX(vbox), hbox, FALSE, TRUE, 0);
	
	// create a toggle button to switch the display type from 'static-image' to 'capture'
	gui.toggle = toggle = gtk_toggle_button_new_with_mnemonic("_Cap");
	g_signal_connect(toggle, "toggled", G_CALLBACK(toggle_callback), GUINT_TO_POINTER(FLAG_CAPTURE));
	gtk_box_pack_start(GTK_BOX(hbox), toggle, FALSE, FALSE, 0);
	
	separator = gtk_vseparator_new();
	gtk_box_pack_start(GTK_BOX(hbox), separator, FALSE, TRUE, 5);
	
	// create a check box to show/hide logview output
	checkbox = gtk_check_button_new_with_mnemonic("Show _log window");
	g_signal_connect(checkbox, "toggled", G_CALLBACK(toggle_callback), GUINT_TO_POINTER(FLAG_LOGVIEW));
	gtk_box_pack_start(GTK_BOX(hbox), checkbox, FALSE, FALSE, 5);
	
	separator = gtk_vseparator_new();
	gtk_box_pack_start(GTK_BOX(hbox), separator, FALSE, TRUE, 5);
	
	// create some radio buttons to switch mode
	radio = gtk_radio_button_new_with_mnemonic(NULL, "mode _0");
	g_signal_connect(radio, "toggled", G_CALLBACK(on_radio_toggled), GINT_TO_POINTER(0));
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(radio), TRUE);
	group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(radio));
	gtk_box_pack_start(GTK_BOX(hbox), radio, FALSE, TRUE, 0);
	
	radio = gtk_radio_button_new_with_mnemonic(group, "mode _1");
	group = gtk_radio_button_get_group(GTK_RADIO_BUTTON(radio));
	g_signal_connect(radio, "toggled", G_CALLBACK(on_radio_toggled), GINT_TO_POINTER(1));
	gtk_box_pack_start(GTK_BOX(hbox), radio, FALSE, TRUE, 0);
	
	radio = gtk_radio_button_new_with_mnemonic(group, "mode _2");
	g_signal_connect(radio, "toggled", G_CALLBACK(on_radio_toggled), GINT_TO_POINTER(2));
	gtk_box_pack_start(GTK_BOX(hbox), radio, FALSE, TRUE, 0);
	
	separator = gtk_vseparator_new();
	gtk_box_pack_start(GTK_BOX(hbox), separator, FALSE, TRUE, 0);

	
	
	// create some normal buttons to do something
	button = gtk_button_new_with_mnemonic("_Open");
	gtk_widget_set_size_request(button, 80, 20);
	gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 5);
	g_signal_connect(button, "clicked", G_CALLBACK(on_button_clicked), GINT_TO_POINTER(1));
	
	button = gtk_button_new_with_mnemonic("_Color");
	gtk_widget_set_size_request(button, 80, 20);
	gtk_box_pack_start(GTK_BOX(hbox), button, FALSE, FALSE, 5);
	g_signal_connect(button, "clicked", G_CALLBACK(on_button_clicked), GINT_TO_POINTER(2));
	
	separator = gtk_vseparator_new();
	gtk_box_pack_start(GTK_BOX(hbox), separator, FALSE, TRUE, 0);
	
	
	// create a 'quit' button to exit
	button = gtk_button_new_with_label("quit");
	gtk_widget_set_size_request(button, 80, 20);
	gtk_box_pack_end(GTK_BOX(hbox), button, FALSE, TRUE, 0);
	g_signal_connect_swapped(button, "clicked", G_CALLBACK(gtk_widget_destroy), (gpointer)window);
	
	
	// create a h-direction layout container and pack onto bottom
	hbox = gtk_hbox_new(FALSE, 5);
	gtk_box_pack_end(GTK_BOX(vbox), hbox, FALSE, TRUE, 0);
	
	// creat a trackbar (range widget) 
	GtkObject * adjust = gtk_adjustment_new(0.0, 0.0, 110.0, 0.5, 5.0, 10.0);	
	 
	gui.hscale = hscale = gtk_hscale_new(GTK_ADJUSTMENT(adjust));
	gtk_widget_set_size_request(hscale, 200, -1);
	
	gtk_range_set_update_policy(GTK_RANGE(hscale), GTK_UPDATE_CONTINUOUS);
	gtk_scale_set_digits(GTK_SCALE(hscale), 1);
	gtk_scale_set_value_pos(GTK_SCALE(hscale), GTK_POS_TOP);
	gtk_scale_set_draw_value(GTK_SCALE(hscale), TRUE);
	
	gtk_box_pack_start(GTK_BOX(hbox), hscale, TRUE, TRUE, 0);
	
	
	
	
	
	gtk_container_add(GTK_CONTAINER(window), vbox);
	gtk_widget_show_all(window);
	return window;
}


// toggle and check button的回调函数
void toggle_callback(GtkWidget * widget, gpointer data)
{
	guint flag = GPOINTER_TO_UINT(data);

	if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
	{
		gui.uflags |= flag;
	}else
	{
		gui.uflags &= ~flag;
	}

	if(flag < FLAG_LOGVIEW)
	{
		// signal was sent by the toggle button
		if(gui.uflags & FLAG_CAPTURE)
		{
			g_print("display capture ...\n");
			StartCapture();
			
		}else
		{
			StopCapture();
			g_print("display static image ...\n");
		}
	}
	else
	{
		// signal was sent by the checkbox
		if(gui.uflags & FLAG_LOGVIEW)
		{
			g_print("show logview...\n");
		}else
		{
			g_print("hide logview...\n");
		}
	}
	
}

// radio按钮的回调函数
void on_radio_toggled(GtkWidget * widget, gpointer data)
{
	if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
	{
		gui.mode = GPOINTER_TO_INT(data);
		switch(gui.mode)
		{
		case 0: 
			// do sth.			
			break;
		case 1: // do sth.
			break;
		case 2: // do sth.
			break;
		default:
			return;
		}
		g_print("mode = %d\n", gui.mode);
	}
}

// 当在"色彩选择器"对话框中选取了某一颜色时, 更改右侧绘图区的背景
static void on_color_changed(GtkWidget * widget, GtkColorSelection * color_sel)
{
	GdkColor color;
	gtk_color_selection_get_current_color(color_sel, &color);
	gtk_widget_modify_bg(gui.draw_area, GTK_STATE_NORMAL, &color);
	
}

// 点击按钮时, 做相应的处理
void on_button_clicked(GtkWidget * widget, gpointer data)
{
	gint id = GPOINTER_TO_INT(data);
	int rc;
	
	if(1 == id) // button 1 clicked
	{
		// do sth.
	
	}else if(2 == id) // button 2 clicked
	{
		// 点击button2 按钮时, 打开色彩选择器对话框
		
		GtkColorSelection * color_sel;
		GtkWidget * dlg;
		
		dlg = gtk_color_selection_dialog_new("Change color");
		color_sel = GTK_COLOR_SELECTION(GTK_COLOR_SELECTION_DIALOG(dlg)->colorsel);
		
		gtk_color_selection_set_previous_color(color_sel, &gui.color);
		gtk_color_selection_set_current_color(color_sel, &gui.color);
		gtk_color_selection_set_has_palette(color_sel, TRUE);
		
		g_signal_connect(color_sel, "color_changed", G_CALLBACK(on_color_changed), (gpointer)color_sel);
		
		rc = gtk_dialog_run(GTK_DIALOG(dlg));
		
		if(GTK_RESPONSE_OK == rc)
		{
			gtk_color_selection_get_current_color(color_sel, &gui.color);
		}else
		{
			gtk_widget_modify_bg(gui.draw_area, GTK_STATE_NORMAL, &gui.color);
		}
		
		gtk_widget_destroy(dlg);
		
		
	}
}


chehw_1 2015-12-05
  • 打赏
  • 举报
回复
写了一个用gtk界面来显示opencv图像的小程序 整体功能没写完整, 只是一个简单的不使用highgui库来显式图像/视频的示例 编译环境和使用的库: linux / gtk+2.24 、opencv-2.4.9 $ gcc -Wall -o "test3" "test3.c" -lpthread `pkg-config --cflags opencv` `pkg-config --libs opencv` `pkg-config --cflags gtk+-2.0` `pkg-config --libs gtk+-2.0`

/*
 * test3.c
 * 
 * Copyright 2015 Che Hongwei <htc.chehw@gmail.com>
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301, USA.
 * 
 * 
 */


#include <stdio.h>
#include <opencv/cv.h>
#include <opencv/cxcore.h>
#include <opencv/highgui.h>

//~ #include <opencv2/core/core_c.h>
//~ #include <opencv2/imgproc/imgproc_c.h>
//~ #include <opencv2/highgui/highgui_c.h>

#include <gtk/gtk.h>

typedef struct GUI_PARAM
{
	GtkWidget * window;
	GtkWidget * vbox;
	GtkWidget * draw_area;
	GtkWidget * toggle;
	GtkWidget * logview;
	GtkWidget * statusbar;
	GtkWidget * hscale;
	
	GdkColor color;
	
	guint 		uflags;
	gint	 	mode;
	
	gint 		timer;
	gboolean	running;
	
	GtkWidget * image;
	
	CvCapture * capture;
}GUI_PARAM_t;

GUI_PARAM_t gui;

enum GLOBAL_FLAGS
{	
	FLAG_STATIC_IMAGE = 0,
	FLAG_CAPTURE = 1,
	FLAG_LOGVIEW = 2
};

GtkWidget * create_main_window();


int main(int argc, char **argv)
{
	gdk_threads_init();
	gtk_init(&argc, &argv);
	
	create_main_window();	
	
	gtk_main();	
	return 0;
}

void toggle_callback(GtkWidget * widget, gpointer data);
void on_radio_toggled(GtkWidget * widget, gpointer data);
void on_button_clicked(GtkWidget * widget, gpointer data);

// 在timeout中读取从摄像头中捕获的图像, 
// 根据需要进行加工处理后, 用Gtk的GtkImage部件来显示
static gboolean on_timeout(gpointer data)
{
	// 界面左下角的切换按钮可以控制[启动]/[终止]捕获
	if(NULL == gui.capture) { // 如果当前没启动捕获, 则不做任何处理
		return TRUE;
	}
	
	IplImage * frame = cvQueryFrame(gui.capture); // 读取当前捕获到的帧
	
	IplImage * output = NULL;
	IplImage * temp;
	GdkPixbuf * pix;
	unsigned char * imageData = NULL;
	
	
	if(NULL == frame)
	{
		g_printerr("cvQueryFrame failed.\n");
		return TRUE;
	}
	
	switch(gui.mode)	// 界面下方放了三个radio按钮, 用于切换显式效果
	{
		case 0: // 直接显式
			// opencv默认的色彩方案是BGR模式, 在gtk的界面下显式则需要先转换为RGB模式
			output = cvCreateImage(cvGetSize(frame), frame->depth, frame->nChannels);
			if(NULL != output)
			{
				cvCvtColor(frame, output, CV_BGR2RGB);
			}
			break;
		case 1: // 转换为灰度图
			temp = cvCreateImage(cvGetSize(frame), IPL_DEPTH_8U, 1);
			output = cvCreateImage(cvGetSize(frame), IPL_DEPTH_8U, 3);
			
			//~ memset(output, 0, sizeof(IplImage));
			cvCvtColor(frame, temp, CV_BGR2GRAY);
			cvCvtColor(temp, output, CV_GRAY2RGB);
			cvReleaseImage(&temp);
			break;
			
		case 2: // 模糊(柔化)处理
			// opencv-2.4.9可能有bug, 在C下直接用 cvCreateImage / cvSmooth后,无法回收内存:
			// 一旦调用cvReleaseImage,就会出现Segmentation fault
			// 有可能是在某些函数内部被opencv库用c++的new分配了内存, 而釋放時可能用的是free
			// 目前的解决方法是:
			// 用malloc为imageData分配内存, 然后调用 cvCreateImageHeader + cvSetData 来替代 cvCreateImage
			imageData = (unsigned char *)malloc(frame->widthStep * frame->height * frame->nChannels);
			temp = cvCreateImageHeader(cvGetSize(frame), IPL_DEPTH_8U, 3);			
			cvSetData(temp, imageData, frame->widthStep * frame->nChannels);
			
			output = cvCreateImage(cvGetSize(frame), IPL_DEPTH_8U, 3);
			cvSmooth(frame, temp, CV_GAUSSIAN, 3, 3, 0.0, 0.0);
			cvCvtColor(temp, output, CV_BGR2RGB);
			
			cvReleaseImageHeader(&temp);
			free(imageData);
			
			break;
	}
	
	if(NULL != output)
	{
		// 将图像的数据转换为GdkPix格式, 并在GtkImage控件中显示
		pix = gdk_pixbuf_new_from_data((const guchar *)output->imageData,
				GDK_COLORSPACE_RGB, FALSE,
				output->depth, output->width, output->height,
				output->widthStep,
				NULL, NULL);
		
		cvReleaseImage(&output);
		
		gtk_image_set_from_pixbuf(GTK_IMAGE(gui.image), pix);		
		g_object_unref(pix);
		gtk_widget_queue_draw(gui.image);	
	}
	
	return TRUE;
}

static void StartCapture()
{
	if(NULL == gui.capture)
	{
		gui.capture = cvCreateCameraCapture(0);
		//~ gui.capture = cvCaptureFromCAM(0);
		if(NULL == gui.capture)
		{
			perror("cvCreateCameraCapture failed.\n");
			return;
		}
	}
	
	if(!gui.running) // 如果定时器没启动
	{
		// 设置定时器, 大约每33毫秒读取一帧(30fps)
		gui.timer = g_timeout_add(33, (GSourceFunc)on_timeout, NULL);
		gui.running = TRUE;
	}	
	
}

static void StopCapture()
{
	if(gui.running)
	{
		gtk_timeout_remove(gui.timer);
		gui.running = FALSE;
	}
}


static gboolean on_quit_main(GtkWidget * widget, GdkEvent * event, gpointer data)
{
	StopCapture();
	if(NULL != gui.capture)
	{
		cvReleaseCapture(&gui.capture);
		gui.capture = NULL;
	}
	gtk_main_quit();
	return FALSE;
}

static void on_destroy(GtkWidget * widget, gpointer data)
{
	StopCapture();
	if(NULL != gui.capture)
	{
		cvReleaseCapture(&gui.capture);
		gui.capture = NULL;
	}
	gtk_main_quit();
}

// 一层写不下,后面还有...
karen99 2015-12-04
  • 打赏
  • 举报
回复
谢谢你的代码,又占用你宝贵的时间了。其实我也记得你的忠告,不要随便用多线程,而且我对底层的东西真的不太了解,也不喜欢多线程,调试起来真麻烦,可是老板执意要用多线程,可能是考虑到以后系统会更加复杂,连框图都给我画好了,我也没有办法,只好当是个学习的机会了,可是圣诞前要出东西,就有点着急,谢谢你帮我省了不少时间。 其实我只是用OpenCV highgui 显示图像,没有用任何其他的GUI库,界面都是我自己画到图像上去的,然后根据键盘输入决定什么时候显示什么界面。 是不是只要用OpenCV显示图像,就一定用到highgui了?如何不用Highgui呢? 还想小声说,我也特别喜欢C,不喜欢C++,觉得C++调试起来特别麻烦。一直以为是我没有写过大程序的缘故,都不敢跟别人说。看到有丰富编程经验的人也有同好,真的很开心。其实我也看过一个特别庞大的视频特效程序,写程序的人一定是个专家,那么复杂的程序他也是用C写的,参数一堆一堆的,看来真的是个人喜好问题?估计C++程序员不这么认为。 再次感谢你的程序,你的时间,和你的分享:)
引用 1 楼 chehw_1 的回复:
能用单线程实现时,就最好不要使用多线程。 一般GUI库都有自己的消息(或事件、信号)处理机制,通常单线程的就可以实现你所需要的功能。 highgui是一个轻量级的GUI库,欠缺很多功能,最好不要轻易使用多线程(除非你能够对底层有深入了解,确切地知道你在做什么)。 下面是一个用C实现的在单线程下处理键盘消息的示例(PS:不好意思,用的是C代码;因为我对C有强烈偏好,对C++有抵触),你可以试着用C++改写一下。 如果对opencv的底层实现有一定了解,完全可以不使用highgui,而是用自己熟悉的GUI库来显式经opencv处理后的图像(稍微有点儿复杂,就不写示例了)。
chehw_1 2015-12-04
  • 打赏
  • 举报
回复
能用单线程实现时,就最好不要使用多线程。 一般GUI库都有自己的消息(或事件、信号)处理机制,通常单线程的就可以实现你所需要的功能。 highgui是一个轻量级的GUI库,欠缺很多功能,最好不要轻易使用多线程(除非你能够对底层有深入了解,确切地知道你在做什么)。 下面是一个用C实现的在单线程下处理键盘消息的示例(PS:不好意思,用的是C代码;因为我对C有强烈偏好,对C++有抵触),你可以试着用C++改写一下。


#include <stdio.h>
#include <opencv/cv.h>
#include <opencv/highgui.h>
#include <opencv/cxcore.h>

const char * cap_winname = "Capture Window";
//~ const char * result_winname = "Result Window";

int display_capture(const char * window_name)
{
	int ret = -1;
	CvCapture * capture = cvCreateCameraCapture(0);
	if(NULL == capture) return ret;
	IplImage * frame;
	
	IplImage * menu = cvLoadImage("menu.png", CV_LOAD_IMAGE_COLOR);
	
	char cmd;
	char flags = 0;
	while(1)
	{
		frame = cvQueryFrame(capture);
		if(NULL == frame) break;
		IplImage * output;
		
		cmd = cvWaitKey(33);
		switch(cmd)
		{
			case 'q': case 'Q':  // 按‘q’键退出
				ret = 0;
				goto label_quit;				
			case 'l': case 'L': //显示 menu.png
				flags = 'l';
				break;
			case 'd': case 'D': // 对frame帧进行处理,比如smooth
				flags = 'd';
				break;				
			//default:
			case 27: // 按'ESC'建返回默认状态
				flags = 0;
				break;
			default:
				break;
		}
		
		if(flags == 'l')
		{
			cvShowImage(window_name, menu);
		}else if(flags == 'd')
		{
			output = cvCreateImage(cvGetSize(frame), IPL_DEPTH_8U, 3);			
			cvSmooth(frame, output, CV_GAUSSIAN, 3, 3, 0, 0);
			cvShowImage(window_name, output);
			cvReleaseImage(&output);
			
		}else
			cvShowImage(window_name, frame);
	
	}
	
	
	
label_quit:
	printf("quit\n");
	cvReleaseImage(&menu);
	cvReleaseCapture(&capture);
	return ret;
	
}

int main(int argc, char **argv)
{
	cvNamedWindow(cap_winname, CV_WINDOW_AUTOSIZE);
//	cvNamedWindow(result_winname, CV_WINDOW_AUTOSIZE);
	
	display_capture(cap_winname);
	
	
	cvDestroyAllWindows();
	return 0;
}

如果对opencv的底层实现有一定了解,完全可以不使用highgui,而是用自己熟悉的GUI库来显式经opencv处理后的图像(稍微有点儿复杂,就不写示例了)。

23,118

社区成员

发帖
与我相关
我的任务
社区描述
Linux/Unix社区 应用程序开发区
社区管理员
  • 应用程序开发区社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧