VS中图像处理多线程框架(导入队列、导出队列)

在处理大批量图像的过程中,由于raw data的分辨率很高,或者为多通道图像,不满足后续的处理要求。

为了提高图像的加载速度和处理速度,参考相关网络资源,这里给出了一个简单多线程处理框架。


部分主程序:main.cpp

#if 0

#include <process.h>
#include "comm_def.hpp"
#include "comm_fun.hpp"
#include "img_queue.hpp"


DWORD WINAPI ThreadProc1(LPVOID lpParam);
DWORD WINAPI ThreadProc2(LPVOID lpParam);

HANDLE hMutex;
Queue g_image_queue = NULL;
int g_import_finish = 0;	//所有图像都加载完成
int g_process_finish = 0;	//所有图像都处理完成
int g_temp_save_flag = 0;	//是否保存模板


int export_image(QUEUE_DATA *queue_data)
{
	int ret = 0;
	int flag = 1;

	WaitForSingleObject(hMutex, INFINITE);
	if (isEmpty(g_image_queue))
	{
		cout<<"the queue is empty when exporting"<<endl;
		ret = -1;
	}
	else
	{
		deQueue(g_image_queue, queue_data);
		ret = 0;
	}
	ReleaseMutex(hMutex);
	return ret;
}


void image_proc()
{
	IplImage *p_image = NULL;
	int import_finish;
	char scan_data[8] = {0};
	printf("going to create the template? y/n:");
	scanf("%s",scan_data);
	if (scan_data[0] == 'y' || scan_data[0] == 'Y')
	{
		g_temp_save_flag = 1;
	}
	else
	{
		initial_tmeplate();
		g_temp_save_flag = 0;
	}

	QUEUE_DATA queue_data;
	while (1)
	{
		if (0 == export_image(&queue_data))
		{
			cny_rec(queue_data.p_image, queue_data.file_name);
			cvReleaseImage(&(queue_data.p_image));
		}
		else
		{
			WaitForSingleObject(hMutex, INFINITE);
			import_finish = g_import_finish;
			if (import_finish)
				g_process_finish = 1;
			ReleaseMutex(hMutex);
			if (import_finish)
				break;
			else
				Sleep(500);
		}
	}
	return;
}


//将图像装在到队列
int import_image(const char *file_name, const char *file_path)
{
	int ret = 0;
	int flag = 1;
	IplImage *p_image_read = cvLoadImage(file_path);
	//获取图像缩放后,释放原图像	
	IplImage *p_image_zoom = NULL;
	image_zoom(p_image_read, 1, 0.35, &p_image_zoom); //0.35
	cvReleaseImage(&p_image_read);

	//获取灰度图像后,释放缩放图像
	QUEUE_DATA queue_data;
	queue_data.p_image = cvCreateImage(cvGetSize(p_image_zoom), p_image_zoom->depth, 1);
	memcpy(queue_data.file_name, file_name, sizeof(queue_data.file_name));

	cvCvtColor(p_image_zoom, queue_data.p_image, CV_BGR2GRAY);
	cvReleaseImage(&p_image_zoom);

	char file_path_imp[128] = {0};
	sprintf(file_path_imp, "%s\\%s.bmp",PATH_IMP, file_name);
	cvSaveImage(file_path_imp, queue_data.p_image);

	while (flag)
	{
		WaitForSingleObject(hMutex, INFINITE);
		if (isFull(g_image_queue))
		{
			cout<<"waiting in thread 1"<<endl;
		}
		else
		{
			enQueue(g_image_queue, queue_data);
			flag = 0;
		}
		ReleaseMutex(hMutex);
		Sleep(500);
	}
	//释放
	cvReleaseImage(&(queue_data.p_image));
	return ret;
}

void FindBmpFile(CString strFoldername)  
{  
	CFileFind tempFind;   
	BOOL bFound; //判断是否成功找到文件  
	bFound=tempFind.FindFile(strFoldername   +   "\\*.*");   //修改" "内内容给限定查找文件类型  
	CString strTmp;   //如果找到的是文件夹 存放文件夹路径  
	while(bFound)      //遍历所有文件  
	{   
		bFound=tempFind.FindNextFile(); //第一次执行FindNextFile是选择到第一个文件,以后执行为选择到下一个文件  
		if(tempFind.IsDots())   
			continue; //如果找到的是返回上层的目录 则结束本次查找  
		if(tempFind.IsDirectory())   //找到的是文件夹,则遍历该文件夹下的文件  
		{   
			continue;
			strTmp="";   
			strTmp=tempFind.GetFilePath();  
			tempFind.FindFile(strTmp);   
		}   
		else   
		{   
			strTmp=tempFind.GetFileName(); //保存文件名,包括后缀名  
			// 在此处添加对找到文件的处理 
			char file_name[128] = {0};
			char file_path[128] = {0};
			sprintf(file_name, "%S", strTmp);
			memset(file_name+10, 0x0, sizeof(file_name) - 10);	//去除后缀
			sprintf(file_path, "%S\\%S", strFoldername,strTmp);
			import_image(file_name, file_path);
			printf("load \"%s\" successfully\n",file_path);
		}   
	}
	//没有文件可导入了
	WaitForSingleObject(hMutex, INFINITE);
	g_import_finish = 1;
	ReleaseMutex(hMutex);
	tempFind.Close();   
	return;   
}

int main()
{
	int exit = 0;
	int state = 0;
	HANDLE handle1;
	HANDLE handle2;
	//初始化队列
	g_image_queue = createQueue(50);
	handle1 = CreateThread(NULL, 0, ThreadProc1, NULL, 0, NULL);
	handle2 = CreateThread(NULL, 0, ThreadProc2, NULL, 0, NULL);
	CloseHandle(handle1);
	CloseHandle(handle2);
	hMutex = CreateMutex(NULL, false, NULL);

	//waiting to load image
	Sleep(1000);
	//waiting
	while (1)
	{
		WaitForSingleObject(hMutex, INFINITE);
		state = isEmpty(g_image_queue);
		exit = g_process_finish;
		ReleaseMutex(hMutex);
		if (exit && state)
		{
			Sleep(2000);
			break;
		}
		else
		{
// 			cout<<"delay to exit in main()"<<endl;
			Sleep(2000);
		}	
	}

	//销毁队列
	disPoseQueue(g_image_queue);
	return 0;
}

DWORD WINAPI ThreadProc1(LPVOID lpParam)
{
/*
	while (0)
	{
		WaitForSingleObject(hMutex, INFINITE);
		if (tickets > 0)
		{
			Sleep(1);
			cout<<"thread1 :"<<tickets--<<endl;
		}
		ReleaseMutex(hMutex);
	}
*/
	FindBmpFile(PATH_ORIGINAL);
	cout<<"thread1 exit"<<endl;
	return 0;
}
DWORD WINAPI ThreadProc2(LPVOID lpParam)
{
	int import_finish = 0;
/*
	while (1)
	{
		WaitForSingleObject(hMutex, INFINITE);
		if (tickets > 0)
		{
			Sleep(1);
			cout<<"thread2 :"<<tickets--<<endl;
		}
		ReleaseMutex(hMutex);
	}
*/
	//给时间导入图片
// 	Sleep(1000*25);
	while (!import_finish)
	{
		WaitForSingleObject(hMutex, INFINITE);
		import_finish = g_import_finish;
		ReleaseMutex(hMutex);
		Sleep(1000);
	}

	image_proc();
	cout<<"thread2 exit"<<endl;
	return 0;
}

#endif


队列源文件:image_queue.cpp

//http://blog.csdn.net/cdl2008sky/article/details/8300264
#include "img_queue.hpp"

int isEmpty(Queue q){
	return q->size==0;
}

int isFull(Queue q){
	return q->size==q->capacity;
}

Queue createQueue(int capacity){
	Queue queue;
	queue = (Queue)malloc(sizeof(lqueue));
	if(queue == NULL){
		return NULL;
	}
	//申请空间
	queue->Array = (QUEUE_DATA *)malloc(sizeof(QUEUE_DATA)*capacity);
	if(queue->Array == NULL ){
		return NULL;
	}
	//清零
	memset(queue->Array, 0x0, sizeof(QUEUE_DATA)*capacity);

	queue->capacity = capacity;
	queue->size = 0;
	queue->front = 0;
	queue->rear = -1;
	return queue;
}

void makEmpty(Queue q){
	q->size = 0;
	q->rear = -1;
	q->front = 0;
}

void disPoseQueue(Queue q){
	if(q != NULL)
	{
		if (q->Array != NULL)
		{
			free(q->Array);
		}
		free(q);	
	}
}

/**这个方法实现循环队列,当rear到达尾端(入列),或者front到达尾端(出列),它又回到开头**/
int circularQ(int index,Queue q){
	if(++index > q->capacity){
		return 0;
	}
	return index;
}

/*入列*/
int enQueue(Queue q, QUEUE_DATA queue_data){
	if(isFull(q)){
		printf("Queue is Full\n");
		return -1;
	} else {
		q->size ++;
		q->rear = circularQ(q->rear,q);
		q->Array[q->rear].p_image = cvCloneImage(queue_data.p_image);
		memset(q->Array[q->rear].file_name, 0x0, STR_SIZE);
		memcpy(q->Array[q->rear].file_name, queue_data.file_name, STR_SIZE);
		return 0;
	}
}

/*出列*/
int deQueue(Queue q, QUEUE_DATA *queue_data){
	IplImage *temp_img;
	char *temp_name;
	if(isEmpty(q)){
		printf("queue is Empty\n");
		return -1;
	} else {
		q->size --;
		temp_img = q->Array[q->front].p_image;
		temp_name = q->Array[q->front].file_name;
		queue_data->p_image = cvCloneImage(temp_img);
		memcpy(queue_data->file_name, temp_name, STR_SIZE);
		cvReleaseImage(&temp_img);
		q->front = circularQ(q->front,q);
		return 0;
	}
}

/**取队列头元素**/
QUEUE_DATA *front(Queue q){
	return &(q->Array[q->front]);
}


下载地址: http://download.csdn.net/detail/k_shmily/9583760



Spring Boot可以通过使用多线程来解决顺序写入Workbook的问题。 在Spring Boot,可以使用内置的ThreadPoolTaskExecutor来实现多线程的管理和调度。首先,我们可以在应用程序的配置文件配置ThreadPoolTaskExecutor的参数,如线程池的大小、队列容量等。 接下来,我们需要使用Spring Boot的异步任务注解@Async来标记我们的导出方法。这样,当调用导出方法时,Spring Boot就会将该方法放入线程池执行,而不会阻塞主线程。 在导出方法,我们可以使用Apache POI等工具来创建Workbook,并在多个线程向Workbook写入数据。每个线程负责处理一定数量的数据。为了保证数据的顺序写入,我们可以使用线程安全的数据结构,如ConcurrentLinkedQueue或BlockingQueue来保存每个线程处理的数据。在每个线程处理完数据后,将数据按照顺序写入Workbook。 当所有线程都处理完数据后,我们可以将Workbook保存到文件,或者直接返回给前端。 需要注意的是,多线程写入Workbook可能存在线程安全的问题,如多个线程同时写入同一个单元格。为了解决这个问题,我们可以使用同步锁或原子操作来保证数据的一致性。此外,我们还可以使用线程池的返回结果Future来获取每个线程的执行结果并进行处理。 综上所述,Spring Boot可以通过使用多线程和线程池来解决多线程导出顺序写入Workbook的问题。通过合理的设计和使用线程安全的数据结构,我们可以实现高效、稳定的导出功能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值