/** 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); } } }
int Plot2DAxes::drawOnto(cimg_library::CImg<unsigned char> & im, float opacity) { im.fBox2_drawAxes(_range, _gradColor, opacity); if (_gradStatus) im.fBox2_drawGraduations(_range, _scaling, _gradColor, opacity); if (_numStatus) im.fBox2_drawNumbers(_range, _scaling, _numColor, opacity); return 100; }
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; } } } }
void writeMagnitude(cimg_library::CImg<T>& image, const std::vector<T>& magnitude) { for (int x=0; x<image.width(); x++) { for (int y=0; y<image.height(); y++) { const unsigned char mag = magnitude[y*image.width()+x]; const unsigned char color_mag[] = { mag, mag, mag }; image.draw_point(x, y, color_mag); } } }
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; }
void writeMagnitudeDirection(cimg_library::CImg<T>& image, const std::vector<T>& magnitude, const std::vector<float>& direction) { for (int x=0; x<image.width(); x++) { for (int y=0; y<image.height(); y++) { float _r,_g,_b; HSVtoRGB(&_r, &_g, &_b, direction[y*image.width()+x]*180/M_PI, 1, (float)magnitude[y*image.width()+x]/255.0); const T color_dir[] = { (int)floor(_r*255), (int)floor(_g*255), (int)floor(_b*255) }; image.draw_point(x, y, color_dir); } } }
//找最大的团并返回外轮廓 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; };
void sobelOperator(const cimg_library::CImg<T>& image, std::vector<T>& magnitude, std::vector<float>& direction) { //Allocate the magnitude magnitude.resize(image.width()*image.height()); direction.resize(image.width()*image.height()); //Loop through the image and apply the sobel operator for (int x=0; x<image.width(); x++) { for (int y=0; y<image.height(); y++) { int dx=0, dy=0, mag = 0; float dir=0; if (!(x == 0 || x == image.width()-1 || y == 0 || y == image.height()-1)) { for (int i=-1; i<=1; i++) { for (int j=-1; j<=1; j++) { dx = dx + gx[j+1][i+1] * greyVal(image, x+j, y+i); dy = dy + gy[j+1][i+1] * greyVal(image, x+j, y+i); } } } mag = (int)sqrt(pow((double)dx,2) + pow((double)dy,2)); dir = atan2(dy, dx); if (mag > 255) mag = 255; if (mag < 0) mag = 0; magnitude[y*image.width()+x] = mag; direction[y*image.width()+x] = dir; } } }
void flood(cimg_library::CImg<unsigned char> &draw_image, std::vector<std::vector<int> > &energy_map, char *color, int val, int x, int y) { if (!valid_coord(std::pair<int, int>(x, y), energy_map[0].size(), energy_map.size())) return; if (energy_map[x][y] == val) return; draw_image.draw_point(y, x, color); energy_map[x][y] = val; flood(draw_image, energy_map, color, val, x - 1, y); flood(draw_image, energy_map, color, val, x + 1, y); flood(draw_image, energy_map, color, val, x, y - 1); flood(draw_image, energy_map, color, val, x, y + 1); }
double image_to_pl_function(const cimg_library::CImg<double> &image, T &t, std::map<typename T::Face_handle, Function> &fs) { typedef typename T::Point Point; std::vector<Point> grid; std::map<Point, double> fgrid; size_t n = image.width(); size_t m = image.height(); double dx = 2/double(n-1), x0=-1.0; double dy = 2/double(m-1), y0=-1.0; for (size_t i = 0; i < n; ++i) { for (size_t j = 0; j < m; ++j) { Point p(x0 + i * dx, y0 + j * dy); grid.push_back(p); fgrid[p] = image(i,m-j-1)/double(255) + 1e-3; } } t = T(grid.begin(), grid.end()); double tot_orig(0); for (auto f = t.finite_faces_begin(); f != t.finite_faces_end(); ++f) { Point p = f->vertex(0)->point(), q = f->vertex(1)->point(), r = f->vertex(2)->point(); fs[f] = Function(p, fgrid[p], q, fgrid[q], r, fgrid[r]); tot_orig += CGAL::to_double(MA::integrate_centroid(p,q,r, fs[f])); } return tot_orig; }
void applyQWAF(cimg_library::CImg<T>& image,cimg_library::CImg<T>& out) { for (int x=0; x<image.width(); x++) { for (int y=0; y<image.height(); y++) { Quaternion q[9]; for (int ix=-1; ix<=1; ix++) { for (int iy=-1; iy<=1; iy++) { int mx=x,my=y; coord(mx, my, image.width(), image.height()); q[(iy+1)*3+(ix+1)] = Quaternion(0,image(mx,my,0,0),image(mx,my,0,1),image(mx,my,0,2)); } } //Get the weighted average filter Quaternion p = QWAF(q); int mx=x, my=y; coord(mx, my, image.width(), image.height()); T col[3] = { (T)p.b, (T)p.c, (T)p.d }; out.draw_point(mx, my, col); } } }
inline void loadImage( const std::string& filename, cimg_library::CImg<T>& image ) { image.load( filename.c_str() ); }
/* 输入原二值图像,返回一个MYPOINT类型的容器,容器内标记最大连通域的外轮廓 这是直接对已经找到最大连通域的二值图像进行外轮廓标记 */ std::vector<MYPOINT> FindContour(cimg_library::CImg<unsigned char> origin) { int i = 0, j = 0; int cols = origin.width(), rows = origin.height(); int imgsize = (cols + 2)*(rows + 2); unsigned char *ori = new unsigned char[imgsize]; memset(ori, 0, imgsize*sizeof(unsigned char)); for (i = 0; i < rows; i++){ for (j = 0; j < cols; j++) ori[(i + 1)*(cols + 2) + (j + 1)] = origin[j,i]; } int *oriLabel = new int[imgsize]; memset(oriLabel, 0, imgsize*sizeof(int)); std::vector < MYPOINT > contour; //find the start point for (i = 0; i < rows + 2; i++){ for (j = 0; j < cols + 2 && ori[i*(cols + 2) + j] != 255; j++){} if (ori[i*(cols + 2) + j] == 255) break; } if (i == rows + 2 && j == cols + 2 && ori[imgsize] == 0) { std::cout << "there is no contour." << std::endl; return contour; } MYPOINT start(i - 1, j - 1); contour.push_back(start); oriLabel[i*(cols + 2) + j] = 1; //设置循环计算的参数 MYPOINT CurP; MYPOINT LastP = start; int x[8] = { i, i + 1, i + 1, i + 1, i, i - 1, i - 1, i - 1 }; int y[8] = { j + 1, j + 1, j, j - 1, j - 1, j - 1, j, j + 1 }; int c = 7, n = 0; for (n = 0; n < 8; n++){ if (ori[x[c] * (cols + 2) + y[c]] == 255) { oriLabel[x[c] * (cols + 2) + y[c]] = 1; break; } else oriLabel[x[c] * (cols + 2) + y[c]] = -1; c = (c + 1) % 8; } if (n == 7 && ori[x[c] * (cols + 2) + y[c]] == 0) { return contour; } else{ CurP.x = x[c] - 1; CurP.y = y[c] - 1; contour.push_back(CurP); //重新计算x[],y[],c, n x[0] = CurP.x + 1, x[1] = CurP.x + 1 + 1, x[2] = CurP.x + 1 + 1, x[3] = CurP.x + 1 + 1, x[4] = CurP.x + 1, x[5] = CurP.x + 1 - 1, x[6] = CurP.x + 1 - 1, x[7] = CurP.x + 1 - 1; y[0] = CurP.y + 1 + 1, y[1] = CurP.y + 1 + 1, y[2] = CurP.y + 1, y[3] = CurP.y + 1 - 1, y[4] = CurP.y + 1 - 1, y[5] = CurP.y + 1 - 1, y[6] = CurP.y + 1, y[7] = CurP.y + 1 + 1; n = 0, c = (c + 6) % 8; } //std::cout << start << std::endl; int stop = 1; while (stop != 0){ for (n = 0; n < 8; n++){ if (ori[x[c] * (cols + 2) + y[c]] == 255) { oriLabel[x[c] * (cols + 2) + y[c]] = 1; break; } else oriLabel[x[c] * (cols + 2) + y[c]] = -1; c = (c + 1) % 8; } LastP = CurP; CurP.x = x[c] - 1; CurP.y = y[c] - 1; contour.push_back(CurP); //重新计算x[],y[],c, n if (LastP.x == start.x && LastP.y == start.y){ //for (int cc = 0; cc < 7; cc++) // printf("%3d, %3d, %3d, %3d, %3d, %3d, %3d\n", oriLabel[cc * 7 + 0], oriLabel[cc * 7 + 1], oriLabel[cc * 7 + 2], oriLabel[cc * 7 + 3], oriLabel[cc * 7 + 4], oriLabel[cc * 7 + 5], oriLabel[cc * 7 + 6], oriLabel[cc * 7 + 7]); for (n = 0; n < 8 && (oriLabel[x[n] * (cols + 2) + y[n]] != 0 || ori[x[n] * (cols + 2) + y[n]] == 255); n++); if (n == 8 && (oriLabel[x[7] * (cols + 2) + y[7]] != 0 || ori[x[7] * (cols + 2) + y[7]] == 255)) stop = 0; contour.pop_back(); } x[0] = CurP.x + 1, x[1] = CurP.x + 1 + 1, x[2] = CurP.x + 1 + 1, x[3] = CurP.x + 1 + 1, x[4] = CurP.x + 1, x[5] = CurP.x + 1 - 1, x[6] = CurP.x + 1 - 1, x[7] = CurP.x + 1 - 1; y[0] = CurP.y + 1 + 1, y[1] = CurP.y + 1 + 1, y[2] = CurP.y + 1, y[3] = CurP.y + 1 - 1, y[4] = CurP.y + 1 - 1, y[5] = CurP.y + 1 - 1, y[6] = CurP.y + 1, y[7] = CurP.y + 1 + 1; c = (c + 6) % 8; } //unsigned char *op = new unsigned char[rows*cols]; //for (int i = 0; i < rows; i++){ // for (int j = 0; j < cols; j++){ // if (oriLabel[(i + 1)*(cols + 2) + (j + 1)] == 1) // op[i*cols + j] = 255; // else // op[i*cols + j] = 0; // } //} //cimg_library::CImg<unsigned char> ttt(op, rows, cols); //cimg_library::CImgDisplay ddd(ttt, "ddd"); return contour; }
/** 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; }
cimg_library::CImg<unsigned char> AreaMask(cimg_library::CImg<unsigned char> origin, std::vector<MYPOINT> Points){ int i, j, x0 = origin.width(), y0 = origin.height(), x1 = 0, y1 = 0; cimg_library::CImg<unsigned char> mask(origin.width(), origin.height(), 1, 1); mask.fill(0); //draw the circle of chosen area for (i = 0, j = Points.size() - 1; i < Points.size(); j = i++){ DrawLine(mask, Points[j].x, Points[j].y, Points[i].x, Points[i].y); } //draw the mask //find a point in the circle //缩小计算范围 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; } MYPOINT p(x0, (y1+y0)/2); //while (!JudgePoint(p, Points) && p.y <= y1){ // p.x = (p.x + 1) % (x1 + 1) + x0; // if (p.x == x0) p.y++; //} int c = 0, tmp_x = Points[0].x, tmp_y = Points[0].y; while (p.y <= y1){ if (mask.atXY(p.x, p.y) == 255) { if (c == 0){ tmp_x = p.x + 1; tmp_y = p.y; } c++; } if (c == 2){ if (mask.atXY(tmp_x, tmp_y) == 0 && tmp_y == p.y && tmp_x < p.x) break; } p.x = (p.x + 1) % (x1 + 1) + x0; if (p.x == x0){ p.y++; c = 0; } } p.x = tmp_x; p.y = tmp_y; //std::cout << x0 << " " << y0 << std::endl; //std::cout << tmp_x << " " << tmp_y << std::endl; std::vector<MYPOINT> stack; stack.push_back(p); MYPOINT Cur = p, Las; while (stack.size()){ mask.atXY(Cur.x, Cur.y) = 255; if (Cur.x + 1 < origin.width() && mask.atXY(Cur.x + 1, Cur.y) == 0){ Cur.x += 1; stack.push_back(Cur); continue; } if (Cur.y + 1 < origin.height() && mask.atXY(Cur.x, Cur.y +1 ) == 0){ Cur.y += 1; stack.push_back(Cur); continue; } if (Cur.x - 1 > -1 && mask.atXY(Cur.x - 1, Cur.y) == 0){ Cur.x -= 1; stack.push_back(Cur); continue; } if (Cur.y - 1 > -1 && mask.atXY(Cur.x, Cur.y - 1) == 0){ Cur.y -= 1; stack.push_back(Cur); continue; } stack.pop_back(); if (stack.size()){ Cur.x = stack.back().x; Cur.y = stack.back().y; } } return mask; }