void DrawLine(cimg_library::CImg<unsigned char>& mask, int x0, int y0, int x1, int y1){ int dx = x1 - x0; int dy = y1 - y0; int ux = ((dx > 0) << 1) - 1; int uy = ((dy > 0) << 1) - 1; int x = x0, y = y0, eps; eps = 0; dx = abs(dx); dy = abs(dy); if (dx > dy){ for (x = x0; x != x1; x += ux){ mask.atXY(x,y) = 255; eps += dy; if ((eps << 1) >= dx){ y += uy; eps -= dx; } } } else{ for (y = y0; y != y1; y += uy){ mask.atXY(x,y) = 255; eps += dx; if ((eps << 1) >= dy){ x += ux; eps -= dy; } } } }
std::vector<std::vector<double> > calculate_luminosity(cimg_library::CImg<unsigned char> &image) { std::vector<std::vector<double> > luminosity_map(image.height(), std::vector<double>(image.width(), DBL_MAX)); for (int i = 0; i < image.height(); i++) { for (int j = 0; j < image.width(); j++) { luminosity_map[i][j] = luminosity(image.atXY(j, i, 0, 0), image.atXY(j, i, 0, 1), image.atXY(j, i, 0, 2)); } } return luminosity_map; }
//找最大的团并返回外轮廓 std::vector<MYPOINT> FindBiggestContour(cimg_library::CImg<unsigned char> origin, std::vector<MYPOINT> Points) { std::vector<MYPOINT> contour; cimg_library::CImg<unsigned char> mask; //compute the binary img int threshold = otsu(origin, Points, mask, 1); unsigned char *bi_img = new unsigned char[origin.width()*origin.height()]; for (int i = 0; i < origin.height(); i++){ for (int j = 0; j < origin.width(); j++){ if (origin.atXY(j, i) >= threshold && mask.atXY(j, i) == 255) bi_img[i*origin.width() + j] = 255; else bi_img[i*origin.width() + j] = 0; } } //返回二值图像 cimg_library::CImg<unsigned char> bi(bi_img, origin.width(), origin.height()); //done //找团 std::vector<int> stRun, enRun, rowRun, masRun; int NumberofRuns = 0, offset = 1, maxRun = 1; fillRunVector(bi, NumberofRuns, stRun, enRun, rowRun, masRun); std::vector<int> runLabels; std::vector<std::pair<int, int>> equivalences; firstPass(stRun, enRun, rowRun, NumberofRuns, runLabels, equivalences, offset); if (!NumberofRuns){ std::cout << "NOTHING FOUND!!!" << std::endl <<"size of contour is: "<< contour.size() << std::endl; return contour; } replaceSameLabel(runLabels, equivalences); int maxLabel = *max_element(runLabels.begin(), runLabels.end()); int *MassofRuns = new int[maxLabel + 1]; memset(MassofRuns, 0, (maxLabel + 1)*sizeof(int)); memset(bi_img, 0, (bi.height()*bi.width())*sizeof(unsigned char)); for (int c = 0; c < NumberofRuns; c++){ MassofRuns[runLabels[c]] += masRun[c]; if (MassofRuns[runLabels[c]]>maxRun){ maxRun = MassofRuns[runLabels[c]]; maxLabel = runLabels[c]; } int i = rowRun[c]; for (int j = stRun[c]; j <= enRun[c]; j++){ bi_img[i*bi.width() + j] = runLabels[c]; } } for (int i = 0; i < bi.height(); i++) for (int j = 0; j < bi.width(); j++) { if (bi_img[i*bi.width()+j] == maxLabel) bi_img[i*bi.width() + j] = 255; else bi_img[i*bi.width() + j] = 0; } return FindContour(bi_img, bi.width(), bi.height()); }
int patchDistance(cimg_library::CImg<unsigned char> currentPatch,cimg_library::CImg<unsigned char> patchPlusOffset) { int width = currentPatch.width(); int height = currentPatch.height(); int distance =0; for(int i = 0; i< width; i++) { for(int j = 0; j< height; j++) { distance = distance + ((int)(currentPatch.atXY(i,j,0))-(int)(patchPlusOffset.atXY(i,j,0)))*((int)(currentPatch.atXY(i,j,0))-(int)(patchPlusOffset.atXY(i,j,0))) + ((int)(currentPatch.atXY(i,j,1))-(int)(patchPlusOffset.atXY(i,j,1)))*((int)(currentPatch.atXY(i,j,1))-(int)(patchPlusOffset.atXY(i,j,1))) + ((int)(currentPatch.atXY(i,j,2))-(int)(patchPlusOffset.atXY(i,j,2)))*((int)(currentPatch.atXY(i,j,2))-(int)(patchPlusOffset.atXY(i,j,2))); } } return distance; };
/** find all the runs in the img parameter: @origin --the original CImg pic @NumberofRuns --count the number of runs @stRun --record the start of a run @enRun --record the end of a run @rowRun --record which row the run is in @masRun --record how much mass a run has */ void fillRunVector(cimg_library::CImg<unsigned char> origin, int &NumberofRuns, std::vector<int> &stRun, std::vector<int> &enRun, std::vector<int> &rowRun, std::vector<int> &masRun) { for (int i = 0; i < origin.height(); i++){ if (origin.atXY(0, i) == 255){ NumberofRuns++; stRun.push_back(0); rowRun.push_back(i); } for (int j = 1; j < origin.width(); j++){ if (origin.atXY(j - 1, i) == 0 && origin.atXY(j, i) == 255){ NumberofRuns++; stRun.push_back(j); rowRun.push_back(i); } else if (origin.atXY(j-1, i) == 255 && origin.atXY(j, i) == 0) { enRun.push_back(j - 1); masRun.push_back(enRun[NumberofRuns-1] - stRun[NumberofRuns-1] + 1); } } if (origin.atXY(origin.width() - 1,i)){ enRun.push_back(origin.width() - 1); masRun.push_back(enRun[NumberofRuns-1] - stRun[NumberofRuns-1] + 1); } } }
/** otsu, return the computed threshold,the CImg version parameter: @origin --original pic @Points --ROI, 给定连续的点,按顺序连城线以确定一个封闭的环 @debug --debug option, 0 means no information outputed */ int otsu(cimg_library::CImg<unsigned char> origin, std::vector<MYPOINT> Points, cimg_library::CImg<unsigned char>& mask, int debug = 0){ int thresholdValue = 1; int ihist[256] = { 0 }; int i, j, k; int rows = origin.height(), cols = origin.width(); int n, n1, n2, gmin = 255, gmax = 0; double m1, m2, sum, csum, fmax, sb; int x0 = origin.width(), y0 = origin.height(), x1 = 0, y1 = 0; //缩小计算范围 for (std::vector<MYPOINT>::iterator it = Points.begin(); it != Points.end(); it++){ x0 = x0 < (*it).x ? x0 : (*it).x; y0 = y0 < (*it).y ? y0 : (*it).y; x1 = x1 > (*it).x ? x1 : (*it).x; y1 = y1 > (*it).y ? y1 : (*it).y; } mask = AreaMask(origin, Points); for (i = y0; i <= y1; i++){ for (j = x0; j < x1; j++){ if (mask.atXY(j, i) == 255){ ihist[origin.atXY(j,i)]++; if (origin.atXY(j,i) > gmax)gmax = origin.atXY(j,i); if (origin.atXY(j,i) < gmin)gmin = origin.atXY(j,i); } } } sum = csum = 0.0; n = 0; for (k = 0; k < 256; k++){ sum += (double)k*(double)ihist[k]; n += ihist[k]; } if (!n){ std::cout << "NOT NORMAL!!!" << std::endl << " thresholdValue = 160\n" << std::endl; return 160; } //do the otsu global thresholding method fmax = -1.0; n1 = 0; for (k = 0; k < 255; k++){ n1 += ihist[k]; if (!n1){ continue; } n2 = n - n1; if (n2 == 0){ break; } csum += (double)k*ihist[k]; m1 = csum / n1; m2 = (sum - csum) / n2; sb = (double)n1*(double)n2*(m1 - m2)*(m1 - m2); if (sb>fmax){ fmax = sb; thresholdValue = k; } } if (debug) std::cout << "#OTSU: thresholdValue = " << thresholdValue << std::endl << "gmin = " << gmin << std::endl << "gmax = " << gmax << std::endl; return thresholdValue; }