Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added .DS_Store
Binary file not shown.
20 changes: 20 additions & 0 deletions .vscode/c_cpp_properties.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"configurations": [
{
"name": "Mac",
"includePath": [
"${workspaceFolder}/**"
],
"defines": [],
"macFrameworkPath": [
"/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk/System/Library/Frameworks"
],
"compilerPath": "/usr/bin/clang",
"cStandard": "c17",
"cppStandard": "c++17",
"intelliSenseMode": "macos-clang-arm64",
"configurationProvider": "ms-vscode.makefile-tools"
}
],
"version": 4
}
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
# CISC372_hw4
Do not commit to this repository. Please fork a copy into your own repository, then work from your personal forked copy.
USE "make image" to compile the original program
USE "make image_pt" to compile the pthread version
USE "make image_omp" to compile the OpenMP version
Binary file added image
Binary file not shown.
3 changes: 1 addition & 2 deletions image.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
#include <stdio.h>
#include <stdint.h>
#include <time.h>
#include <string.h>
Expand Down Expand Up @@ -119,4 +118,4 @@ int main(int argc,char** argv){
t2=time(NULL);
printf("Took %ld seconds\n",t2-t1);
return 0;
}
}
20 changes: 20 additions & 0 deletions image.dSYM/Contents/Info.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleIdentifier</key>
<string>com.apple.xcode.dsym.image</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundlePackageType</key>
<string>dSYM</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>
Binary file added image.dSYM/Contents/Resources/DWARF/image
Binary file not shown.
1 change: 1 addition & 0 deletions image.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ typedef double Matrix[3][3];

uint8_t getPixelValue(Image* srcImage,int x,int y,int bit,Matrix algorithm);
void convolute(Image* srcImage,Image* destImage,Matrix algorithm);
void* p_convolute(void *args);
int Usage();
enum KernelTypes GetKernelType(char* type);

Expand Down
128 changes: 128 additions & 0 deletions image_omp.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
#include <stdint.h>
#include <time.h>
#include <string.h>
#include "image.h"
#include <omp.h>

#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"

#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.h"

//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(Image* srcImage,Image* destImage,Matrix algorithm){
int row,pix,bit,span;
span=srcImage->bpp*srcImage->bpp;
# pragma omp for
for (row=0;row<srcImage->height;row++){
for (pix=0;pix<srcImage->width;pix++){
for (bit=0;bit<srcImage->bpp;bit++){
destImage->data[Index(pix,row,srcImage->width,bit,srcImage->bpp)]=getPixelValue(srcImage,pix,row,bit,algorithm);
}
}
}
}

//Usage: Prints usage information for the program
//Returns: -1
int Usage(){
printf("Usage: image <filename> <type>\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);

# pragma omp parallel
convolute(&srcImage,&destImage,algorithms[type]);
t2 = time(NULL);
printf("Processing done, saving image\n");

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);
printf("Took %ld seconds\n",t2-t1);
return 0;
}
184 changes: 184 additions & 0 deletions image_pt.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
#include <stdio.h>
#include <stdint.h>
#include <time.h>
#include <string.h>
#include "image.h"
#include <pthread.h>

#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"

#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.h"

enum KernelTypes type;

int thread_count;

//Struct to store all args to pass to p_convolute
typedef struct {
Image* srcImage;
Image* destImage;
} convArgs;

convArgs c_args;
//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(Image* srcImage,Image* destImage,Matrix algorithm){
int row,pix,bit,span;
span=srcImage->bpp*srcImage->bpp;
for (row=0;row<srcImage->height;row++){
for (pix=0;pix<srcImage->width;pix++){
for (bit=0;bit<srcImage->bpp;bit++){
destImage->data[Index(pix,row,srcImage->width,bit,srcImage->bpp)]=getPixelValue(srcImage,pix,row,bit,algorithm);
}
}
}
}


//p_convolute: Applies a kernel matrix to an image with p_threads
//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* p_convolute(void * rank){
int my_rows, my_start, bit, span, pix;
long my_rank = (long) rank;
int total_rows = c_args.destImage->height;
span=c_args.srcImage->bpp * c_args.srcImage->bpp;

//calculate how many rows each thread will process
my_rows = (int) total_rows / thread_count;
my_start = (int) my_rank * my_rows;
if((int)my_rank==thread_count-1){
my_rows+=total_rows % thread_count;
}

//process the given rows for the thread
for(int row = my_start; row<my_start+my_rows; row++){
for(pix=0; pix<c_args.srcImage->width; pix++){
for(bit=0; bit<c_args.srcImage->bpp; bit++){
c_args.destImage->data[Index(pix,row,c_args.srcImage->width,bit,c_args.srcImage->bpp)]=getPixelValue(c_args.srcImage,pix,row,bit,algorithms[type]);
}
}
}

return NULL;
}

//Usage: Prints usage information for the program
//Returns: -1
int Usage(){
printf("Usage: image <filename> <type> <threadcount>\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!=4) 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);

//create threads and call function HERE
long thread;
pthread_t* thread_handles;
thread_count = strtol(argv[3], NULL, 10);
thread_handles = (pthread_t*)malloc(thread_count * sizeof(pthread_t));

//loop to create p_threads
for(thread=0; thread<thread_count; thread++){
c_args.srcImage = &srcImage;
c_args.destImage = &destImage;
pthread_create(&thread_handles[thread], NULL, &p_convolute, (void *) thread);
}
//join the threads
for(thread=0; thread<thread_count; thread++){
pthread_join(thread_handles[thread], NULL);
}

t2=time(NULL);
printf("Processing complete, writing to disk\n");

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);
printf("Took %ld seconds\n",t2-t1);
return 0;
}
8 changes: 6 additions & 2 deletions makefile
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@

image:image.c image.h
image: image.c image.h
gcc -g image.c -o image -lm
image_pt: image_pt.c image.h
gcc -g image_pt.c -o image -lm -lpthread
image_omp: image_omp.c image.h
gcc -g image_omp.c -o image -lm -fopenmp
clean:
rm -f image output.png
rm -f image output.png
Binary file added output.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.