diff --git a/image.c b/image_mp.c similarity index 98% rename from image.c rename to image_mp.c index 2573a5b..a73eb69 100644 --- a/image.c +++ b/image_mp.c @@ -2,11 +2,10 @@ #include #include #include -#include "image.h" - +#include +#include "image_mp.h" #define STB_IMAGE_IMPLEMENTATION #include "stb_image.h" - #define STB_IMAGE_WRITE_IMPLEMENTATION #include "stb_image_write.h" @@ -56,9 +55,11 @@ uint8_t getPixelValue(Image* srcImage,int x,int y,int bit,Matrix algorithm){ // destImage: A pointer to a pre-allocated (including space for the pixel array) structure to receive the convoluted image. It should be the same size as srcImage // algorithm: The kernel matrix to use for the convolution //Returns: Nothing + void convolute(Image* srcImage,Image* destImage,Matrix algorithm){ int row,pix,bit,span; span=srcImage->bpp*srcImage->bpp; + #pragma omp parallel for schedule(static) private(pix, bit) for (row=0;rowheight;row++){ for (pix=0;pixwidth;pix++){ for (bit=0;bitbpp;bit++){ diff --git a/image.h b/image_mp.h similarity index 100% rename from image.h rename to image_mp.h diff --git a/image_pt.c b/image_pt.c new file mode 100644 index 0000000..6ac0925 --- /dev/null +++ b/image_pt.c @@ -0,0 +1,163 @@ +#include +#include +#include +#include +#include +#include +#include "image_pt.h" + +#define STB_IMAGE_IMPLEMENTATION +#include "stb_image.h" + +#define STB_IMAGE_WRITE_IMPLEMENTATION +#include "stb_image_write.h" + +int thread_count; +pthread_t* thread_handles; + +typedef struct { + Image* srcImage; + Image* destImage; + Matrix* algorithm; + int rank; +} ThreadArgs; +//An array of kernel matrices to be used for image convolution. +//The indexes of these match the enumeration from the header file. ie. algorithms[BLUR] returns the kernel corresponding to a box blur. +Matrix algorithms[]={ + {{0,-1,0},{-1,4,-1},{0,-1,0}}, + {{0,-1,0},{-1,5,-1},{0,-1,0}}, + {{1/9.0,1/9.0,1/9.0},{1/9.0,1/9.0,1/9.0},{1/9.0,1/9.0,1/9.0}}, + {{1.0/16,1.0/8,1.0/16},{1.0/8,1.0/4,1.0/8},{1.0/16,1.0/8,1.0/16}}, + {{-2,-1,0},{-1,1,1},{0,1,2}}, + {{0,0,0},{0,1,0},{0,0,0}} +}; + + +//getPixelValue - Computes the value of a specific pixel on a specific channel using the selected convolution kernel +//Paramters: srcImage: An Image struct populated with the image being convoluted +// x: The x coordinate of the pixel +// y: The y coordinate of the pixel +// bit: The color channel being manipulated +// algorithm: The 3x3 kernel matrix to use for the convolution +//Returns: The new value for this x,y pixel and bit channel +uint8_t getPixelValue(Image* srcImage,int x,int y,int bit,Matrix algorithm){ + int px,mx,py,my,i,span; + span=srcImage->width*srcImage->bpp; + // for the edge pixes, just reuse the edge pixel + px=x+1; py=y+1; mx=x-1; my=y-1; + if (mx<0) mx=0; + if (my<0) my=0; + if (px>=srcImage->width) px=srcImage->width-1; + if (py>=srcImage->height) py=srcImage->height-1; + uint8_t result= + algorithm[0][0]*srcImage->data[Index(mx,my,srcImage->width,bit,srcImage->bpp)]+ + algorithm[0][1]*srcImage->data[Index(x,my,srcImage->width,bit,srcImage->bpp)]+ + algorithm[0][2]*srcImage->data[Index(px,my,srcImage->width,bit,srcImage->bpp)]+ + algorithm[1][0]*srcImage->data[Index(mx,y,srcImage->width,bit,srcImage->bpp)]+ + algorithm[1][1]*srcImage->data[Index(x,y,srcImage->width,bit,srcImage->bpp)]+ + algorithm[1][2]*srcImage->data[Index(px,y,srcImage->width,bit,srcImage->bpp)]+ + algorithm[2][0]*srcImage->data[Index(mx,py,srcImage->width,bit,srcImage->bpp)]+ + algorithm[2][1]*srcImage->data[Index(x,py,srcImage->width,bit,srcImage->bpp)]+ + algorithm[2][2]*srcImage->data[Index(px,py,srcImage->width,bit,srcImage->bpp)]; + return result; +} + +//convolute: Applies a kernel matrix to an image +//Parameters: srcImage: The image being convoluted +// destImage: A pointer to a pre-allocated (including space for the pixel array) structure to receive the convoluted image. It should be the same size as srcImage +// algorithm: The kernel matrix to use for the convolution +//Returns: Nothing +void* convolute(void* rank) { + ThreadArgs* args = (ThreadArgs*) rank; + Image* srcImage = args->srcImage; + Image* destImage = args->destImage; + Matrix* algorithm = args->algorithm; + int thread_rank = args->rank; + + int rows_per_thread = srcImage->height / thread_count; + int start_row = thread_rank * rows_per_thread; + int end_row = (thread_rank == thread_count - 1) ? srcImage->height : start_row + rows_per_thread; + + for (int row = start_row; row < end_row; row++) { + for (int pix = 0; pix < srcImage->width; pix++) { + for (int bit = 0; bit < srcImage->bpp; bit++) { + destImage->data[Index(pix, row, srcImage->width, bit, srcImage->bpp)] = getPixelValue(srcImage, pix, row, bit, *algorithm); + } + } + } + return NULL; +} + + + +//Usage: Prints usage information for the program +//Returns: -1 +int Usage(){ + printf("Usage: image \n\twhere type is one of (edge,sharpen,blur,gauss,emboss,identity)\n"); + return -1; +} + +//GetKernelType: Converts the string name of a convolution into a value from the KernelTypes enumeration +//Parameters: type: A string representation of the type +//Returns: an appropriate entry from the KernelTypes enumeration, defaults to IDENTITY, which does nothing but copy the image. +enum KernelTypes GetKernelType(char* type){ + if (!strcmp(type,"edge")) return EDGE; + else if (!strcmp(type,"sharpen")) return SHARPEN; + else if (!strcmp(type,"blur")) return BLUR; + else if (!strcmp(type,"gauss")) return GAUSE_BLUR; + else if (!strcmp(type,"emboss")) return EMBOSS; + else return IDENTITY; +} + +//main: +//argv is expected to take 2 arguments. First is the source file name (can be jpg, png, bmp, tga). Second is the lower case name of the algorithm. +int main(int argc,char** argv){ + long t1,t2; + t1=time(NULL); + + stbi_set_flip_vertically_on_load(0); + if (argc!=3) return Usage(); + char* fileName=argv[1]; + if (!strcmp(argv[1],"pic4.jpg")&&!strcmp(argv[2],"gauss")){ + printf("You have applied a gaussian filter to Gauss which has caused a tear in the time-space continum.\n"); + } + enum KernelTypes type=GetKernelType(argv[2]); + + Image srcImage,destImage,bwImage; + srcImage.data=stbi_load(fileName,&srcImage.width,&srcImage.height,&srcImage.bpp,0); + if (!srcImage.data){ + printf("Error loading file %s.\n",fileName); + return -1; + } + destImage.bpp=srcImage.bpp; + destImage.height=srcImage.height; + destImage.width=srcImage.width; + destImage.data=malloc(sizeof(uint8_t)*destImage.width*destImage.bpp*destImage.height); + + thread_count = 16; + thread_handles = malloc(thread_count * sizeof(pthread_t)); + + ThreadArgs* args = malloc(thread_count * sizeof(ThreadArgs)); + + for (int i = 0; i < thread_count; i++) { + args[i].srcImage = &srcImage; + args[i].destImage = &destImage; + args[i].algorithm = &algorithms[type]; + args[i].rank = i; + pthread_create(&thread_handles[i], NULL, convolute, &args[i]); + } + + for (int i = 0; i < thread_count; i++) { + pthread_join(thread_handles[i], NULL); + } + + stbi_write_png("output.png",destImage.width,destImage.height,destImage.bpp,destImage.data,destImage.bpp*destImage.width); + stbi_image_free(srcImage.data); + + free(destImage.data); + free(thread_handles); + free(args); + t2=time(NULL); + printf("Took %ld seconds\n",t2-t1); + return 0; +} \ No newline at end of file diff --git a/image_pt.h b/image_pt.h new file mode 100644 index 0000000..551a9a4 --- /dev/null +++ b/image_pt.h @@ -0,0 +1,23 @@ +#ifndef ___IMAGE +#define ___IMAGE +#include + +#define Index(x,y,width,bit,bpp) y*width*bpp+bpp*x+bit + +typedef struct{ + uint8_t* data; + int width; + int height; + int bpp; +} Image; + +enum KernelTypes{EDGE=0,SHARPEN=1,BLUR=2,GAUSE_BLUR=3,EMBOSS=4,IDENTITY=5}; + +typedef double Matrix[3][3]; + +uint8_t getPixelValue(Image* srcImage,int x,int y,int bit,Matrix algorithm); +void* convolute(void* rank); +int Usage(); +enum KernelTypes GetKernelType(char* type); + +#endif \ No newline at end of file diff --git a/output.png b/output.png new file mode 100644 index 0000000..827bec8 Binary files /dev/null and b/output.png differ diff --git a/output.txt b/output.txt new file mode 100644 index 0000000..70359f0 --- /dev/null +++ b/output.txt @@ -0,0 +1,10 @@ +Script started on Mon Oct 30 18:41:15 2023 +^[]0;jhcoop@r1n10.darwin:~/CISC372_picProject^G^[[?1034h[jhcoop@r1n10 CISC372_picProject]$ srun ima$ +Took 6 seconds +^[]0;jhcoop@r1n10.darwin:~/CISC372_picProject^G[jhcoop@r1n10 CISC372_picProject]$ srun image_pt pic$ +Took 6 seconds +^[]0;jhcoop@r1n10.darwin:~/CISC372_picProject^G[jhcoop@r1n10 CISC372_picProject]$ exit +exit + +Script done on Mon Oct 30 18:41:57 2023 +