#include #include #include #include #include using namespace std; //struct for holding rgb color values typedef struct { int r,g,b; } rgb; int main(int argc, char *argv[]){ string magicnum, comment; int height, width, range; int edge_threshhold = 130; int hysteresis_threshold = 100; ifstream in; cout << "opening file: " << argv[1] << endl; in.open(argv[1], ios::in); getline(in, magicnum); if(!(magicnum == "P3")){ cout << "error: image is not of type PPM!" << endl; return 0; } getline(in, comment); in >> width; in >> height; in >> range; cout << "width: " << width << " height: " << height << " range: " << range << endl; rgb** ppm = new rgb*[height]; for(int k = 0; k < height; k++) ppm[k] = new rgb[width]; int** pgm = new int*[height]; for(int k = 0; k < height; k++) pgm[k] = new int[width]; int** smoothed = new int*[height]; for(int k = 0; k < height; k++) smoothed[k] = new int[width]; int** edges = new int*[height]; for(int k = 0; k < height; k++) edges[k] = new int[width]; int** gx = new int*[height]; for(int k = 0; k < height; k++) gx[k] = new int[width]; int** gy = new int*[height]; for(int k = 0; k < height; k++) gy[k] = new int[width]; cout << "reading file... " << endl; //read the input file into an array of rgb data structures for(int y = 0; y < height; y++){ for(int x=0; x < width; x++){ in >> ppm[y][x].r; in >> ppm[y][x].g; in >> ppm[y][x].b; } } in.close(); cout << "done.\ngenerating grayscale image... " << endl; //generate a greyscale representation of the input file for(int y = 0; y < height; y++){ for(int x=0; x < width; x++){ pgm[y][x] = (ppm[y][x].r + ppm[y][x].g + ppm[y][x].b)/3; } } cout << "done.\napplying gaussian filtering... " << endl; //generate a flattened grayscale image using gaussian filtering for(int y = 1; y < height-1; y++){ for(int x=1; x < width-1; x++){ smoothed[y][x]=(pgm[y][x]*4+pgm[y-1][x]*2+pgm[y+1][x]*2+pgm[y][x-1]*2+pgm[y][x+1]*2+pgm[y-1][x+1]*1+pgm[y-1][x-1]*1+pgm[y+1][x+1]*1+pgm[y+1][x-1]*1)/16; } } cout << "done.\ndetecting edges... " << endl; //detect edges, setting color value to 256 out of a possible 255 if an edge pixel is found to signify an edge pixel for(int y = 2; y < height-2; y++){ for(int x = 2; x < width-2; x++){ if(y>0){ gx[y][x] = smoothed[y][x-1]*(-2)+smoothed[y-1][x-1]*(-1)+smoothed[y+1][x-1]*(-1)+smoothed[y+1][x]*(2)+smoothed[y+1][x-1]*(1)+smoothed[y+1][x+1]*(1); gy[y][x] = smoothed[y-1][x]*(-2)+smoothed[y-1][x-1]*(-1)+smoothed[y-1][x+1]*(-1)+smoothed[y+1][x]*(2)+smoothed[y+1][x-1]*(1)+smoothed[y+1][x+1]*(1); if(abs(abs(gx[y][x])+abs(gy[y][x]))>edge_threshhold){ edges[y][x] = abs(gx[y][x])+abs(gy[y][x]); } } } } //apply non-maximum suppression for(int y = 2; y < height-2; y++){ for(int x = 2; x < width-2; x++){ if(abs(gx[y][x])>abs(gy[y][x])){ if(gx[y][x]<0){ if(gx[y][x-1]gx[y][x] || gx[y][x-1]>gx[y][x]) edges[y][x] = 0; } } else if(abs(gx[y][x])gy[y][x] || gy[y-1][x]>gy[y][x]) edges[y][x] = 0; } } } } cout << "done.\nbeginning output... " << endl; //output the smoothed grayscale image with no edge superposition fstream out1; out1.open("output.pgm", fstream::out); out1 << "P2" << endl; out1 << comment << endl; out1 << width << " " << height << endl; out1 << range << endl; for(int y = 0; y < height; y++){ for(int x = 0; x < width; x++){ out1 << smoothed[y][x] << endl; } } out1.close(); comment = "#created by Andrew Stebbins"; //output the detected edges fstream out2; out2.open("output.ppm", fstream::out); out2 << magicnum << endl; out2 << comment << endl; out2 << width << " " << height << endl; out2 << range << endl; for(int y = 0; y < height; y++){ for(int x = 0; x < width; x++){ /* //if edge pixel, make red if(edges[y][x] == 256){ out2 << 255 << endl; out2 << 0 << endl; out2 << 0 << endl; } else{ out2 << 0 << endl; out2 << 0 << endl; out2 << 0 << endl; } */ out2 << edges[y][x] << endl; out2 << edges[y][x] << endl; out2 << edges[y][x] << endl; } } out2.close(); cout << "done." << endl; return 0; }