CPU_并行(多线程)旋转图片

并行(多线程)旋转图片

代码

ImageStuff.h

struct ImgProp
{
   int Hpixels;
   int Vpixels;
   unsigned char HeaderInfo[54];
   unsigned long int Hbytes;
};

struct Pixel
{
   unsigned char R;
   unsigned char G;
   unsigned char B;
};

unsigned char** CreateBlankBMP();
unsigned char** ReadBMP(char* );
void WriteBMP(unsigned char** , char*);

extern struct ImgProp 	ip;

ImageStuff.c

#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>

#include "ImageStuff.h"


unsigned char** CreateBlankBMP()
{
   int i,j;

   unsigned char** img = (unsigned char **)malloc(ip.Vpixels * sizeof(unsigned char*));
   for(i=0; i<ip.Vpixels; i++){
       img[i] = (unsigned char *)malloc(ip.Hbytes * sizeof(unsigned char));
   	memset((void *)img[i],0,(size_t)ip.Hbytes); // zero out every pixel
   }
   return img;
}


unsigned char** ReadBMP(char* filename)
{
   int i;
   FILE* f = fopen(filename, "rb");
   if(f == NULL){
   	printf("\n\n%s NOT FOUND\n\n",filename);
   	exit(1);
   }

   unsigned char HeaderInfo[54];
   fread(HeaderInfo, sizeof(unsigned char), 54, f); // read the 54-byte header

   // extract image height and width from header
   int width = *(int*)&HeaderInfo[18];
   int height = *(int*)&HeaderInfo[22];

   //copy header for re-use
   for(i=0; i<54; i++) {
   	ip.HeaderInfo[i] = HeaderInfo[i];
   }

   ip.Vpixels = height;
   ip.Hpixels = width;
   int RowBytes = (width*3 + 3) & (~3);
   ip.Hbytes = RowBytes;

   printf("\n   Input BMP File name: %20s  (%u x %u)",filename,ip.Hpixels,ip.Vpixels);

   unsigned char tmp;
   unsigned char **TheImage = (unsigned char **)malloc(height * sizeof(unsigned char*));
   for(i=0; i<height; i++) {
   	TheImage[i] = (unsigned char *)malloc(RowBytes * sizeof(unsigned char));
   }

   for(i = 0; i < height; i++) {
   	fread(TheImage[i], sizeof(unsigned char), RowBytes, f);
   }
   fclose(f);
   return TheImage;  // remember to free() it in caller!
}


void WriteBMP(unsigned char** img, char* filename)
{
   FILE* f = fopen(filename, "wb");
   if(f == NULL){
   	printf("\n\nFILE CREATION ERROR: %s\n\n",filename);
   	exit(1);
   }

   unsigned long int x,y;
   unsigned char temp;

   //write header
   for(x=0; x<54; x++) {	fputc(ip.HeaderInfo[x],f);	}

   //write data
   for(x=0; x<ip.Vpixels; x++) {
   	for(y=0; y<ip.Hbytes; y++){
   		temp=img[x][y];
   		fputc(temp,f);
   	}
   }
   printf("\n  Output BMP File name: %20s  (%u x %u)",filename,ip.Hpixels,ip.Vpixels);
   fclose(f);
}

imrotate.c

#include <pthread.h>
#include <stdint.h>
#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <sys/time.h>

#include "ImageStuff.h"

#define REPS 	     1
#define MAXTHREADS   128

long  			NumThreads;         		// Total number of threads working in parallel
int 	     	ThParam[MAXTHREADS];		// Thread parameters ...
double			RotAngle;					// rotation angle
pthread_t      	ThHandle[MAXTHREADS];		// Thread handles
pthread_attr_t 	ThAttr;						// Pthread attrributes
void* (*RotateFunc)(void *arg);				// Function pointer to rotate the image (multi-threaded)

unsigned char**	TheImage;					// This is the main image
unsigned char**	CopyImage;					// This is the copy image
struct ImgProp 	ip;


void *Rotate(void* tid)
{
   long tn;            		     // My thread number (ID) is stored here
   int row,col,h,v,c;
   int NewRow,NewCol;
   double X, Y, newX, newY, ScaleFactor;
   double Diagonal, H, V;
   struct Pixel pix;

   tn = *((int *) tid);           // Calculate my Thread ID
   tn *= ip.Vpixels/NumThreads;
   
   for(row=tn; row<tn+ip.Vpixels/NumThreads; row++)
   {
       col=0;
       while(col<ip.Hpixels*3)
       {
   		// transpose image coordinates to Cartesian coordinates
   		c=col/3;  		h=ip.Hpixels/2;   v=ip.Vpixels/2;	// integer div
   		X=(double)c-(double)h;
   		Y=(double)v-(double)row;
   		
   		// image rotation matrix
   		newX=cos(RotAngle)*X-sin(RotAngle)*Y;
   		newY=sin(RotAngle)*X+cos(RotAngle)*Y;
   		
   		// Scale to fit everything in the image box
   		H=(double)ip.Hpixels;
   		V=(double)ip.Vpixels;
   		Diagonal=sqrt(H*H+V*V);
   		ScaleFactor=(ip.Hpixels>ip.Vpixels) ? V/Diagonal : H/Diagonal;
   		newX=newX*ScaleFactor;
   		newY=newY*ScaleFactor;
   		
   		// convert back from Cartesian to image coordinates
   		NewCol=((int) newX+h);
   		NewRow=v-(int)newY;     
   		if((NewCol>=0) && (NewRow>=0) && (NewCol<ip.Hpixels) && (NewRow<ip.Vpixels)){
   			NewCol*=3;
   			CopyImage[NewRow][NewCol]   = TheImage[row][col];
   			CopyImage[NewRow][NewCol+1] = TheImage[row][col+1];
   			CopyImage[NewRow][NewCol+2] = TheImage[row][col+2];
           }
           col+=3;
       }
   }
   pthread_exit(NULL);
}


int main(int argc, char** argv)
{
   int					RotDegrees;
   int 				a,i,ThErr;
   struct timeval 		t;
   double         		StartTime, EndTime;
   double         		TimeElapsed;
   
   switch (argc){
   	case 3 : NumThreads=1; 				RotDegrees=45;					break;
   	case 4 : NumThreads=1;  			RotDegrees = atoi(argv[3]);		break;
   	case 5 : NumThreads=atoi(argv[4]);  RotDegrees = atoi(argv[3]);		break;
   	default: printf("\n\nUsage: imrotate inputBMP outputBMP [RotAngle] [NumThreads : 1-128]");
   			 printf("\n\nExample: imrotate infilename.bmp outname.bmp 45 8\n\n");
   			 printf("\n\nExample: imrotate infilename.bmp outname.bmp -75\n\n");
   			 printf("\n\nNothing executed ... Exiting ...\n\n");
   			exit(EXIT_FAILURE);
   }
   if((NumThreads<1) || (NumThreads>MAXTHREADS)){
           printf("\nNumber of threads must be between 1 and %u... \n",MAXTHREADS);
           printf("\n'1' means Pthreads version with a single thread\n");
   		 printf("\n\nNothing executed ... Exiting ...\n\n");
           exit(EXIT_FAILURE);
   }
   if((RotDegrees<-360) || (RotDegrees>360)){
           printf("\nRotation angle of %d degrees is invalid ...\n",RotDegrees);
           printf("\nPlease enter an angle between -360 and +360 degrees ...\n");
   		 printf("\n\nNothing executed ... Exiting ...\n\n");
           exit(EXIT_FAILURE);
   }
   printf("\nExecuting the Pthreads version with %li threads ...\n",NumThreads);
   RotAngle=2*3.141592/360.000*(double) RotDegrees;   // Convert the angle to radians
   printf("\nRotating image by %d degrees (%5.4f radians) ...\n",RotDegrees,RotAngle);
   RotateFunc=Rotate;

   TheImage = ReadBMP(argv[1]);
   CopyImage = CreateBlankBMP();

   gettimeofday(&t, NULL);
   StartTime = (double)t.tv_sec*1000000.0 + ((double)t.tv_usec);
   
   pthread_attr_init(&ThAttr);
   pthread_attr_setdetachstate(&ThAttr, PTHREAD_CREATE_JOINABLE);
   for(a=0; a<REPS; a++){
   	for(i=0; i<NumThreads; i++){
   		ThParam[i] = i;
   		ThErr = pthread_create(&ThHandle[i], &ThAttr, RotateFunc, (void *)&ThParam[i]);
   		if(ThErr != 0){
   			printf("\nThread Creation Error %d. Exiting abruptly... \n",ThErr);
   			exit(EXIT_FAILURE);
   		}
   	}
   	pthread_attr_destroy(&ThAttr);
   	for(i=0; i<NumThreads; i++){
   		pthread_join(ThHandle[i], NULL);
   	}
   }
   
   gettimeofday(&t, NULL);
   EndTime = (double)t.tv_sec*1000000.0 + ((double)t.tv_usec);
   TimeElapsed=(EndTime-StartTime)/1000.00;
   TimeElapsed/=(double)REPS;
   
   //merge with header and write to file
   WriteBMP(CopyImage, argv[2]);

	// free() the allocated area for the images
   for(i = 0; i < ip.Vpixels; i++) { free(TheImage[i]); free(CopyImage[i]); }
   free(TheImage);   free(CopyImage);   
  
   printf("\n\nTotal execution time: %9.4f ms.  ",TimeElapsed);
   if(NumThreads>1) printf("(%9.4f ms per thread).  ",TimeElapsed/(double)NumThreads);
   printf("\n (%6.3f ns/pixel)\n", 1000000*TimeElapsed/(double)(ip.Hpixels*ip.Vpixels));
   
   return (EXIT_SUCCESS);
}

编译

gcc imrotate.c ImageStuff.c -o imrotate -lpthread -lm

在这里插入图片描述
在这里插入图片描述

运行效果

使用两个线程,顺时针 10 ° 10\degree 10° 旋转图片

./imrotate nature_monte.bmp nature_monte_10.bmp 10 2 

在这里插入图片描述
使用两个线程,顺时针 45 ° 45\degree 45° 旋转图片

./imrotate nature_monte.bmp nature_monte_45.bmp 45 2 

在这里插入图片描述
使用两个线程,顺时针 285 ° 285\degree 285° (逆时针 75 ° 75\degree 75°)旋转图片

./imrotate nature_monte.bmp nature_monte_285.bmp 285 2

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值