/** * This function fits ellipses to each set of points (contour). */ void MyEllipses::fitEllipses(){ int size = linkedPoints.size(); cv::vector<cv::Point> currentContour; cv::vector<cv::RotatedRect> minEllipse(size); cv::Scalar color = cv::Scalar( 255,0,0 ); int validEllipsesCounter = 0; for( int i = 0; i < size; i++){ currentContour = linkedPoints[i]; if( currentContour.size()>5){ minEllipse[validEllipsesCounter] = cv::fitEllipse(cv::Mat(currentContour)); //cv::ellipse( ellipsesImage, minEllipse[i], color, 2, 8 ); validEllipsesCounter++; } } minEllipse.resize(validEllipsesCounter); fittedEllipses = minEllipse; }
static std::vector<cv::RotatedRect> blob_finder(cv::Mat *pic){ cv::Mat cppic; pic->copyTo(cppic); cv::normalize(cppic,cppic,0, 255, cv::NORM_MINMAX, CV_8UC1); cv::Mat img(cppic.rows/4,cppic.cols/4,CV_8UC1); cv::resize(cppic,img,img.size()); int rad=6; cv::Point pos(0,0); // float abs_max=0; // float *p_res, *p_avg, *p_blob; float *p_res, *p_blob; cv::Mat result = cv::Mat::zeros(img.rows,img.cols,CV_32FC1); cv::Mat res_blob,res_avg,blob_mat; gen_blob_neu(rad,&blob_mat); img.convertTo(img, CV_32FC1); filter2D(img, res_blob, -1 , blob_mat, cv::Point( -1, -1 ), 0, cv::BORDER_REPLICATE ); for(int i=20; i<result.rows;i++){ //ignore 20 first becouse of advertisement p_res=result.ptr<float>(i); //p_avg=res_avg.ptr<float>(i); p_blob=res_blob.ptr<float>(i); for(int j=0; j<result.cols;j++){ if(p_blob[j]>15) p_res[j]=p_blob[j]*p_blob[j]; else p_res[j]=0; } } //cv::normalize(result,result,0, 255, cv::NORM_MINMAX, CV_8UC1); float lmin=100000000; float lmax=0; float rmin=100000000; float rmax=0; for(int i=0; i<result.rows;i++){ p_res=result.ptr<float>(i); for(int j=0; j<result.cols/2;j++){ if(p_res[j]<lmin) lmin=p_res[j]; if(p_res[j]>lmax) lmax=p_res[j]; } for(int j=result.cols/2; j<result.cols;j++){ if(p_res[j]<rmin) rmin=p_res[j]; if(p_res[j]>rmax) rmax=p_res[j]; } } //norm for(int i=0; i<result.rows;i++){ p_res=result.ptr<float>(i); for(int j=0; j<result.cols/2;j++){ p_res[j]= ((p_res[j]-lmin)/(lmax-lmin))*255; } for(int j=result.cols/2; j<result.cols;j++){ p_res[j]= ((p_res[j]-rmin)/(rmax-rmin))*255; } } result.convertTo(result, CV_8UC1); cv::threshold(result,result,100,255,cv::THRESH_BINARY); std::vector<std::vector<cv::Point>> contours; std::vector<cv::Vec4i> hierarchy; cv::findContours( result, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, cv::Point(0, 0) ); std::vector<cv::RotatedRect> minEllipse( contours.size() ); for( size_t i = 0; i < contours.size(); i++ ){ if( contours[i].size() > 5 ){ minEllipse[i] = cv::fitEllipse( cv::Mat(contours[i]) ); minEllipse[i].center.x=minEllipse[i].center.x*4; minEllipse[i].center.y=minEllipse[i].center.y*4; minEllipse[i].size.width=minEllipse[i].size.width*10; minEllipse[i].size.height=minEllipse[i].size.height*10; minEllipse[i].center.x=minEllipse[i].center.x-(minEllipse[i].size.width/2); minEllipse[i].center.y=minEllipse[i].center.y-(minEllipse[i].size.height/2); } } std::vector<cv::RotatedRect> pupiEllipse; cv::Mat pupil_region; for( size_t k = 0; k < minEllipse.size(); k++ ){ if(minEllipse[k].size.height>0 && minEllipse[k].size.width>0){ pupil_region=cv::Mat::zeros(minEllipse[k].size.height,minEllipse[k].size.width,CV_8UC1); for(int i=0; i<pupil_region.rows;i++) for(int j=0; j<pupil_region.cols;j++) if(int(minEllipse[k].center.y+i)>0 && int(minEllipse[k].center.y+i)<cppic.rows && minEllipse[k].center.x+j>0 && minEllipse[k].center.x+j<cppic.cols){ pupil_region.data[(pupil_region.cols*i)+j]=cppic.data[( cppic.cols*int(minEllipse[k].center.y+i)) + int(minEllipse[k].center.x+j)]; } //cv::imshow("pr",pupil_region); //cv::waitKey(10); cv::normalize(pupil_region,pupil_region,0, 255, cv::NORM_MINMAX, CV_8UC1); //histo seperation int histi[256]; for(int i=0; i<256;i++) histi[i]=0; for(int i=0; i<pupil_region.rows;i++) for(int j=0; j<pupil_region.cols;j++){ histi[pupil_region.data[(pupil_region.cols*i)+j]]++; } /* cv::Mat sh_hist=cv::Mat::zeros(800,256, CV_8UC1); for(int i=0; i<256;i++) for(int j=0; j<histi[i] && j<800;j++) sh_hist.data[(sh_hist.cols*(799-j))+i]=255; cv::imshow("histo",sh_hist); cv::waitKey(100); */ int window=25; int maxima[100]; int maxima_idx=0; for(int i=0; i<100;i++) maxima[i]=0; for(int i=0; i<256;i++){ bool bigest=true; for(int j=-window; j<=window && bigest;j++){ if(i+j>=0 && i+j<256 && histi[i+j]>histi[i]) bigest=false; } if(bigest) maxima[maxima_idx++]=i; } if(maxima_idx<2) return pupiEllipse; int max1=maxima[0]; int help_idx=0; for(int i=0; i<maxima_idx;i++){ if(histi[maxima[i]]>histi[max1]){ max1=maxima[i]; help_idx=i; } } maxima[help_idx]=255; int max2=maxima[0]; for(int i=0; i<maxima_idx;i++){ if(histi[maxima[i]]>histi[max2]){ max2=maxima[i]; } } int m1=(max1>max2)?max1:max2; int m2=(max1<max2)?max1:max2; int min_val=1000000; int min_idx=0; for(int i=m2+1; i<m1;i++){ int cnt=0; int val=0; for(int j=-window; j<=window;j++){ if(i+j>0 && i+j<256){ val+=histi[i+j]; cnt++; } } if(cnt>0) val=val/cnt; else val=0; if(val<min_val){ min_val=val; min_idx=i; } } cv::threshold(pupil_region,pupil_region,min_idx,255,cv::THRESH_BINARY); /* std::cout<<max1<<":"<<max2<<"|"<<min_idx<<std::endl; cv::imshow("prth",pupil_region); cv::waitKey(1000); */ //contur contours.clear(); hierarchy.clear(); //cv::findContours( pupil_region, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, cv::Point(0, 0) ); cv::Mat border(pupil_region.rows,pupil_region.cols,CV_8UC1, cv::Scalar(0,0,0)); for(int i=1;i<pupil_region.rows-1;i++) for(int j=1;j<pupil_region.cols-1;j++) if(pupil_region.data[(pupil_region.cols*i)+j]>0){ bool has_black=false; for(int k1=-1;k1<=1;k1++) for(int k2=-1;k2<=1;k2++) if(pupil_region.data[(pupil_region.cols*(i+k1))+(j+k2)]==0) has_black=true; if(has_black) border.data[(border.cols*i)+j]=255; } /* cv::imshow("contur",border); cv::waitKey(10000); */ //collect lines std::vector<cv::Point> ak_line; for(int i=0;i<border.rows;i++) for(int j=0;j<border.cols;j++) if(border.data[(border.cols*i)+j]==255){ ak_line.clear(); border.data[(border.cols*i)+j]=200; ak_line.push_back(cv::Point(j,i)); size_t ak_idx=0; while(ak_idx<ak_line.size()){ cv::Point ak_pos=ak_line.at(ak_idx); for(int k1=-1;k1<=1;k1++) for(int k2=-1;k2<=1;k2++) if(ak_pos.y+k1>0 && ak_pos.y+k1<border.rows && ak_pos.x+k2>0 && ak_pos.x+k2<border.cols) if(border.data[(border.cols*(ak_pos.y+k1))+(ak_pos.x+k2)]==255){ border.data[(border.cols*(ak_pos.y+k1))+(ak_pos.x+k2)]=200; ak_line.push_back(cv::Point(ak_pos.x+k2,ak_pos.y+k1)); } ak_idx++; } if(ak_line.size()>10) contours.push_back(ak_line); } int index=-1; for( size_t i = 0; i < contours.size(); i++ ) if(index==-1 || contours[index].size()<contours[i].size()) index=i; //ellipse fit RANSAC like only better :-) if(index>=0) for( int i = index; i <=index; i++ ){ if( contours[i].size() > 5 ){ cv::RotatedRect best_pupi; best_pupi.size.width=100; best_pupi.size.height=1000; int step=contours[i].size()/4; std::vector<cv::Point> ak_set; for(int iter=0;iter<4;iter++){ cv::RotatedRect ak_pupi; ak_set.clear(); for(int set_st=step*iter;set_st<(step*iter)+(2*step);set_st++) ak_set.push_back(contours[i].at(set_st%contours[i].size())); if(ak_set.size()>5){ ak_pupi=cv::fitEllipse( cv::Mat(ak_set) ); /* cv::ellipse(pupil_region,ak_pupi,cv::Scalar(150,150,150),1,8); cv::imshow("ellipses",pupil_region); */ } if(ak_pupi.center.x>0 && ak_pupi.center.y>0 && ak_pupi.size.height>0 && ak_pupi.size.width>0 && ak_pupi.size.height*ak_pupi.size.width>200 && ak_pupi.size.height-ak_pupi.size.width<20){ if(abs(best_pupi.size.width-best_pupi.size.height)>abs(ak_pupi.size.width-ak_pupi.size.height)) best_pupi=ak_pupi; } } if(best_pupi.center.x>0 && best_pupi.center.y>0 && best_pupi.size.height>0 && best_pupi.size.width>0 && best_pupi.size.height*best_pupi.size.width>200 && best_pupi.size.height-best_pupi.size.width<20){ best_pupi.center.x+=minEllipse[k].center.x; best_pupi.center.y+=minEllipse[k].center.y; pupiEllipse.push_back(best_pupi); } } } } } minEllipse.clear(); /* cv::imshow("img",*pic); cv::imshow("pupils",result); cv::waitKey(200); */ return pupiEllipse; }
void imageCb(const sensor_msgs::ImageConstPtr& msg) { cv_bridge::CvImagePtr cv_ptr; try { cv_ptr = cv_bridge::toCvCopy(msg, enc::BGR8); } catch (cv_bridge::Exception& e) { ROS_ERROR("cv_bridge exception: %s", e.what()); return; } cv::Mat CircleImage; cv::resize(cv_ptr->image,CircleImage,cv::Size(cv_ptr->image.cols/processingScale,cv_ptr->image.rows/processingScale)); cv::cvtColor( CircleImage, CircleImage, CV_BGR2GRAY ); //cout << "3 " << endl; cv::GaussianBlur( CircleImage, CircleImage, cv::Size(5, 5), 2, 2 ); // cv::vector<cv::Vec3f> circles; // cv::imshow(WINDOW, CircleImage); // cv::HoughCircles( CircleImage, circles, CV_HOUGH_GRADIENT, 1, CircleImage.rows/(8*processingScale), 200, 100, 0, 0 ); cv::vector<std::vector<cv::Point> > contours; cv::vector<cv::Vec4i> hierarchy; cv::Canny(CircleImage,CircleImage,100,250,3); //cv::imshow(WINDOW, CircleImage); cv::findContours(CircleImage,contours,hierarchy,CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, cv::Point(0, 0) ); cv::vector<cv::RotatedRect> minEllipse( contours.size() ); int numCircles = 0; bool circleMask [contours.size()]; for (int i = 0;i<contours.size();i++) { circleMask[i] = false; } for( int i = 0; i < contours.size(); i++ ) { if( contours[i].size() > 5 ) { minEllipse[i] = cv::fitEllipse( cv::Mat(contours[i]) ); minEllipse[i].center.x = minEllipse[i].center.x * processingScale; minEllipse[i].center.y = minEllipse[i].center.y * processingScale; minEllipse[i].size.height = minEllipse[i].size.height * processingScale; minEllipse[i].size.width = minEllipse[i].size.width * processingScale; double approxCircle = minEllipse[i].size.height>minEllipse[i].size.width?minEllipse[i].size.height/minEllipse[i].size.width:minEllipse[i].size.width/minEllipse[i].size.height; std::cout << i << ":" << approxCircle; if (approxCircle<majorToMinor) { std::cout << ": yes" << std::endl; numCircles++; circleMask[i] = true; cv::Scalar color = cv::Scalar( 255,255,0 ); cv::ellipse( cv_ptr->image, minEllipse[i], color, 2, 8 ); } std::cout << std::endl; } } // std::cout << "Sizes: " << minEllipse.size() << ":"<< numCircles << std::endl; std::vector<double> x; std::vector<double> y; std::vector<double> r; if (true)//numCircles>4 && numCircles<20 && minEllipse.size()<35) // culls out larger data sets { bool flag = false; for (int i = 0; i<minEllipse.size();i++) { if (circleMask[i]==true) { for (int j=0; j<minEllipse.size();j++) { if (circleMask[j]==true && i!=j && ImageConverter::Distance(minEllipse[i].center.x,minEllipse[i].center.y,minEllipse[j].center.x,minEllipse[j].center.y) < 10) { // std::cout << i << ":" << j << "::::"<< abs( (minEllipse[i].size.height>minEllipse[j].size.height ? minEllipse[i].size.height/minEllipse[j].size.height : minEllipse[j].size.height/minEllipse[i].size.height) - 2) << std::endl; double r0 = minEllipse[i].size.height>minEllipse[i].size.width? minEllipse[i].size.height : minEllipse[i].size.width; double r1 = minEllipse[j].size.height>minEllipse[j].size.width? minEllipse[j].size.height : minEllipse[j].size.width; double diff = (r0>r1?r0/r1:r1/r0); diff = (diff-2.0)>0.0?(diff-2.0):-(diff-2.0); // manual abs std::cout << r0 << ":" << r1 << "::::"<<diff; if (diff < 0.5) { std::cout << " yes "; // calculates distance between points bool success = true; for (int k=0;k<x.size();k++) { if( abs(x.at(k)-minEllipse[i].center.x)<10 && abs(y.at(k)-minEllipse[i].center.y)<10 ) {success=false;} } if(success) { x.push_back(minEllipse[i].center.x); y.push_back(minEllipse[i].center.y); r.push_back(r0>r1?r0:r1); cv::Scalar color = cv::Scalar( 0,0,255); cv::ellipse( cv_ptr->image, minEllipse[r0>r1?i:j], color, 2, 8 ); } if (x.size() == 4) { std::cout << "Points: " << x.size() << std::endl; for (int index = 0; index < x.size(); index++) { circle_data.data[3*index]=x.at(index); circle_data.data[3*index+1]=y.at(index); circle_data.data[3*index+2]=r.at(index); } circle_pub.publish(circle_data); flag=true; break; } } std::cout << std::endl; } } } if (flag==true){break;} } } cv::imshow(WINDOW, cv_ptr->image); //std::cout<<"lbl 2"<<std::endl; cv::waitKey(1); // std::cout<<"lbl 3"<<std::endl; image_pub_.publish(cv_ptr->toImageMsg()); //std::cout<<"lbl 4"<<std::endl; }
void do_work(const sensor_msgs::ImageConstPtr& msg, const std::string input_frame_from_msg) { // Work on the image. try { // Convert the image into something opencv can handle. cv::Mat frame = cv_bridge::toCvShare(msg, msg->encoding)->image; // Messages opencv_apps::RotatedRectArrayStamped rects_msg, ellipses_msg; rects_msg.header = msg->header; ellipses_msg.header = msg->header; // Do the work cv::Mat src_gray; /// Convert image to gray and blur it if ( frame.channels() > 1 ) { cv::cvtColor( frame, src_gray, cv::COLOR_RGB2GRAY ); } else { src_gray = frame; } cv::blur( src_gray, src_gray, cv::Size(3,3) ); /// Create window if( debug_view_) { cv::namedWindow( window_name_, cv::WINDOW_AUTOSIZE ); } cv::Mat threshold_output; int max_thresh = 255; std::vector<std::vector<cv::Point> > contours; std::vector<cv::Vec4i> hierarchy; cv::RNG rng(12345); /// Detect edges using Threshold cv::threshold( src_gray, threshold_output, threshold_, 255, cv::THRESH_BINARY ); /// Find contours cv::findContours( threshold_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, cv::Point(0, 0) ); /// Find the rotated rectangles and ellipses for each contour std::vector<cv::RotatedRect> minRect( contours.size() ); std::vector<cv::RotatedRect> minEllipse( contours.size() ); for( size_t i = 0; i < contours.size(); i++ ) { minRect[i] = cv::minAreaRect( cv::Mat(contours[i]) ); if( contours[i].size() > 5 ) { minEllipse[i] = cv::fitEllipse( cv::Mat(contours[i]) ); } } /// Draw contours + rotated rects + ellipses cv::Mat drawing = cv::Mat::zeros( threshold_output.size(), CV_8UC3 ); for( size_t i = 0; i< contours.size(); i++ ) { cv::Scalar color = cv::Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) ); // contour cv::drawContours( drawing, contours, (int)i, color, 1, 8, std::vector<cv::Vec4i>(), 0, cv::Point() ); // ellipse cv::ellipse( drawing, minEllipse[i], color, 2, 8 ); // rotated rectangle cv::Point2f rect_points[4]; minRect[i].points( rect_points ); for( int j = 0; j < 4; j++ ) cv::line( drawing, rect_points[j], rect_points[(j+1)%4], color, 1, 8 ); opencv_apps::RotatedRect rect_msg; opencv_apps::Point2D rect_center; opencv_apps::Size rect_size; rect_center.x = minRect[i].center.x; rect_center.y = minRect[i].center.y; rect_size.width = minRect[i].size.width; rect_size.height = minRect[i].size.height; rect_msg.center = rect_center; rect_msg.size = rect_size; rect_msg.angle = minRect[i].angle; opencv_apps::RotatedRect ellipse_msg; opencv_apps::Point2D ellipse_center; opencv_apps::Size ellipse_size; ellipse_center.x = minEllipse[i].center.x; ellipse_center.y = minEllipse[i].center.y; ellipse_size.width = minEllipse[i].size.width; ellipse_size.height = minEllipse[i].size.height; ellipse_msg.center = ellipse_center; ellipse_msg.size = ellipse_size; ellipse_msg.angle = minEllipse[i].angle; rects_msg.rects.push_back(rect_msg); ellipses_msg.rects.push_back(ellipse_msg); } /// Create a Trackbar for user to enter threshold if( debug_view_) { if (need_config_update_) { config_.threshold = threshold_; srv.updateConfig(config_); need_config_update_ = false; } cv::createTrackbar( "Threshold:", window_name_, &threshold_, max_thresh, trackbarCallback); cv::imshow( window_name_, drawing ); int c = cv::waitKey(1); } // Publish the image. sensor_msgs::Image::Ptr out_img = cv_bridge::CvImage(msg->header, sensor_msgs::image_encodings::BGR8, drawing).toImageMsg(); img_pub_.publish(out_img); rects_pub_.publish(rects_msg); ellipses_pub_.publish(ellipses_msg); } catch (cv::Exception &e) { NODELET_ERROR("Image processing error: %s %s %s %i", e.err.c_str(), e.func.c_str(), e.file.c_str(), e.line); } prev_stamp_ = msg->header.stamp; }