inline int nearest_cluster(int num_clusters, int num_coords, float *point, float **clusters) { int retval = 0; float dist, min_dist = numeric_limits<float>::max(); int i; for (i = 0; i < num_clusters; i++) { if ((dist = dist_square(num_coords, point, clusters[i])) < min_dist) { min_dist = dist; retval = i; } } return retval; }
// get ROI + edgeDectection void FindContour::cellDetection(const Mat &img, vector<Point> &cir_org, Mat &dispImg1, Mat &dispImg2, vector<Point2f> &points1, vector<Point2f> &points2, int &area, int &perimeter, Point2f &ctroid, float &shape, // vector<int> &blebs, int &frameNum){ frame = &img; //rect = boundingRect(Mat(cir)); Mat frameGray; cv::cvtColor(*frame, frameGray, CV_RGB2GRAY); /* QString cellFileName0 = "frame" + QString::number(frameNum) + ".png"; imwrite(cellFileName0.toStdString(), frameGray);*/ vector<Point> cir; //***global coordinates of circle*** for(unsigned int i = 0; i < cir_org.size(); i++){ cir.push_back(Point(cir_org[i].x / scale, cir_org[i].y / scale)); } //cout << "original circle: " << cir_org << "\n" << " scaled circle: " << cir << endl; //enlarge the bounding rect by adding a margin (e) to it rect = enlargeRect(boundingRect(Mat(cir)), 5, img.cols, img.rows); //global circle mask Mat mask_cir_org = Mat::zeros(frame->size(), CV_8UC1); fillConvexPoly(mask_cir_org, cir, Scalar(255)); // flow points vector<unsigned int> cell_pts_global; vector<Point2f> longOptflow_pt1, longOptflow_pt2; Point2f avrg_vec = Point2f(0,0); for(unsigned int i = 0; i < points1.size(); i++){ Point p1 = Point(points1[i].x, points1[i].y); Point p2 = Point(points2[i].x, points2[i].y); if(mask_cir_org.at<uchar>(p1.y,p1.x) == 255 ){ cell_pts_global.push_back(i); if(dist_square(p1, p2) > 2.0){ longOptflow_pt1.push_back(Point2f(p1.x, p1.y)); longOptflow_pt2.push_back(Point2f(p2.x, p2.y)); avrg_vec.x += (p2.x-p1.x); avrg_vec.y += (p2.y-p1.y); } } } // if(longOptflow_pt1.size()!= 0){ // avrg_vec.x = avrg_vec.x / longOptflow_pt1.size(); // avrg_vec.y = avrg_vec.y / longOptflow_pt1.size(); // } Rect trans_rect = translateRect(rect, avrg_vec); // *** // if (the homography is a good one) use the homography to update the rectangle // otherwise use the same rectangle // *** if (longOptflow_pt1.size() >= 4){ Mat H = findHomography(Mat(longOptflow_pt1), Mat(longOptflow_pt2), CV_RANSAC, 2); //cout << "H: " << H << endl; if(determinant(H) >= 0){ vector<Point> rect_corners; rect_corners.push_back(Point(rect.x, rect.y)); rect_corners.push_back(Point(rect.x+rect.width, rect.y)); rect_corners.push_back(Point(rect.x, rect.y+rect.height)); rect_corners.push_back(Point(rect.x+rect.width, rect.y+rect.height)); vector<Point> rect_update_corners = pointTransform(rect_corners, H); trans_rect = boundingRect(rect_update_corners); } } rectangle(frameGray, trans_rect, Scalar(255), 2); imshow("frameGray", frameGray); dispImg1 = (*frame)(rect).clone(); //dispImg2 = Mat(dispImg1.rows, dispImg1.cols, CV_8UC3); Mat sub; //*** the rectangle region of ROI (Gray) *** cv::cvtColor(dispImg1, sub, CV_RGB2GRAY); int width = sub.cols; int height = sub.rows; vector<Point> circle_ROI; //***local coordinates of circle*** for (unsigned int i = 0; i < cir.size(); i++){ Point p = Point(cir[i].x - rect.x, cir[i].y - rect.y); circle_ROI.push_back(p); } Mat adapThreshImg1 = Mat::zeros(height, width, sub.type()); //image edge detection for the sub region (roi rect) adaptiveThreshold(sub, adapThreshImg1, 255.0, ADAPTIVE_THRESH_GAUSSIAN_C, CV_THRESH_BINARY_INV, blockSize, constValue); //imshow("adapThreshImg1", adapThreshImg1); // dilation and erosion Mat dilerod; dilErod(adapThreshImg1, dilerod, dilSize); //display image 2 -- dilerod of adaptive threshold image GaussianBlur(dilerod, dilerod, Size(3, 3), 2, 2 ); //mask for filtering out the cell of interest Mat mask_conv = Mat::zeros(height, width, CV_8UC1); fillConvexPoly(mask_conv, circle_ROI, Scalar(255)); //imshow("mask_before", mask_conv); //dilate the mask -> region grows Mat mask_conv_dil; Mat element = getStructuringElement( MORPH_ELLIPSE, Size( 2*2+2, 2*2+1 ), Point(2,2) ); dilate(mask_conv, mask_conv_dil, element); //imshow("mask_dil", mask_conv_dil); /* Mat mask_conv_ero; erode(mask_conv, mask_conv_ero, element); Mat ring_dil, ring_ero; bitwise_xor(mask_conv, mask_conv_dil, ring_dil); bitwise_xor(mask_conv, mask_conv_ero, ring_ero); Mat ring; bitwise_or(ring_dil, ring_ero, ring); imshow("ring", ring); vector<unsigned int> opt_onRing_index; // use optflow info set rectangle for(unsigned int i = 0; i < points2.size(); i++){ Point p2 = Point(points2[i].x, points2[i].y); Point p1 = Point(points1[i].x, points1[i].y); if(ring.at<uchar>(p1.y,p1.x) != 255 && ring.at<uchar>(p2.y,p2.x) != 255) continue; else{ opt_onRing_index.push_back(i); } }*/ /* // draw the optflow on dispImg1 unsigned int size = opt_inside_cl_index.size(); for(unsigned int i = 0; i < size; i++ ){ Point p0( ceil( points1[i].x - rect.x ), ceil( points1[i].y - rect.y ) ); Point p1( ceil( points2[i].x - rect.x ), ceil( points2[i].y - rect.y) ); //std::cout << "(" << p0.x << "," << p0.y << ")" << "\n"; //std::cout << "(" << p1.x << "," << p1.y << ")" << std::endl; //draw lines to visualize the flow double angle = atan2((double) p0.y - p1.y, (double) p0.x - p1.x); double arrowLen = 0.01 * (double) (width); line(dispImg1, p0, p1, CV_RGB(255,255,255), 1 ); Point p; p.x = (int) (p1.x + arrowLen * cos(angle + 3.14/4)); p.y = (int) (p1.y + arrowLen * sin(angle + 3.14/4)); line(dispImg1, p, p1, CV_RGB(255,255,255), 1 ); p.x = (int) (p1.x + arrowLen * cos(angle - 3.14/4)); p.y = (int) (p1.y + arrowLen * sin(angle - 3.14/4)); line(dispImg1, p, Point(2*p1.x - p0.x, 2*p1.y - p0.y), CV_RGB(255,255,255), 1 ); //line(dispImg1, p, p1, CV_RGB(255,255,255), 1 ); }*/ /* //stop growing when meeting with canny edges that outside the circle Mat canny; CannyWithBlur(sub, canny); Mat cannyColor; cvtColor(canny, cannyColor, CV_GRAY2RGB); imwrite("canny.png", canny); vector<Point> outsideCircle; vector<Point> onRing; for(int j = 0; j < height; j++){ for(int i = 0; i < width; i++){ if(canny.at<uchar>(j,i) != 0 && mask_conv.at<uchar>(j,i) == 0){ cannyColor.data[cannyColor.channels()*(cannyColor.cols*j + i)+0] = 81; cannyColor.data[cannyColor.channels()*(cannyColor.cols*j + i)+1] = 172; cannyColor.data[cannyColor.channels()*(cannyColor.cols*j + i)+2] = 251; outsideCircle.push_back(Point(i, j)); if(ring.at<uchar>(j,i) != 0){ cannyColor.data[cannyColor.channels()*(cannyColor.cols*j + i)+0] = 255; cannyColor.data[cannyColor.channels()*(cannyColor.cols*j + i)+1] = 255; cannyColor.data[cannyColor.channels()*(cannyColor.cols*j + i)+2] = 0; onRing.push_back(Point(i,j)); } } } } */ // QString cannyFileName = "canny" + QString::number(frameNum) + ".png"; // imwrite(cannyFileName.toStdString(), cannyColor); //bitwise AND on mask and dilerod bitwise_and(mask_conv/*_dil*/, dilerod, dispImg2); // findcontours vector<vector<Point> > contours; vector<Vec4i> hierarchy; unsigned int largest_contour_index; dilErodContours(dispImg2, contours, hierarchy, largest_contour_index, perimeter, dispImg1); // find the area of the cell by counting the white area inside the largest contour Mat cellArea = Mat::zeros(height, width, CV_8UC1); drawContours(cellArea, contours, largest_contour_index, Scalar(255), -1, 8, hierarchy, 0, Point() ); //imshow("cell", cell); area = countNonZero(cellArea); //cout << "frame " << frameNum << "\n"; //cout << contours[largest_contour_index] << endl; //change dispImg2 from gray to rgb for displaying cvtColor(dispImg2, dispImg2, CV_GRAY2RGB); //renew circle points as the convex hull vector<Point> convHull; convexHull(contours[largest_contour_index], convHull); // find the centroid of the contour Moments mu = moments(contours[largest_contour_index]); ctroid = Point2f(mu.m10/mu.m00 + rect.x, mu.m01/mu.m00 + rect.y); // find the shape of the cell by the largest contour and centroid shape = findShape(ctroid, contours[largest_contour_index]); ////---- draw largest contour start ---- //draw the largest contour Mat borderImg = Mat::zeros(height, width, CV_8UC1); drawContours(borderImg, contours, largest_contour_index, Scalar(255), 1, 8, hierarchy, 0, Point()); //QString cellFileName0 = "border" + QString::number(frameNum) + ".png"; //imwrite(cellFileName0.toStdString(), borderImg); ////---- draw largest contour end ---- // find the number and the sizes of blebs of the cell Mat smooth; vector<Point> smoothCurve; int WIN = 25; vector< vector<Point> > tmp; smooth = curveSmooth(borderImg, WIN, contours[largest_contour_index], smoothCurve, convHull/*ctroid*/); tmp.push_back(smoothCurve); drawContours(dispImg1, tmp, 0, Scalar(255, 0, 0)); bitwise_not(smooth, smooth); Mat blebsImg; bitwise_and(smooth, cellArea, blebsImg); //imshow("blebs", blebs); //QString cellFileName2 = "blebs" + QString::number(frameNum) + ".png"; //imwrite(cellFileName2.toStdString(), blebs); // vector<Point> blebCtrs; // recursive_connected_components(blebsImg, blebs, blebCtrs); // for(unsigned int i = 0; i < blebCtrs.size(); i++){ // circle(dispImg1, blebCtrs[i], 2, Scalar(255, 255, 0)); // } cir_org.clear(); for(unsigned int i = 0; i < convHull.size(); i++) cir_org.push_back(Point((convHull[i].x + rect.x)*scale, (convHull[i].y + rect.y)*scale)); }