CPU_并行(多线程)使用数据共享 MUTEX 结构边缘检测图片

并行(多线程)使用数据共享 MUTEX 结构边缘检测图片

代码

ImageStuff.h

#define EDGE		 0
#define NOEDGE       255
#define MAXTHREADS   128

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

struct PrPixel{
	unsigned char 	R;
	unsigned char 	G;
	unsigned char 	B;
	unsigned char 	x;    // unused. to make it an even 4B
	float 			BW;
	float 			BW2,BW4,BW5,BW9,BW12,BW15;
	float			Gauss, Gauss2;
	float			Theta,Gradient;
};

double** CreateBWCopy(unsigned char** img);
double** CreateBlankDouble();
unsigned char** CreateBlankBMP(unsigned char FILL);
struct PrPixel** PrAMTReadBMP(char*);
struct PrPixel** PrReadBMP(char*);
unsigned char** ReadBMP(char*);
void WriteBMP(unsigned char** , char*);

extern struct	ImgProp 	ip;
extern long 	NumThreads, PrThreads;
extern int		ThreadCtr[];

ImageStuff.c

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

#include "ImageStuff.h"


double** CreateBlankDouble()
{
    int i;

	double** img = (double **)malloc(ip.Vpixels * sizeof(double*)); 
    for(i=0; i<ip.Vpixels; i++){
		img[i] = (double *)malloc(ip.Hpixels*sizeof(double));
		memset((void *)img[i],0,(size_t)ip.Hpixels*sizeof(double));
    }
    return img;
}


double** CreateBWCopy(unsigned char** img)
{
    int i,j,k;

	double** imgBW = (double **)malloc(ip.Vpixels * sizeof(double*)); 
    for(i=0; i<ip.Vpixels; i++){
		imgBW[i] = (double *)malloc(ip.Hpixels*sizeof(double));
		for(j=0; j<ip.Hpixels; j++){
			// convert each pixel to B&W = (R+G+B)/3
			k=3*j;
			imgBW[i][j]=((double)img[i][k]+(double)img[i][k+1]+(double)img[i][k+2])/3.0;  
		}
    }	
    return imgBW;
}


unsigned char** CreateBlankBMP(unsigned char FILL)
{
    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],FILL,(size_t)ip.Hbytes); // zero out every pixel
    }
    return img;
}


// This thread function asynchronously pre-calculates a row of pixels.
// It uses the CounterMutex to updated the shared counter-based variables
pthread_mutex_t		CounterMutex;
struct PrPixel 		**PrIm;
int					NextRowToProcess, LastRowRead;
int					ThreadCtr[MAXTHREADS];  // Counts # rows processed by each thread


void *AMTPreCalcRow(void* ThCtr)
{
	unsigned char r, g, b;
	int i,j,Last;
	float R, G, B, BW, BW2, BW3, BW4, BW5, BW9, BW12, Z=0.0;

	do{
		// get the next row number safely
		pthread_mutex_lock(&CounterMutex);
			Last=LastRowRead;  
			i=NextRowToProcess;  
			if(Last>=i){
				NextRowToProcess++;
				j = *((int *)ThCtr);
				*((int *)ThCtr) = j+1; // One more row processed by this thread
			}
		pthread_mutex_unlock(&CounterMutex);
		if(Last<i) continue;
		if(i>=ip.Vpixels) break;
		for(j=0; j<ip.Hpixels; j++){
			b=PrIm[i][j].B;			B=(float)b;
			g=PrIm[i][j].G; 		G=(float)g;
			r=PrIm[i][j].R;			R=(float)r;
			BW3=R+G+B;
			PrIm[i][j].BW   = BW   = BW3*0.3333333;
			PrIm[i][j].BW2  = BW2  = BW+BW;
			PrIm[i][j].BW4  = BW4  = BW2+BW2;
			PrIm[i][j].BW5  = BW5  = BW4+BW;
			PrIm[i][j].BW9  = BW9  = BW5+BW4;
			PrIm[i][j].BW12 = BW12 = BW9+BW3;
			PrIm[i][j].BW15 = BW12+BW3;
			PrIm[i][j].Gauss = PrIm[i][j].Gauss2 = Z;
			PrIm[i][j].Theta = PrIm[i][j].Gradient = Z;
		}
	}while(i<ip.Vpixels);
	pthread_exit(NULL);
}


// This function calculates the pre-processed pixels while reading from disk
// It does it in an "asynhcorous Multi-threaded (AMT)" fashion using a Mutex
struct PrPixel** PrAMTReadBMP(char* filename)
{
	int i,j,k,ThErr;
	unsigned char Buffer[24576];
	pthread_t ThHan[MAXTHREADS];
	pthread_attr_t attr;
	
	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];			ip.Hpixels = width;
	int height = *(int*)&HeaderInfo[22];		ip.Vpixels = height;
	int RowBytes = (width*3 + 3) & (~3);		ip.Hbytes  = RowBytes;
	//copy header for re-use
	for(i=0; i<54; i++) {	ip.HeaderInfo[i] = HeaderInfo[i];	}
	printf("\n   Input BMP File name: %20s  (%u x %u)",filename,ip.Hpixels,ip.Vpixels);
	// allocate memory to store the main image
	PrIm = (struct PrPixel **)malloc(height * sizeof(struct PrPixel *));
	for(i=0; i<height; i++) {
		PrIm[i] = (struct PrPixel *)malloc(width * sizeof(struct PrPixel));
	}
	pthread_attr_init(&attr);		// Initialize threads and MUTEX
	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
	pthread_mutex_init(&CounterMutex, NULL);
	
	pthread_mutex_lock(&CounterMutex);
		NextRowToProcess=0; // Set the asynchronous row counter to 0
		LastRowRead=-1;
		for(i=0; i<PrThreads; i++) ThreadCtr[i]=0; // zero every thread counter
	pthread_mutex_unlock(&CounterMutex);
	// read the image from disk and pre-calculate the PRImage pixels
	for(i = 0; i<height; i++) {
		if(i==20){   // when sufficient # of rows are read, launch threads
			// PrThreads is the number of pre-processing threads
			for(j=0; j<PrThreads; j++){
				ThErr=pthread_create(&ThHan[j], &attr, AMTPreCalcRow, (void *)&ThreadCtr[j]);
				if(ThErr != 0){
					printf("\nThread Creation Error %d. Exiting abruptly... \n",ThErr);
					exit(EXIT_FAILURE);
				}
			}
		}
		fread(Buffer, sizeof(unsigned char), RowBytes, f);
		for(j=0,k=0; j<width; j++, k+=3){
			PrIm[i][j].B=Buffer[k];
			PrIm[i][j].G=Buffer[k+1];
			PrIm[i][j].R=Buffer[k+2];
		}
		pthread_mutex_lock(&CounterMutex);
			LastRowRead=i;
		pthread_mutex_unlock(&CounterMutex);
	}		
	// wait for all threads to be done	
	for(i=0; i<PrThreads; i++){	pthread_join(ThHan[i], NULL);	}
	pthread_attr_destroy(&attr);
	pthread_mutex_destroy(&CounterMutex);
	fclose(f);
	return PrIm;  // return the pointer to the main image
}


// This function calculates the pre-processed pixels while reading from disk
struct PrPixel** PrReadBMP(char* filename)
{
	int i,j,k;
	unsigned char r, g, b;
	float R, G, B, BW, BW2, BW3, BW4, BW5, BW9, BW12, Z=0.0;
	unsigned char Buffer[24576];
	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];			ip.Hpixels = width;
	int height = *(int*)&HeaderInfo[22];		ip.Vpixels = height;
	int RowBytes = (width*3 + 3) & (~3);		ip.Hbytes  = RowBytes;
	//copy header for re-use
	for(i=0; i<54; i++) {	ip.HeaderInfo[i] = HeaderInfo[i];	}
	printf("\n   Input BMP File name: %20s  (%u x %u)",filename,ip.Hpixels,ip.Vpixels);
	// allocate memory to store the main image
	struct PrPixel **PrIm = (struct PrPixel **)malloc(height * sizeof(struct PrPixel *));
	for(i=0; i<height; i++) {
		PrIm[i] = (struct PrPixel *)malloc(width * sizeof(struct PrPixel));
	}
	// read the image from disk and pre-calculate the PRImage pixels
	for(i = 0; i < height; i++) {
		fread(Buffer, sizeof(unsigned char), RowBytes, f);
		for(j=0,k=0; j<width; j++, k+=3){
			b=PrIm[i][j].B=Buffer[k];		B=(float)b;
			g=PrIm[i][j].G=Buffer[k+1];		G=(float)g;
			r=PrIm[i][j].R=Buffer[k+2];		R=(float)r;
			BW3=R+G+B;
			PrIm[i][j].BW   = BW   = BW3*0.3333333;
			PrIm[i][j].BW2  = BW2  = BW+BW;
			PrIm[i][j].BW4  = BW4  = BW2+BW2;
			PrIm[i][j].BW5  = BW5  = BW4+BW;
			PrIm[i][j].BW9  = BW9  = BW5+BW4;
			PrIm[i][j].BW12 = BW12 = BW9+BW3;
			PrIm[i][j].BW15 = BW12+BW3;
			PrIm[i][j].Gauss = PrIm[i][j].Gauss2 = Z;
			PrIm[i][j].Theta = PrIm[i][j].Gradient = Z;
		}
	}
	fclose(f);
	return PrIm;  // return the pointer to the main image
}


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];			ip.Hpixels = width;
	int height = *(int*)&HeaderInfo[22];		ip.Vpixels = height;
	int RowBytes = (width*3 + 3) & (~3);		ip.Hbytes  = RowBytes;
	//copy header for re-use
	for(i=0; i<54; i++) {	ip.HeaderInfo[i] = HeaderInfo[i];	}
	printf("\n   Input BMP File name: %20s  (%u x %u)",filename,ip.Hpixels,ip.Vpixels);
	// allocate memory to store the main image
	unsigned char **Img = (unsigned char **)malloc(height * sizeof(unsigned char*));
	for(i=0; i<height; i++) {
		Img[i] = (unsigned char *)malloc(RowBytes * sizeof(unsigned char));
	}
	// read the image from disk
	for(i = 0; i < height; i++) {
		fread(Img[i], sizeof(unsigned char), RowBytes, f);
	}
	fclose(f);
	return Img;  // return the pointer to the main image
}


void WriteBMP(unsigned char** img, char* filename)
{
	int i;
	FILE* f = fopen(filename, "wb");
	if(f == NULL){
		printf("\n\nFILE CREATION ERROR: %s\n\n",filename);
		exit(1);
	}
	//write header
	for(i=0; i<54; i++) {	fputc(ip.HeaderInfo[i],f);	}

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

imedgeMCT.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 PI			 3.1415926
#define ONEOVER159   0.00628931

long  			NumThreads,PrThreads;  		// Regular/Pre-processing threads
int 	     	ThParam[MAXTHREADS];		// Thread parameters ...
int				ThreshLo,ThreshHi;			// "Edge" vs. "No Edge" thresholds
pthread_t      	ThHandle[MAXTHREADS];		// Thread handles
pthread_attr_t 	ThAttr;						// Pthread attrributes

unsigned char**	TheImage;					// This is the main image
struct PrPixel **PrImage;					// the pre-calculated image
unsigned char**	CopyImage;					// This is the copy image (to store edges)

double			**BWImage;					// B&W of TheImage (each pixel=double)
double			**GaussImage;				// Gauss filtered version of the B&W image
double			**Gradient, **Theta;		// gradient and theta for each pixel
struct ImgProp 	ip;


//sobel kernels
double Gx[3][3] = {		{ -1, 0, 1 },
						{ -2, 0, 2 },
						{ -1, 0, 1 }	};

double Gy[3][3] = {		{ -1, -2, -1 },
						{  0,  0,  0 },
						{  1,  2,  1 }	};

double Gauss[5][5] = {	{ 2, 4,  5,  4,  2 },
						{ 4, 9,  12, 9,  4 },
						{ 5, 12, 15, 12, 5 },
						{ 4, 9,  12, 9,  4 },
						{ 2, 4,  5,  4,  2 }	};

						
						// Function that takes the .Gradient and .Thetapre-computed values for
// each pixel and calculates the final value (EDGE/NOEDGE)
void *PrThreshold(void* tid)
{
    long tn;            		     // My thread number (ID) is stored here
    int row,col,col3;
	unsigned char PIXVAL;
	float L,H,G,T;

    tn = *((int *) tid);           // Calculate my Thread ID
    tn *= ip.Vpixels/NumThreads;

    for(row=tn; row<tn+ip.Vpixels/NumThreads; row++)
    {
		if((row<1) || (row>(ip.Vpixels-2))) continue;
        col=1;   col3=3;
        while(col<=(ip.Hpixels-2)){
			L=(float)ThreshLo;		H=(float)ThreshHi;
			G=PrImage[row][col].Gradient;
			PIXVAL=NOEDGE;
			if(G<=L){						// no edge
				PIXVAL=NOEDGE;
			}else if(G>=H){					// edge
				PIXVAL=EDGE;
			}else{
				T=PrImage[row][col].Theta;
				if((T<-67.5) || (T>67.5)){   
					// Look at left and right
					PIXVAL=((PrImage[row][col-1].Gradient>H) || (PrImage[row][col+1].Gradient>H)) ? EDGE:NOEDGE;
				}else if((T>=-22.5) && (T<=22.5)){  
					// Look at top and bottom
					PIXVAL=((PrImage[row-1][col].Gradient>H) || (PrImage[row+1][col].Gradient>H)) ? EDGE:NOEDGE;
				}else if((T>22.5) && (T<=67.5)){   
					// Look at upper right, lower left
					PIXVAL=((PrImage[row-1][col+1].Gradient>H) || (PrImage[row+1][col-1].Gradient>H)) ? EDGE:NOEDGE;
				}else if((T>=-67.5) && (T<-22.5)){   
					// Look at upper left, lower right
					PIXVAL=((PrImage[row-1][col-1].Gradient>H) || (PrImage[row+1][col+1].Gradient>H)) ? EDGE:NOEDGE;
				}
			}
			if(PIXVAL==EDGE){	// Each pixel was initialized to NOEDGE
				CopyImage[row][col3]=PIXVAL;
				CopyImage[row][col3+1]=PIXVAL;
				CopyImage[row][col3+2]=PIXVAL;
			}
            col++;       col3+=3;
        }
    }
    pthread_exit(NULL);
}


// Function that calculates the .Gradient and .Theta for each pixel.
// Uses the pre-computed .Gauss and .Gauss2x values
void *PrSobel(void* tid)
{
    long tn;            		     // My thread number (ID) is stored here
    int row,col,i,j;
	float GX,GY;          float RPI=180.0/PI;

    tn = *((int *) tid);           // Calculate my Thread ID
    tn *= ip.Vpixels/NumThreads;

    for(row=tn; row<tn+ip.Vpixels/NumThreads; row++)
    {
		if((row<1) || (row>(ip.Vpixels-2))) continue;
        col=1;
        while(col<=(ip.Hpixels-2)){
			// calculate Gx and Gy
			GX=PrImage[row-1][col+1].Gauss+PrImage[row+1][col+1].Gauss+PrImage[row][col+1].Gauss2;
			GX-=(PrImage[row-1][col-1].Gauss+PrImage[row+1][col-1].Gauss+PrImage[row][col-1].Gauss2);
			GY=PrImage[row+1][col-1].Gauss+PrImage[row+1][col+1].Gauss+PrImage[row+1][col].Gauss2;
			GY-=(PrImage[row-1][col-1].Gauss+PrImage[row-1][col+1].Gauss+PrImage[row-1][col].Gauss2);
			PrImage[row][col].Gradient=sqrtf(GX*GX+GY*GY);
			PrImage[row][col].Theta=atanf(GX/GY)*RPI;
            col++;
        }
    }
    pthread_exit(NULL);
}


// Function that takes the pre-calculated .BW. .BW2, .BW4, ... 
// pixel values and compute the .Gauss value from it
void *PrGaussianFilter(void* tid)
{
    long tn;            // My thread number (ID) is stored here
    int row,col,i,j;
	float G;  			// temp to calculate the Gaussian filtered version

    tn = *((int *) tid);           // Calculate my Thread ID
    tn *= ip.Vpixels/NumThreads;

    for(row=tn; row<tn+ip.Vpixels/NumThreads; row++)
    {
		if((row<2) || (row>(ip.Vpixels-3))) continue;
        col=2;
        while(col<=(ip.Hpixels-3)){
			G=PrImage[row][col].BW15;
			G+=(PrImage[row-1][col].BW12  + PrImage[row+1][col].BW12  + PrImage[row][col-1].BW12  + PrImage[row][col+1].BW12);
			G+=(PrImage[row-1][col-1].BW9 + PrImage[row-1][col+1].BW9 + PrImage[row+1][col-1].BW9 + PrImage[row+1][col+1].BW9);
			G+=(PrImage[row][col-2].BW5   + PrImage[row][col+2].BW5   + PrImage[row-2][col].BW5   + PrImage[row+2][col].BW5);
			G+=(PrImage[row-1][col-2].BW4 + PrImage[row+1][col-2].BW4 + PrImage[row-1][col+2].BW4 + PrImage[row+1][col+2].BW4);
			G+=(PrImage[row-2][col-2].BW2 + PrImage[row+2][col-2].BW2 + PrImage[row-2][col+2].BW2 + PrImage[row+2][col+2].BW2);
			G*=ONEOVER159;
			PrImage[row][col].Gauss=G;
			PrImage[row][col].Gauss2=G+G;
            col++;
        }
    }
    pthread_exit(NULL);
}


// Function that takes BWImage and calculates the Gaussian filtered version
// Saves the result in the GaussFilter[][] array
void *GaussianFilter(void* tid)
{
    long tn;            // My thread number (ID) is stored here
    int row,col,i,j;
	double G;  			// temp to calculate the Gaussian filtered version

    tn = *((int *) tid);           // Calculate my Thread ID
    tn *= ip.Vpixels/NumThreads;

    for(row=tn; row<tn+ip.Vpixels/NumThreads; row++)
    {
		if((row<2) || (row>(ip.Vpixels-3))) continue;
        col=2;
        while(col<=(ip.Hpixels-3)){
			G=0.0;
			for(i=-2; i<=2; i++){
				for(j=-2; j<=2; j++){
					G+=BWImage[row+i][col+j]*Gauss[i+2][j+2];
				}
			}
			GaussImage[row][col]=G/159.00D;
            col++;
        }
    }
    pthread_exit(NULL);
}


// Function that calculates the Gradient and Theta for each pixel
// Takes the Gauss[][] array and creates the Gradient[][] and Theta[][] arrays
void *Sobel(void* tid)
{
    long tn;            		     // My thread number (ID) is stored here
    int row,col,i,j;
	double GX,GY;

    tn = *((int *) tid);           // Calculate my Thread ID
    tn *= ip.Vpixels/NumThreads;

    for(row=tn; row<tn+ip.Vpixels/NumThreads; row++)
    {
		if((row<1) || (row>(ip.Vpixels-2))) continue;
        col=1;
        while(col<=(ip.Hpixels-2)){
			// calculate Gx and Gy
			GX=0.0; GY=0.0;
			for(i=-1; i<=1; i++){
				for(j=-1; j<=1; j++){
					GX+=GaussImage[row+i][col+j]*Gx[i+1][j+1];
					GY+=GaussImage[row+i][col+j]*Gy[i+1][j+1];
				}
			}
			Gradient[row][col]=sqrt(GX*GX+GY*GY);
			Theta[row][col]=atan(GX/GY)*180.0/PI;
            col++;
        }
    }
    pthread_exit(NULL);
}


// Function that takes the Gradient[][] and Theta[][] arrays and 
// calculates the final value (EDGE/NOEDGE) for each pixel
void *Threshold(void* tid)
{
    long tn;            		     // My thread number (ID) is stored here
    int row,col;
	unsigned char PIXVAL;
	double L,H,G,T;

    tn = *((int *) tid);           // Calculate my Thread ID
    tn *= ip.Vpixels/NumThreads;

    for(row=tn; row<tn+ip.Vpixels/NumThreads; row++)
    {
		if((row<1) || (row>(ip.Vpixels-2))) continue;
        col=1;
        while(col<=(ip.Hpixels-2)){
			L=(double)ThreshLo;		H=(double)ThreshHi;
			G=Gradient[row][col];
			PIXVAL=NOEDGE;
			if(G<=L){						// no edge
				PIXVAL=NOEDGE;
			}else if(G>=H){					// edge
				PIXVAL=EDGE;
			}else{
				T=Theta[row][col];
				if((T<-67.5) || (T>67.5)){   
					// Look at left and right
					PIXVAL=((Gradient[row][col-1]>H) || (Gradient[row][col+1]>H)) ? EDGE:NOEDGE;
				}else if((T>=-22.5) && (T<=22.5)){  
					// Look at top and bottom
					PIXVAL=((Gradient[row-1][col]>H) || (Gradient[row+1][col]>H)) ? EDGE:NOEDGE;
				}else if((T>22.5) && (T<=67.5)){   
					// Look at upper right, lower left
					PIXVAL=((Gradient[row-1][col+1]>H) || (Gradient[row+1][col-1]>H)) ? EDGE:NOEDGE;
				}else if((T>=-67.5) && (T<-22.5)){   
					// Look at upper left, lower right
					PIXVAL=((Gradient[row-1][col-1]>H) || (Gradient[row+1][col+1]>H)) ? EDGE:NOEDGE;
				}
			}
			CopyImage[row][col*3]=PIXVAL;
			CopyImage[row][col*3+1]=PIXVAL;
			CopyImage[row][col*3+2]=PIXVAL;
            col++;
        }
    }
    pthread_exit(NULL);
}


// returns the time stamps in ms
double GetDoubleTime()
{
    struct timeval 		tnow;

    gettimeofday(&tnow, NULL);
    return ((double)tnow.tv_sec*1000000.0 + ((double)tnow.tv_usec))*0.001;
}


double ReportTimeDelta(double PreviousTime, char *Message)
{
	double	Tnow,TimeDelta;
	
	Tnow=GetDoubleTime();
	TimeDelta=Tnow-PreviousTime;
	printf("\n.....%-30s ... %7.0f ms\n",Message,TimeDelta);
	return Tnow;
}


int main(int argc, char** argv)
{
    int 		a,i,ThErr;
    double		t1,t2,t3,t4,t5,t6,t7,t8;
	
    switch (argc){
		case 3 : NumThreads=1;             ThreshLo=50; 	       ThreshHi=100;			PrThreads=NumThreads;		break;
		case 4 : NumThreads=atoi(argv[3]); ThreshLo=50; 	       ThreshHi=100;			PrThreads=NumThreads;		break;
		case 5 : NumThreads=atoi(argv[3]); ThreshLo=atoi(argv[4]); ThreshHi=100;			PrThreads=NumThreads;		break;
		case 6 : NumThreads=atoi(argv[3]); ThreshLo=atoi(argv[4]); ThreshHi=atoi(argv[5]);	PrThreads=NumThreads;		break;
		case 7 : NumThreads=atoi(argv[3]); ThreshLo=atoi(argv[4]); ThreshHi=atoi(argv[5]);	PrThreads=atoi(argv[6]);	break;
		default: printf("\n\nUsage: imedge infile outfile [Threads] [ThreshLo] [ThreshHi]  [PrThreads]");
				 printf("\n\nExample: imedge in.bmp out.bmp 8\n\n");
				 printf("\n\nExample: imedge in.bmp out.bmp 4 50 150\n\n");
				 printf("\n\nExample: imedge in.bmp out.bmp 4 50 150 2\n\n");
				 printf("\n\nNothing executed ... Exiting ...\n\n");
				exit(EXIT_FAILURE);
    }
	if((NumThreads<1) || (NumThreads>MAXTHREADS) || (PrThreads<1) || (PrThreads>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((ThreshLo<0) || (ThreshHi>255) || (ThreshLo>ThreshHi)){
        printf("\nInvalid Thresholds: Threshold must be between [0...255] ...\n");
		printf("\n\nNothing executed ... Exiting ...\n\n");
        exit(EXIT_FAILURE);
	}else{
		printf("ThresLo=%d ... ThreadHi=%d\n",ThreshLo,ThreshHi);	
	}
	printf("\nExecuting the Pthreads version with %li threads ...\n",NumThreads);
	printf("\nWill do pre-processing with %li threads ...\n",PrThreads);
	t1 = GetDoubleTime();

	PrImage=PrAMTReadBMP(argv[1]);  	  printf("\n");
    t2 = ReportTimeDelta(t1,"PrAMTReadBMP complete");	// Start time without IO

	CopyImage = CreateBlankBMP(NOEDGE);		// This will store the edges in RGB  
	t3=ReportTimeDelta(t2, "Auxiliary images created");

	pthread_attr_init(&ThAttr);
	pthread_attr_setdetachstate(&ThAttr, PTHREAD_CREATE_JOINABLE);

	for(i=0; i<NumThreads; i++){
		ThParam[i] = i;
		ThErr = pthread_create(&ThHandle[i], &ThAttr, PrGaussianFilter, (void *)&ThParam[i]);
		if(ThErr != 0){
			printf("\nThread Creation Error %d. Exiting abruptly... \n",ThErr);
			exit(EXIT_FAILURE);
		}
	}
	for(i=0; i<NumThreads; i++){	pthread_join(ThHandle[i], NULL);	}
	t4=ReportTimeDelta(t3, "Gauss Image created");
	for(i=0; i<NumThreads; i++){
		ThParam[i] = i;
		ThErr = pthread_create(&ThHandle[i], &ThAttr, PrSobel, (void *)&ThParam[i]);
		if(ThErr != 0){
			printf("\nThread Creation Error %d. Exiting abruptly... \n",ThErr);
			exit(EXIT_FAILURE);
		}
	}
	for(i=0; i<NumThreads; i++){	pthread_join(ThHandle[i], NULL);	}
	t5=ReportTimeDelta(t4, "Gradient, Theta calculated");
	for(i=0; i<NumThreads; i++){
		ThParam[i] = i;
		ThErr = pthread_create(&ThHandle[i], &ThAttr, PrThreshold, (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);	}
	t6=ReportTimeDelta(t5, "Thresholding completed");
	
    //merge with header and write to file
    WriteBMP(CopyImage, argv[2]);  printf("\n");
	t7=ReportTimeDelta(t6, "WriteBMP completed");

	// free() the allocated area for image and pointers
	for(i = 0; i < ip.Vpixels; i++) { 
		free(CopyImage[i]);		free(PrImage[i]); 
	}
	free(CopyImage); 		free(PrImage);
    
    t8=ReportTimeDelta(t2, "Program Runtime without IO");
	printf("\n\n------------------------------------------------\n");
	for(i=0; i<PrThreads; i++)  { printf("\ntid=%2li processed %4d rows\n",i,ThreadCtr[i]); }
	printf("\n\n------------------------------------------------\n");
	
    return (EXIT_SUCCESS);
}

编译

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

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

运行

使用2个线程, T h r e s L o = 50 ThresLo=50 ThresLo=50 , T h r e a d H i = 1 = 100 ThreadHi=1=100 ThreadHi=1=100 两个阈值 边缘检测图片

./imedgeMCT nature_monte.bmp nature_monte_20_50_100.bmp 2 50 100

在这里插入图片描述
使用2个线程, T h r e s L o = 50 ThresLo=50 ThresLo=50 , T h r e a d H i = 1 = 150 ThreadHi=1=150 ThreadHi=1=150 两个阈值 边缘检测图片

./imedgeMCT nature_monte.bmp nature_monte_20_50_100.bmp 2 50 150

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值