Reputation: 37
Recently I made my first vision application. My code can recognise marbles of a certain colour and gives me the X,Y,Z coordinates of this marble. To debug and setup my system I made some code with which I can easily tweak and try settings. This code tries to detect all marbles within an image and tells me where it thinks marbles are by marking it with a green dot.
Basically my code works like this: My camera takes a picture.
It looks for colours within a certain range and makes a mask out of this (within range is white, out of range is black) like this: .
I then look for circles within this image using the houghcircles
command.
I extract the centre point from each detected circle and put it over the original image, like this: (green dot = centre circle)
There are still some problem with my detection but for the moment I am quite satisfied.
Now, the thing I would like to know is this: Is it possible to put a percentage next to each marked centre point, telling me how sure the program is that it is a circle.
If you have any other suggestions or questions feel free to ask. I've put my code below:
#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <librealsense2/rs.hpp>
using namespace std;
using namespace cv;
Mat image;
Mat imgHSV;
Mat OutputImage;
Mat testframe;
int iLowH = 104;
int iHighH = 111;
int iLowS = 109;
int iHighS = 155;
int iLowV = 120;
int iHighV = 255;
int acc = 1;
int rows = 10;
int para1 = 100;
int para2 = 7;
int minRad = 3;
int maxRad = 14;
static void HSVthreshold(int, int, int, int, int, int, void*)
{
inRange(imgHSV, Scalar(iLowH, iLowS, iLowV), Scalar(iHighH, iHighS, iHighV), OutputImage);
}
static void Circle_detector(int, int, int, int, int, void*)
{
vector<Vec3f> circles;
HoughCircles(OutputImage, circles, HOUGH_GRADIENT, 1,
OutputImage.rows / rows, //change to detect circles that are closer to eachother
para1, para2, minRad, maxRad); //chang last to parameters to detect larger or smaller circles
for (size_t i = 0; i < circles.size(); i++)
{
Vec3i c = circles[i];
Point center = Point(c[0], c[1]);
// circle center
circle(testframe, center, 1, Scalar(0, 255, 0), 2, LINE_AA);
// circle outline
int radius = c[2];
circle(imgHSV, center, radius, Scalar(255, 0, 0), 2, LINE_AA);
}
}
int main()
{
// Contructing piplines and other stuff to receive data from the realsense camera.
//Contruct a pipeline which abstracts the device
rs2::pipeline pipe;
//Create a configuration for configuring the pipeline with a non default profile
rs2::config cfg;
//Add desired streams to configuration
cfg.enable_stream(RS2_STREAM_COLOR, 640, 480, RS2_FORMAT_BGR8, 30);
//Instruct pipeline to start streaming with the requested configuration
pipe.start(cfg);
// Camera warmup - dropping several first frames to let auto-exposure stabilize
rs2::frameset frames;
for (int i = 0; i < 30; i++)
{
//Wait for all configured streams to produce a frame
frames = pipe.wait_for_frames();
}
while (waitKey(1) < 0)
{
frames = pipe.wait_for_frames();
//Get each frame
rs2::frame color_frame = frames.get_color_frame();
// Creating OpenCV Matrix from a color image
Mat color(Size(640, 480), CV_8UC3, (void*)color_frame.get_data(), Mat::AUTO_STEP);
// Display in a GUI
if (color.empty())
{
cerr << "image was not generated !" << endl;
return 1;
}
testframe = color;
namedWindow("Display Image", WINDOW_AUTOSIZE);
imshow("Display Image", color);
//convert RGB to HSV
cvtColor(color, imgHSV, COLOR_BGR2HSV);
//Create windows
namedWindow("image", WINDOW_AUTOSIZE); //window for original image
namedWindow("Control", WINDOW_AUTOSIZE); //window for HSV-control sliders
namedWindow("Output", WINDOW_AUTOSIZE); //window for output mask
namedWindow("Control HoughCircles", WINDOW_AUTOSIZE); //window for HoughCircle sliders
namedWindow("Test-window", WINDOW_AUTOSIZE);
//Create trackbars in "Control HSV" window
createTrackbar("LowH", "Control", &iLowH, 179); //Hue (0 - 179)
createTrackbar("HighH", "Control", &iHighH, 179);
createTrackbar("LowS", "Control", &iLowS, 255); //Saturation (0 - 255)
createTrackbar("HighS", "Control", &iHighS, 255);
createTrackbar("LowV", "Control", &iLowV, 255); //Value (0 - 255)
createTrackbar("HighV", "Control", &iHighV, 255);
int key = 0;
while (key != 27) { // 27 is escape
HSVthreshold(iLowH, iHighH, iLowS, iHighS, iLowV, iHighV, 0);
imshow("Output", OutputImage);
imshow("image", imgHSV);
key = waitKey(1); // wait at most 1 ms for input, if nothing was pressed result is -1
}
//Optional filter --> does not work properly at the moment <--
//morphological opening (remove small objects from the foreground)
erode(OutputImage, OutputImage, getStructuringElement(MORPH_ELLIPSE, Size(1, 1)));
dilate(OutputImage, OutputImage, getStructuringElement(MORPH_ELLIPSE, Size(1, 1)));
//morphological closing (fill small holes in the foreground)
dilate(OutputImage, OutputImage, getStructuringElement(MORPH_ELLIPSE, Size(5, 5)));
erode(OutputImage, OutputImage, getStructuringElement(MORPH_ELLIPSE, Size(5, 5)));
imshow("Output", OutputImage);
waitKey();
//Create trackbars in "Control HoughCircles" window
createTrackbar("Distance between detections", "Control HoughCircles", &rows, 50); //detection distance (0 - 50)
createTrackbar("Upper threshold for internal canny edge", "Control HoughCircles", ¶1, 100); //upper threshold for internal canny edge detector (0 - 100)
createTrackbar("threshold for internal canny edge", "Control HoughCircles", ¶2, 50); //threshold for internal canny edge detector (0 - 50)
createTrackbar("Min radius", "Control HoughCircles", &minRad, 200); //minimum circle radius (0 - 200)
createTrackbar("Max radiu", "Control HoughCircles", &maxRad, 200); // maximum circle radius (0 - 200)
int key2 = 0;
while (key2 != 27) { // 27 is escape
Circle_detector(rows, para1, para2, minRad, maxRad, 0);
imshow("image", imgHSV);
imshow("Test-window", testframe);
key2 = waitKey(1); // wait at most 1 ms for input, if nothing was pressed result is -1
}
waitKey();
}
return 0;
}
EDIT: I've added some new pictures of my testing material, sadly this is not completely equal to the situation above due to light conditions.
Upvotes: 1
Views: 167
Reputation: 4352
I tried the picture you added. I didn't use something differently comparing to your code. I focused to check the pixels inside of each circle. Here are my steps:
medianBlur
to decrease noiseHoughCircles
to binary imageHoughCircles
crop the each circle by a rectangleHere is my code and results(Results are no different with yours, the important part is checking inside the circle):
Code:
#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <librealsense2/rs.hpp>
using namespace std;
using namespace cv;
int main()
{
Mat color = imread("/ur/image/directory/marble.png",1);
Mat hsv;
cvtColor(color, hsv, COLOR_BGR2HSV);
Mat board = Mat::zeros(hsv.rows,hsv.cols,CV_8UC1);
for(int i=0; i<hsv.rows; i++)
{
for(int j=0; j<hsv.cols; j++)
{
if(hsv.at<Vec3b>(Point(j,i))[2]<60 && hsv.at<Vec3b>(Point(j,i))[2]>20 && hsv.at<Vec3b>(Point(j,i))[1]<120 && hsv.at<Vec3b>(Point(j,i))[1]>50
&& hsv.at<Vec3b>(Point(j,i))[0]<105 && hsv.at<Vec3b>(Point(j,i))[0]>85)
board.at<uchar>(Point(j,i)) = 254;
}
}
medianBlur(board,board,3);
vector<Vec3f> circles;
HoughCircles(board, circles, HOUGH_GRADIENT, 1,
board.rows / 10, //change to detect circles that are closer to eachother
100, 7, 3, 14); //chang last to parameters to detect larger or smaller circles
for (size_t i = 0; i < circles.size(); i++)
{
Vec3i cc = circles[i];
Point center = Point(cc[0], cc[1]);
// circle center
circle(color, center, 1, Scalar(0, 255, 0), 2, LINE_AA);
// circle outline
int radius = cc[2];
circle(color, center, radius, Scalar(255, 0, 0), 2, LINE_AA);
// Firstly, Crop that region
Rect crop(center.x-radius-5, center.y-radius-5,2*radius+10,2*radius+10);
Mat crop_for_test = hsv(crop);
//Secondly, check each pixel inside the circle or not
for(int r=0; r<crop_for_test.rows; r++)
{
for(int c=0; c<crop_for_test.cols; c++)
{
double length_to_center = norm(Point(cc[0]-(center.x-radius-5), cc[1]-(center.y-radius-5))-Point(r,c));
if(length_to_center<radius)
{
// Here all points inside the circle
cout<<"H value: "<<to_string(crop_for_test.at<Vec3b>(Point(r,c))[2])<<" "<<"S value: "
<<to_string(crop_for_test.at<Vec3b>(Point(r,c))[1])<<" "<<"V value: "
<<to_string(crop_for_test.at<Vec3b>(Point(r,c))[0])<<endl;
}
}
}
}
imshow("board",board);
imshow("hsv",hsv);
imshow("rgb",color);
waitKey(0);
return 0;
}
HSV Input:
Binary after filter:
Output:
Upvotes: 1