void testSkinRecognition(const BayesianClassifier &classifier, ImageType &image, ImageType &ref, std::string out, bool YCbCr){ int height, width, levels; image.getImageInfo(height,width,levels); ImageType outImg(height,width,levels); RGB val1, val2; int label; std::vector<double> color(2); int TP = 0, TN = 0, FN = 0, FP = 0; RGB white(255,255,255); RGB black(0,0,0); for(int row = 0; row < height; row++){ for(int col = 0; col < width; col++){ image.getPixelVal(row, col, val1); ref.getPixelVal(row, col, val2); if(YCbCr == true){ color[0] = -0.169*val1.r - 0.332*val1.g+ 0.500*val1.b; color[1] = 0.500*val1.r - 0.419*val1.g - 0.081*val1.b; } else{ color[0] = val1.r/float(val1.r+val1.g+val1.b); color[1] = val1.g/float(val1.r+val1.g+val1.b); } label = classifier.predict(color); if(label == 0){ outImg.setPixelVal(row, col, white); if(val2 != black){ TP++; } else{ FP++; } } else{ outImg.setPixelVal(row, col, black); if(val2 == black){ TN++; } else{ FN++; } } } } // end outer for loop std::cout << std::endl << "TP: " << TP << std::endl << "TN: " << TN << std::endl << "FP: " << FP << std::endl << "FN: " << FN << std::endl; /*std::stringstream ss; ss << FP << " " << FN; Debugger debugger("Data_Prog2/errors3a.txt",true); debugger.debug(ss.str()); */ writeImage(out.c_str(), outImg); }
void getMLEParameters(ImageType& trainingImage, ImageType& refImage, bool useRGB, Vector2f &estSkinMu, Matrix2f &estSkinSigma, Vector2f &estNonSkinMu, Matrix2f &estNonSkinSigma) { vector<Vector2f> sampleSkinData, sampleNonSkinData; RGB val; float total, x1, x2; total = x1 = x2 = 0; for(int i=0; i<N; i++) { for(int j=0; j<M; j++) { trainingImage.getPixelVal(i, j, val); if(useRGB) { total = val.r + val.g + val.b; if(total == 0) { x1 = x2 = 0; } else { x1 = (float)val.r / total; //New Red value x2 = (float)val.g / total; //New Green Value } } else { x1 = -0.169 * (float)val.r - 0.332 * (float)val.g + 0.5 * (float)val.b; //New Cb value x2 = 0.5 * (float)val.r - 0.419 * (float)val.g - 0.081 * (float)val.b; //New Cr value } refImage.getPixelVal(i, j, val); if(val.r != 0 && val.g != 0 && val.b != 0) { sampleSkinData.push_back(Vector2f(x1, x2)); } else { // cout << x1 << "\t" << x2 << endl; sampleNonSkinData.push_back(Vector2f(x1, x2)); } } } estNonSkinMu = MLE::calculateSampleMean(sampleNonSkinData); estNonSkinSigma = MLE::calculateSampleCovariance(sampleNonSkinData, estNonSkinMu); estSkinMu = MLE::calculateSampleMean(sampleSkinData); estSkinSigma = MLE::calculateSampleCovariance(sampleSkinData, estSkinMu); }
void testSkinRecogWithThreshold(const std::vector<double> &mean, const Matrix &cov, ImageType &image, std::string out){ RGB white(255,255,255); RGB black(0,0,0); int height, width, levels; image.getImageInfo(height,width,levels); RGB val; std::vector<double> pc(2); // pure color double thR, thG; for(int row = 0; row < height; row++){ for(int col = 0; col < width; col++){ image.getPixelVal(row, col, val); pc[0] = val.r/float(val.r+val.g+val.b); pc[1] = val.g/float(val.r+val.g+val.b); thR = exp(-(cov[0][0] * pow((pc[0] - mean[0]),2) + cov[0][1] * (pc[0]- mean[0]))); thG = exp(-(cov[1][0] * (pc[1] - mean[1]) + cov[1][1] * pow((pc[1] - mean[1]),2))); if((thR >= .9 && thG >= 1.0 && thG < 1.2) || (thR <= .8 && thR >= .7 && thG > 1.1)){ image.setPixelVal(row, col, white); } else{ image.setPixelVal(row, col, black); } } } // end outer for loop writeImage(out.c_str(), image); }
/* Expand image function Writen by: Jeremiah Berns Dependincies, image.cpp, image.h Discription: Will accept the shrunken image, the grow size of the image, and then expand the image back to 256x256 */ void expandImage(ImageType oldImage, ImageType& newImage, int growVal, string newImageName) { //Variable decliration int rows, cols, Q, tempValue; //Variable setting oldImage.getImageInfo(rows, cols, Q); for(int i=0;i<rows;i++) { for(int j=0;j<cols;j++) { oldImage.getPixelVal(i,j, tempValue); for(int k=0;k<growVal;k++) { for(int l=0;l<growVal;l++) { newImage.setPixelVal(i*growVal+k,j*growVal+l,tempValue); } } } } writeImage(newImageName, newImage); }
/* Histogram Equalization function Written by: Jeremiah Berns Dependincies:image.h, image.cpp Discription: This function will perform the histogram equalization algorithem to the oldImage and will output the newImage with the given newImageName. */ void histogramEq(ImageType oldImage, ImageType& newImage, string newImageName) { int rows, cols, Q, pixelValue, pixelCount; oldImage.getImageInfo(rows,cols,Q); pixelCount = rows*cols; int adjustedHistogram[Q]; double histogramArray[Q], equalizedHistogram[Q]; double probabilityArray[Q], cumulativeProbability[Q], probTotal=0; for (int i = 0; i<Q;i++) { histogramArray[i] = 0; equalizedHistogram[i] = 0; } for(int i=0; i<rows;i++) { for(int j=0; j<cols;j++) { oldImage.getPixelVal(i,j,pixelValue); histogramArray[pixelValue]+=1; } } for(int i=0;i<Q;i++) { probTotal+= histogramArray[i]/pixelCount; cumulativeProbability[i] = probTotal; cumulativeProbability[i] = cumulativeProbability[i]*255; adjustedHistogram[i] = cumulativeProbability[i]; cout<<adjustedHistogram[i]<<endl; } for(int i=0; i<rows;i++) { for(int j=0; j<cols;j++) { oldImage.getPixelVal(i,j,pixelValue); newImage.setPixelVal(i,j,adjustedHistogram[pixelValue-1]); } } writeImage(newImageName, newImage); }
void makeColorMatrices(ImageType& img, ImageType& ref, Matrix &sk_cols, Matrix &nsk_cols, bool YCbCr) { int height1, width1, levels1; int height2, width2, levels2; img.getImageInfo(height1, width1, levels1); ref.getImageInfo(height2, width2, levels2); assert(height1 == height2); assert(width1 == width2); assert(levels1 == levels2); RGB val1, val2; std::vector<double> color(2); RGB black(0,0,0); for(int row = 0; row < height1; row++){ for(int col = 0; col < width1; col++){ img.getPixelVal(row, col, val1); ref.getPixelVal(row, col, val2); if(YCbCr == true){ color[0] = -0.169*val1.r - 0.332*val1.g+ 0.500*val1.b; color[1] = 0.500*val1.r - 0.419*val1.g - 0.081*val1.b; } else{ color[0] = val1.r/float(val1.r+val1.g+val1.b); color[1] = val1.g/float(val1.r+val1.g+val1.b); } if(val2 != black){ sk_cols.push_back(color); } else{ nsk_cols.push_back(color); } } } }
void writeImage(const char fname[], ImageType& image) /* write PPM image */ { int i, j; int N, M, Q; unsigned char *charImage; ofstream ofp; image.getImageInfo(N, M, Q); // make space for PPM charImage = (unsigned char *) new unsigned char [3*M*N]; // convert the RGB to unsigned char RGB val; for(i=0; i<N; i++) { for(j=0; j<3*M; j+=3) { image.getPixelVal(i, j/3, val); charImage[i*3*M+j]=(unsigned char)val.r; charImage[i*3*M+j+1]=(unsigned char)val.g; charImage[i*3*M+j+2]=(unsigned char)val.b; } } ofp.open(fname, ios::out | ios::binary); if (!ofp) { cout << "Can't open file: " << fname << endl; exit(1); } ofp << "P6" << endl; ofp << M << " " << N << endl; ofp << Q << endl; ofp.write( reinterpret_cast<char *>(charImage), (3*M*N)*sizeof(unsigned char)); if (ofp.fail()) { cout << "Can't write image " << fname << endl; exit(0); } ofp.close(); delete [] charImage; }
void writeImage(string fname, ImageType& image){ int i, j; int N, M, Q; unsigned char *charImage; ofstream ofp; image.getImageInfo(N, M, Q); charImage = (unsigned char *) new unsigned char [M*N]; // convert the integer values to unsigned char int val; for(i=0; i<N; i++){ for(j=0; j<M; j++){ image.getPixelVal(i, j, val); charImage[i*M+j]=(unsigned char)val; } } ofp.open(fname.c_str(), ios::out | ios::binary); if (!ofp) { cout << "Can't open file: " << fname << endl; exit(1); } ofp << "P5" << endl; ofp << M << " " << N << endl; ofp << Q << endl; ofp.write( reinterpret_cast<char *>(charImage), (M*N)*sizeof(unsigned char)); if (ofp.fail()) { cout << "Can't write image " << fname << endl; exit(0); } ofp.close(); }
/* shrink Image funtion. Writen By Jeremiah Berns. Dependincies: image.h, image.cpp Discription: Will take in the old image, and the new image, and the pixel value based apon the shrink value passed to it. It will place that value from the old image into the new image, then save the new image with the passed in file name. */ void shrinkImage(ImageType oldImage, ImageType& newImage, int shrinkVal, string newImageFname) { //Variable decliration int rows, col, Q, tempValue; //Variable setting oldImage.getImageInfo(rows, col, Q); for(int i=0; i<rows;i++) { for(int j=0;j<col;j++) { if(i%shrinkVal == 0 && j%shrinkVal ==0) { oldImage.getPixelVal(i,j, tempValue); newImage.setPixelVal(i/shrinkVal,j/shrinkVal,tempValue); } } } writeImage(newImageFname, newImage); }
void runTwoClassTest(ImageType& testImage, ImageType& refImage, bool useRGB, Vector2f &estSkinMu, Matrix2f &estSkinSigma, Vector2f &estNonSkinMu, Matrix2f &estNonSkinSigma, const char fileOutput[]) { float falseNegative, falsePositive; float n, p, fn, fp, x1, x2, total; RGB val; ImageType writeNewImage(N, M, Q); falseNegative = falsePositive = n = p = fn = fp = x1 = x2 = total = 0; for(int i=0; i<N; i++) { for(int j=0; j<M; j++) { testImage.getPixelVal(i, j, val); if(useRGB) { total = val.r + val.g + val.b; x1 = (float)val.r / total; //New Red value x2 = (float)val.g / total; //New Green Value } else { x1 = -0.169 * (float)val.r - 0.332 * (float)val.g + 0.5 * (float)val.b; //New Cb value x2 = 0.5 * (float)val.r - 0.419 * (float)val.g - 0.081 * (float)val.b; //New Cr value } bool classifiedAsSkin = BayesClassifier::classifierCaseThree(Vector2f(x1, x2), estSkinMu, estNonSkinMu, estSkinSigma, estNonSkinSigma) == 1; if(classifiedAsSkin) { writeNewImage.setPixelVal(i, j, RGB(0, 0, 0)); } else { writeNewImage.setPixelVal(i, j, RGB(255, 255, 255)); } refImage.getPixelVal(i, j, val); bool isSkin = (val.r != 0 && val.g != 0 && val.b != 0); if(classifiedAsSkin) { p++; } else { n++; } if(!classifiedAsSkin && isSkin) { fn++; } else if(classifiedAsSkin && !isSkin) { fp++; } } } writeImage("write.ppm", writeNewImage); falseNegative = fn / n; falsePositive = fp / p; ofstream generalOutput; generalOutput.open(fileOutput); generalOutput << "Two-Class (Skin vs Non-Skin) Results:" << endl; generalOutput << "False Negative: " << fn << " / " << n << " = " << falseNegative << endl; generalOutput << "False Positive: " << fp << " / " << p << " = " << falsePositive << endl; generalOutput.close(); }
void runThresholdTest(ImageType& testImage, ImageType& refImage, bool useRGB, float thresMin, float thresMax, Vector2f &estMu, Matrix2f &estSigma, const char fileOutput[]) { vector<float> falseNegative, falsePositive; float n, p, fn, fp, x1, x2, total; RGB val; for(float threshold = thresMin; threshold <= thresMax+0.02; threshold+=.05) { n = p = fn = fp = 0; for(int i=0; i<N; i++) { for(int j=0; j<M; j++) { testImage.getPixelVal(i, j, val); if(useRGB) { total = val.r + val.g + val.b; x1 = (float)val.r / total; //New Red value x2 = (float)val.g / total; //New Green Value } else { x1 = -0.169 * (float)val.r - 0.332 * (float)val.g + 0.5 * (float)val.b; //New Cb value x2 = 0.5 * (float)val.r - 0.419 * (float)val.g - 0.081 * (float)val.b; //New Cr value } bool classifiedAsSkin = BayesClassifier::thresholdCaseThree(Vector2f(x1, x2), estMu, estSigma, threshold); refImage.getPixelVal(i, j, val); bool isSkin = (val.r != 0 && val.g != 0 && val.b != 0); if(classifiedAsSkin) p++; else n++; if(isSkin && !classifiedAsSkin) { fn++; } else if(!isSkin && classifiedAsSkin) { fp++; } } } // cout << "Threshold: " << threshold << ": " << endl; // cout << "\tFalse Negative Rate: \t" << fn / n << endl; // cout << "\tFalse Positive Rate: \t" << fp / p << endl << endl; falseNegative.push_back(fn / n); falsePositive.push_back(fp / p); } ofstream generalOutput; generalOutput.open(fileOutput); generalOutput << "Threshold\tFalseNegative\tFalsePositive" << endl; for(float threshold = thresMin, i = 0; threshold <= thresMax+0.02; threshold+=.05, i++) { generalOutput << threshold << "\t" << falseNegative[i] << "\t" << falsePositive[i] << endl; } generalOutput.close(); }