In real time situation, the production line may produce more than single products at the same time. It should be able to determine the object type and location.
Circle or square determination is the most basic one.
Comparing outside contained rectangle or circle area with original contour area, we can easily decide the shape.

outside contained rectangle(green) circle(blue)
Besides, wavelet transformation is used to minimize interference from outside.

test picture

Canny Before wavelet transformation

Canny After wavelet transformation

find region of interest one by one
Linux and Windows versions should be united for maintenance, so using #ifdef function, I combine two versions together.
A usb camera is used to capture picture.
A robot arm is also assembled for test(using serial communication)

Final version of the whole project:
//capture picture from usb camera and determine its shape(rectangle or circle) and send serial info to robot arm //using opencv 2.4.9 //author: Chen Li //v1.0 //2014.10 #include "opencv2/opencv.hpp" #include#include #include #include //if windows #ifdef _WIN32 #include //if linux #else #include #endif //serial communication #include "rs232.h" //canny edge detection min thresh. smaller,more detailed #define THRESH 45 //min target area #define MINSELECTAREA 10000 //max object number in a picture #define MAXOBJECT 10 //gap time between two serial send #define GAPTIME 5 //seconds //serial buffer size #define SERIALBUFFER 100 //camera number #define CAMERAID 0 //if show windows during process -- comment to #define DEMO 1 using namespace cv; using namespace std; //to store object info class TP{ public: float x,y; unsigned int gx,gy; char type; //Undefined/Circle/Rectangle float attri; //Radius/Angle char text[30]; int grid[4][6]; int areano; TP(){ x=y=gx=gy=attri=0; type='U'; grid[0][0]=1313; grid[0][1]=1640; grid[0][2]=1500; grid[0][3]=1407; grid[0][4]=1520; grid[0][5]=1663; } void getpos(char typ,Point tmp,float attr){ x=tmp.x; y=tmp.y; attri=attr; type=typ; } void calgrid(){ if(x>0&&x<320) gx=0; else if(x>=240&&x<640) gx=1; if(y>0&&y<240) gy=1; else if(x>=240&&x<480) gy=0; areano=gx+gy*2; } char* formtext(){ //sprintf(text,"#8 P%d #9 P%d #10 P%d #11 P%d #12 P%d #13 P%d T2000\r\n",grid[areano][0],grid[areano][1],grid[areano][2],grid[areano][3],grid[areano][4],grid[areano][5]); sprintf(text,"PL 0 SQ %d ONCE\r\n",areano); cout< text; } }; //Variables TP tp[MAXOBJECT]; //circle number unsigned int countcircle=0; //rectangle number unsigned int countrect=0; void piccapture(){ cv::VideoCapture cap(CAMERAID); if(!cap.isOpened()) { std::cout<<"Can not open camera"< >frame; imshow("video",frame); char c=cvWaitKey(33); //press ESC to capture if(c==27) break; } #else #ifdef _WIN32 Sleep(500); #else usleep(500*1000); #endif cap>>frame; #endif imwrite("0.Capturedpic.jpg",frame); } void imageProcess(){ //read from last capture Mat frame = imread ("0.Capturedpic.jpg"); Mat image; cvtColor (frame,image,CV_BGR2GRAY); Mat imgCanny; Canny(image, imgCanny, THRESH, THRESH * 3); imwrite("1.Canny.jpg",imgCanny); Mat img_dilate,img_erode; dilate ( imgCanny, img_dilate, Mat()); //imshow("Imagedilate", img_dilate); imwrite("2.ImageDilate.jpg",img_dilate); erode ( img_dilate, img_erode, Mat()); //imshow("Imageerode", img_erode); imwrite("3.ImageErode.jpg",img_erode); vector< vector > contours; findContours(img_erode, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE); Mat contmat = Mat::zeros(imgCanny.rows, imgCanny.cols, CV_8UC3); for (int j = 0; j < contours.size(); j++){ Scalar color(255,0,0); drawContours(contmat, contours, j, color); } imwrite("4.FindContours.jpg",contmat); #ifdef DEMO namedWindow ("canny"); imshow ("canny",contmat); waitKey(0); cv::destroyAllWindows(); #endif for (int j = 0; j < contours.size(); j++){ double contarea=contourArea(contours[j]); if(contarea > contourssingle; findContours(img_erode_single, contourssingle, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE); //find the max contour in a single object(in case an object divided into more) double maxsinglearea=0; unsigned int maxposition=0; for (unsigned int sing = 0; sing < contourssingle.size(); sing++){ double contareatmp=contourArea(contourssingle[sing]); if(contareatmp>MINSELECTAREA&&contareatmp>maxsinglearea){ maxsinglearea=contareatmp; maxposition=sing; } } Mat singleselectcontour = Mat::zeros(imgCanny.rows, imgCanny.cols, CV_8UC3);; drawContours(singleselectcontour,contourssingle,maxposition,Scalar(76,76,76),CV_FILLED); imwrite("7.SingleObjectSelected.jpg",singleselectcontour); #ifdef DEMO imshow("SingleObjectSelected", singleselectcontour); #endif //find minEnclosingCircle float radius; Point2f circlecenter; minEnclosingCircle(contourssingle[maxposition], circlecenter, radius); Point circlecenterdraw; circlecenterdraw.x=circlecenter.x; circlecenterdraw.y=circlecenter.y; circle(frame, circlecenterdraw, static_cast (radius), Scalar(255,0,0), 3); double circlearea=3.14*radius*radius; //find minAreaRect RotatedRect recprofile = minAreaRect(contourssingle[maxposition]); Point2f vertices[4]; recprofile.points(vertices); for (int i = 0; i < 4; i++){ line(frame, vertices[i], vertices[(i+1)%4],Scalar(0,255,0),3); } double rectarea=recprofile.size.height*recprofile.size.width; std::cout<<"Circle area:"<
This article is among the series of FDUROP project. More information: http://104.131.150.53/thinkcmfx/index.php?g=&m=article&a=index&id=17