CPU_并行(多线程)不同高性能旋转图片

news2024/11/18 16:22:25

并行(多线程)不同高性能旋转图片

代码

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);
}

imrotateMC.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 	     129
#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;
			
			// pixel 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);
}
void *Rotate2(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;
	
			H=(double)ip.Hpixels;
			V=(double)ip.Vpixels;
			Diagonal=sqrt(H*H+V*V);
			ScaleFactor=(ip.Hpixels>ip.Vpixels) ? V/Diagonal : H/Diagonal;
    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;
			
			// pixel 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);
}


void *Rotate3(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;
	double CRA,SRA;
    struct Pixel pix;

    tn = *((int *) tid);           // Calculate my Thread ID
    tn *= ip.Vpixels/NumThreads;
	
			H=(double)ip.Hpixels;
			V=(double)ip.Vpixels;
			Diagonal=sqrt(H*H+V*V);
			ScaleFactor=(ip.Hpixels>ip.Vpixels) ? V/Diagonal : H/Diagonal;
			
			CRA=cos(RotAngle);
    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;
			
			// pixel rotation matrix
			newX=CRA*X-sin(RotAngle)*Y;
			newY=sin(RotAngle)*X+CRA*Y;
//			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);
}


void *Rotate4(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;
	double CRA,SRA;
    struct Pixel pix;

    tn = *((int *) tid);           // Calculate my Thread ID
    tn *= ip.Vpixels/NumThreads;
	
			H=(double)ip.Hpixels;
			V=(double)ip.Vpixels;
			Diagonal=sqrt(H*H+V*V);
			ScaleFactor=(ip.Hpixels>ip.Vpixels) ? V/Diagonal : H/Diagonal;
			
			CRA=cos(RotAngle);
			SRA=sin(RotAngle);
    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;
			
			// pixel rotation matrix
			newX=CRA*X-SRA*Y;
			newY=SRA*X+CRA*Y;
//			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);
}


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

    tn = *((int *) tid);           // Calculate my Thread ID
    tn *= ip.Vpixels/NumThreads;
	
			H=(double)ip.Hpixels;
			V=(double)ip.Vpixels;
			Diagonal=sqrt(H*H+V*V);
			ScaleFactor=(ip.Hpixels>ip.Vpixels) ? V/Diagonal : H/Diagonal;
			
			CRA=cos(RotAngle);
			SRA=sin(RotAngle);
			h=ip.Hpixels/2;   v=ip.Vpixels/2;	// integer div
			hp3=ip.Hpixels*3;
    for(row=tn; row<tn+ip.Vpixels/NumThreads; row++){
        col=0;
		c=0;
//      while(col<ip.Hpixels*3){
        while(col<hp3){
			// 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;
			
			// pixel rotation matrix
			newX=CRA*X-SRA*Y;
			newY=SRA*X+CRA*Y;
//			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;
			c++;
        }
    }
    pthread_exit(NULL);
}


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

    tn = *((int *) tid);           // Calculate my Thread ID
    tn *= ip.Vpixels/NumThreads;
	
			H=(double)ip.Hpixels;
			V=(double)ip.Vpixels;
			Diagonal=sqrt(H*H+V*V);
			ScaleFactor=(ip.Hpixels>ip.Vpixels) ? V/Diagonal : H/Diagonal;
			
			CRA=cos(RotAngle);	CRAS=ScaleFactor*CRA;
			SRA=sin(RotAngle);	SRAS=ScaleFactor*SRA;
			h=ip.Hpixels/2;   v=ip.Vpixels/2;	// integer div
			hp3=ip.Hpixels*3;
    for(row=tn; row<tn+ip.Vpixels/NumThreads; row++){
        col=0;
		c=0;
			Y=(double)v-(double)row;
			SRAYS=SRAS*Y;     CRAYS=CRAS*Y;
//      while(col<ip.Hpixels*3){
        while(col<hp3){
			// 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;
			
			// pixel rotation matrix
			newX=CRAS*X-SRAYS;
			newY=SRAS*X+CRAYS;
//			newX=CRA*X-SRA*Y;
//			newY=SRA*X+CRA*Y;
//			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;
			c++;
        }
    }
    pthread_exit(NULL);
}


void *Rotate7(void* tid)
{
    long tn;            		     // My thread number (ID) is stored here
//    int row,col,h,v,c;
    int row,col,h,v,c, hp3;
	double cc, ss, k1, k2;
	int NewRow,NewCol;
	double X, Y, newX, newY, ScaleFactor;
	double Diagonal, H, V;
	double CRA,SRA, CRAS, SRAS, SRAYS, CRAYS;
    struct Pixel pix;

    tn = *((int *) tid);           // Calculate my Thread ID
    tn *= ip.Vpixels/NumThreads;
	
			H=(double)ip.Hpixels;
			V=(double)ip.Vpixels;
			Diagonal=sqrt(H*H+V*V);
			ScaleFactor=(ip.Hpixels>ip.Vpixels) ? V/Diagonal : H/Diagonal;
			
			CRA=cos(RotAngle);	CRAS=ScaleFactor*CRA;
			SRA=sin(RotAngle);	SRAS=ScaleFactor*SRA;
			h=ip.Hpixels/2;   v=ip.Vpixels/2;	// integer div
			hp3=ip.Hpixels*3;
    for(row=tn; row<tn+ip.Vpixels/NumThreads; row++){
        col=0;
		cc=0.00;
		ss=0.00;
			Y=(double)v-(double)row;
			SRAYS=SRAS*Y;     CRAYS=CRAS*Y;
			k1=CRAS*(double)h + SRAYS;
			k2=SRAS*(double)h - CRAYS;
//      while(col<ip.Hpixels*3){
        while(col<hp3){
			// 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;
			
			// pixel rotation matrix
			newX=cc-k1;
			newY=ss-k2;
//			newX=CRA*X-SRA*Y;
//			newY=SRA*X+CRA*Y;
//			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;
			cc += CRAS;
			ss += SRAS;
        }
    }
    pthread_exit(NULL);
}


int main(int argc, char** argv)
{
	int					RotDegrees, Function;
    int 				a,i,ThErr;
    struct timeval 		t;
    double         		StartTime, EndTime;
    double         		TimeElapsed;
	char				FuncName[50];
	
    switch (argc){
		case 3 : NumThreads=1; 				RotDegrees=45;					Function=1; 			break;
		case 4 : NumThreads=1;  			RotDegrees = atoi(argv[3]);		Function=1; 			break;
		case 5 : NumThreads=atoi(argv[4]);  RotDegrees = atoi(argv[3]);		Function=1; 			break;
		case 6 : NumThreads=atoi(argv[4]);  RotDegrees = atoi(argv[3]);		Function=atoi(argv[5]); break;
		default: printf("\nUsage: %s inputBMP outputBMP [RotAngle] [NumThreads : 1-128] [Function:1-6]\n\n",argv[0]);
				 printf("Example: %s infilename.bmp outname.bmp -75\n\n",argv[0]);
				 printf("Example: %s infilename.bmp outname.bmp 45 8\n\n",argv[0]);
				 printf("Example: %s infilename.bmp outname.bmp 125 4 3\n\n",argv[0]);
				 printf("Nothing 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);
	}
	switch(Function){
		case 1:  strcpy(FuncName,"Rotate()");	RotateFunc=Rotate;	break;
		case 2:  strcpy(FuncName,"Rotate2()");	RotateFunc=Rotate2;	break;
		case 3:  strcpy(FuncName,"Rotate3()");	RotateFunc=Rotate3;	break;
		case 4:  strcpy(FuncName,"Rotate4()");	RotateFunc=Rotate4;	break;
		case 5:  strcpy(FuncName,"Rotate5()");	RotateFunc=Rotate5;	break;
		case 6:  strcpy(FuncName,"Rotate6()");	RotateFunc=Rotate6;	break;
		case 7:  strcpy(FuncName,"Rotate7()");	RotateFunc=Rotate7;	break;
//		case 8:  strcpy(FuncName,"Rotate8()");	RotateFunc=Rotate8;	break;
//		case 9:  strcpy(FuncName,"Rotate9()");	RotateFunc=Rotate9;	break;
		default: printf("Wrong function %d ... \n",Function);
					printf("\n\nNothing executed ... Exiting ...\n\n");
					exit(EXIT_FAILURE);
	}
	printf("\nLaunching %li Pthread%s using function:  %s\n",NumThreads,NumThreads<=1?"":"s",FuncName);
	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);

	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\nExecution time:%10.4f ms  ",TimeElapsed);
	if(NumThreads>=1) printf("(%10.4f  Thread-ms)  ",TimeElapsed*(double)NumThreads);
    printf(" (%6.3f ns/pixel)\n", 1000000*TimeElapsed/(double)(ip.Hpixels*ip.Vpixels));
    
    return (EXIT_SUCCESS);
}

编译

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

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

运行效果

使用2个线程,通过Rotate() 方法顺时针旋转图片 10 ° 10\degree 10°

./imrotateMC nature_monte.bmp nature_monte_10_2_func1.bmp 10 2 1

在这里插入图片描述

使用2个线程,通过Rotate2() 方法顺时针旋转图片 10 ° 10\degree 10°

./imrotateMC nature_monte.bmp nature_monte_10_2_func2.bmp 10 2 2

在这里插入图片描述

使用2个线程,通过Rotate3() 方法顺时针旋转图片 10 ° 10\degree 10°

./imrotateMC nature_monte.bmp nature_monte_10_2_func3.bmp 10 2 3

在这里插入图片描述

使用2个线程,通过Rotate4() 方法顺时针旋转图片 10 ° 10\degree 10°

 ./imrotateMC nature_monte.bmp nature_monte_10_2_func4.bmp 10 2 4

在这里插入图片描述

使用2个线程,通过Rotate5() 方法顺时针旋转图片 10 ° 10\degree 10°

 ./imrotateMC nature_monte.bmp nature_monte_10_2_func5.bmp 10 2 5

在这里插入图片描述
使用2个线程,通过Rotate6() 方法顺时针旋转图片 10 ° 10\degree 10°

./imrotateMC nature_monte.bmp nature_monte_10_2_func6.bmp 10 2 6

在这里插入图片描述
使用2个线程,通过Rotate7() 方法顺时针旋转图片 10 ° 10\degree 10°

./imrotateMC nature_monte.bmp nature_monte_10_2_func7.bmp 10 2 7

在这里插入图片描述

原图
在这里插入图片描述
顺时针旋转 10 ° 10\degree 10°
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/149347.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java中>>,>>=,<<,<<=运算符

今天在刷LeetCode的时候遇到了一个运算符<<&#xff0c;对这个运算符的意思有点模糊&#xff0c;然后便开始面向百度学习&#xff0c;但是发现&#xff0c;很多篇帖子表达的意思太文章化&#xff0c;不够通俗易懂&#xff0c;于是打算写下这篇帖子&#xff0c;让大家能够…

工作笔记——微信支付开发相关知识整理

在最近的工作中&#xff0c;引入了微信小程序支付&#xff0c;在开发过程中积累和整理了一些技术知识&#xff0c;现将其整理如下 目录 一、概念认识 &#xff08;一&#xff09;术语介绍 &#xff08;二&#xff09;名词解释 &#xff08;四&#xff09;对接微信支付接口规…

Win10安卓子系统安装教程

Win10安卓子系统安装教程必要安装文件下载和安装子系统安装方法方法一&#xff1a;安装 WSA PacMan方法二&#xff1a;安装 APK安装程序必要安装文件下载和安装 win10安卓子系统和win11子系统的安装一样&#xff0c;都必须要安装适用于 Android ™的 Windows 子系统设置的软件…

Java设计模式中行为型模式是什么/模板方式又是什么,编程怎么运用

继续整理记录这段时间来的收获&#xff0c;详细代码可在我的Gitee仓库SpringBoot克隆下载学习使用&#xff01; 6.行为型模式 6.1 概述 6.1.1 特点 用于描述程序在运行时复杂的流程控制&#xff0c;即描述多个类或对象之间怎么相互协作共同完成单个对象都无法单独完成任务涉…

分布式基础篇3——前端开发基础知识(谷粒商城)

前端技术对比一、ES61、简介2、什么是 JavaScript3、ES6新特性3.1 let3.2 const3.3 解构表达式3.4 字符串扩展3.5 函数优化3.6 对象优化3.7 map 和 reduce3.8 Promise3.9 模块化二、Vue1、MVVM 思想2、Vue 简介3、Vue 入门案例4、Vue 指令插值表达式v-text、v-htmlv-bindv-mode…

【CANN训练营第三季】基于昇腾PyTorch框架的模型训练调优

文章目录性能分析工具PyTorch Profiling性能分析工具CANN Profiling结业考核1、使用Pytorch实现LeNet网络的minist手写数字识别。2、采用课程中学习到的手工或者自动迁移方式&#xff0c;将上述脚本迁移到昇腾npu上&#xff0c;单机单卡&#xff0c;提供迁移脚本&#xff0c;突…

YOLOv5视觉AI库安装

打开YOLOv5开源仓库: https://github.com/ultralytics/yolov5/blob/master/README.zh-CN.md下载源码:安装 : pip install -r requirements.txt完成安装目标检测推理可通过PyTorch Hub加载YOLOv5检测模型检测图像并返回数据帧使用YOLOv5要先安装opencv-python和pandas库安装open…

C#,图像二值化(18)——全局阈值的模糊集理论算法(Huang Thresholding)与源程序

1 模糊集理论模糊集理论,也称为模糊集合论,或简单地称为模糊集,1965年美国学者扎德在数学上创立了一种描述模糊现象的方法—模糊集合论。这种方法把待考察的对象及反映它的模糊概念作为一定的模糊集合&#xff0c;建立适当的隶属函数&#xff0c;通过模糊集合的有关运算和变换&…

arduino - pinMode参数1的确定 - 以arduino nano every核心板为例

文章目录arduino - pinMode参数1的确定 - 以arduino nano every核心板为例概述笔记pins_arduino.hABX00028-datasheet.pdf简单的辨认管脚号就照ABX00028-datasheet.pdf来ENDarduino - pinMode参数1的确定 - 以arduino nano every核心板为例 概述 arduino nano every的核心板使…

我的交易抽象思路分享

这几天我老是抛出一些问题给老师们&#xff0c;都是故意而为之&#xff0c;因为我靠这种方式自己引导自己很多年&#xff1b; 比如&#xff1a;龙头真的存在么&#xff1f;为何前几天它还不是龙头&#xff0c;怎么今天就是了&#xff1f; 再如&#xff1a;交易模式和交易系统…

微信小程序解密encryptedData报错pad block corrupted

前要&#xff1a; 今天调试一下微信授权登录的时候老是第一次报错解密失败pad block corrupted&#xff0c;第二次授权的时候正常&#xff0c;因为第一次已经获取到手机号码&#xff01; 后端代码&#xff1a; public static JSONObject getUserInfo(String encryptedData, S…

微信自动回复软件

软件介绍 软件名称&#xff1a; 微信超级管家 适用平台&#xff1a; windows 是否免费&#xff1a; 完全免费 病毒检测&#xff1a; 火绒安全检测通过 流氓检测&#xff1a; 无广告、无弹窗、无其他流氓行为 软件大小&#xff1a; 183M 这个软件依赖的是本地微信客户端&#x…

C++ 初始化列表详解

目录 1.什么是初始化列表 2.什么时候需要使用初始化列表&#xff1f; 3.初始化列表的效率 4.初始化列表的初始化顺序 1.什么是初始化列表 class A { public:A(int value):m_dada(value){}private:int m_dada; }; 如上图&#xff0c;红色圈起来的部分&#xff0c;就是构造函…

MXNet的Faster R-CNN(基于区域提议网络的实时目标检测)《5》

在上一篇文章的介绍中&#xff0c;我们知道语义分割可以对图像中的每个像素进行类别预测。这节主要讲关于全卷积网络(Fully Convolutional Network,FCN)&#xff0c;实现从图像像素到像素类别的变换。 那这里的卷积神经网络跟以往的有什么不一样的地方吗? 这里的网络是通过转置…

Java中享元模式是什么/享元模式有什么用,编程如何实现,哪里用到了享元模式

继续整理记录这段时间来的收获&#xff0c;详细代码可在我的Gitee仓库SpringBoot克隆下载学习使用&#xff01; 5.8 享元模式 5.8.1 概述 运用共享技术来有效地支持大量细粒度对象的复用&#xff0c;通过共享已经存在的对象来大幅度减少需要创建的对象数量、避免大量相似对象…

图文并茂strapi 4.5.5自定义搭建指南以及数据库字段名接口返回mapping分析

strapi是什么&#xff1f; 基于Nodejs的开源免费CMS框架 为什么选择它&#xff1f; 基于nodejs,100&#xff05;JavaScript&#xff0c;上手迅速可轻松创建功能强大且可自定义的API可以使用任何喜欢的数据库 先决条件 首先你的电脑需要具备以下环境&#xff0c;再执行命令…

技术破局:程序员2023为何跳出舒适圈?

1前言今天的冬日暖阳高照&#xff0c;给我羽绒服下的肉身火一般的燥热&#xff0c;给了我一个错觉&#xff0c;以为到了阳春三月。刚刚送完老妈还有老婆孩子回老家&#xff0c;我坐到电脑机器前&#xff0c;准备捋一下思绪&#xff0c;回首2022的生活和工作。 2 2022 回顾今年用…

Linux下C/C++实现cpustat(测量CPU利用率)

在Linux中&#xff0c;cpustat定期转储正在运行的进程的当前CPU利用率统计信息。cpustat已被优化为具有最小的CPU开销&#xff0c;与top相比&#xff0c;通常使用约35%的CPU。cpustat还包括一些简单的统计分析选项&#xff0c;可以帮助描述CPU的加载方式。 cpustat介绍 cpust…

大数据概论

大数据概论大数据概论概念特点(4V)Volume(大量)Velocity(高速)Variety(多样)Value(低价值密度)应用场景发展前景部门间业务流程分析部门组织结构大数据概论 概念 大数据(BigData)&#xff0c;指无法在一定时间范围内\textcolor{Red}{无法在一定时间范围内}无法在一定时间范围…

iOS—Effective Objective—C2.0(2)

文章目录对象&#xff0c;消息&#xff0c;运行期理解“属性”概念合成与存取dynamic关键字属性特性原子性读/写权限内存管理语义方法名为什么几乎所有的属性都可以使用nonatomic&#xff1a;要点在对象的内部尽量直接访问实例变量惰性初始化&#xff1a;要点理解“对象同等性”…