Detecting circles with OpenCV in a Win10 C++ Universal App - c++

I have some issues detecting circles in a Win10 Universal App (C++).
I Need to detect the blue circles in the following Image:
For that reason I am using OpenCV with the following code:
Mat img_image = imread("template_rund.png");
Mat img_hsv;
Mat img_result;
Mat img_blue;
Mat img_canny;
cvtColor(img_image, img_image, CV_BGR2BGRA);
cv::cvtColor(img_image, img_hsv, cv::COLOR_BGR2HSV);
cv::inRange(img_hsv, cv::Scalar(100, 50, 0), cv::Scalar(140, 255, 255), img_blue);
cv::Canny(img_blue, img_canny, 300, 350);
std::vector<cv::Vec3f> circles;
GaussianBlur(img_canny, img_canny, cv::Size(9, 9), 2, 2);
cv::HoughCircles(img_canny, circles, CV_HOUGH_GRADIENT, 2, 5, 1000, 1000, 0, 1000);
for (size_t current_circle = 0; current_circle < circles.size(); ++current_circle) {
...
}
The algorithm is working fine until the HoughCircles-call.
Inside the circles-vector should be stored all found circles.
But the size of the vector is always about 1537228453755672812
At that Point i thought it would be a good idea to Change the Parameters of the HoughCircles-Call. B ut if I Change the min/max-radius to lets say 10/100, the algorithm still find around 1517229... Circles.
What could be the problem?
Further Info:
I compiled the OCV-Libraries for Windows by myself:
https://msopentech.com/blog/2015/05/15/uap-in-action-running-opencv-on-raspberry-pi-ii/#

Related

How to build cv::Mat from coloured rectangles

My goal is to create yield maps using OpenCV. These yield maps need to be built with coloured rectangles to indicate yield. An example of a Mat built by rectangles here.
So is it possible to create a cv::Mat with coloured rectangles? The amount of rectangles isn't constant, thus changes with every use.
To make the question clear: if I have 4 boxes (2x2 grid) I want to automatically make a Mat which is as big as the 4 boxes. If I have 16 boxes (4x4 grid) I want to make a Mat which is as big as the 16 boxes.
I couldn't find a way to make it work, so I hope somebody here knows if it is possible.
If somebody can help me that would be great, if it is not possible alternatives are also welcome! Thanks
Some info:
OpenCV version:4.5.3
OS: Ubuntu 20.04
Language: C++
You can create rectangle with OpenCV function.
Basic Geometric Drawing OpenCV
int x = 0;
int y = 0;
int width = 10;
int height = 20;
// our rectangle...
cv::Rect rect(x, y, width, height);
// and its top left corner...
cv::Point pt1(x, y);
// and its bottom right corner.
cv::Point pt2(x + width, y + height);
// These two calls...
cv::rectangle(img, pt1, pt2, cv::Scalar(0, 255, 0));
// essentially do the same thing
cv::rectangle(img, rect, cv::Scalar(0, 255, 0))
ref
OpenCV has cv::hconcat and cv::vconcat. Use them like numpy's hstack/vstack.
make sure your parts have the same type (and number of channels).
The documentation has a code example.
cv::Mat matArray[] = { cv::Mat(4, 1, CV_8UC1, cv::Scalar(1)),
cv::Mat(4, 1, CV_8UC1, cv::Scalar(2)),
cv::Mat(4, 1, CV_8UC1, cv::Scalar(3)),};
cv::Mat out;
cv::hconcat( matArray, 3, out );
//out:
//[1, 2, 3;
// 1, 2, 3;
// 1, 2, 3;
// 1, 2, 3]

opencv cornerSubPix Exception while converting python code to c++

I am trying to port this response to c++ but I am not able to get past this cryptic exception (see image below). Not sure what is the limiting factor. I imagine it is the image color format or the corners parameter but nothing seems to be working. If it is related to converting color format please provide a small code snippet.
The python code provided by Anubhav Singh is working great however I would like to develop in c++. Any help would be greatly appreciated.
I am using OpenCV04.2.0
void CornerDetection(){
std::string image_path = samples::findFile("../wing.png");
Mat img = imread(image_path);
Mat greyMat;
Mat dst;
cv::cvtColor(img, greyMat, COLOR_BGR2GRAY);
threshold(greyMat, greyMat, 0, 255, THRESH_BINARY | THRESH_OTSU);
cornerHarris(greyMat, dst, 9, 5, 0.04);
dilate(dst, dst,NULL);
Mat img_thresh;
threshold(dst, img_thresh, 0.32 * 255, 255, 0);
img_thresh.convertTo(img_thresh, CV_8UC1);
Mat labels = Mat();
Mat stats = Mat();
Mat centroids = Mat();
cv::connectedComponentsWithStats(img_thresh, labels, stats, centroids, 8, CV_32S);
TermCriteria criteria = TermCriteria(TermCriteria::EPS + TermCriteria::MAX_ITER, 30, 0.001);
std::vector<Point2f> corners = std::vector<Point2f>();
Size winSize = Size(5, 5);
Size zeroZone = Size(-1, -1);
cornerSubPix(greyMat, corners, winSize, zeroZone, criteria);
for (int i = 0; i < corners.size(); i++)
{
circle(img, Point(corners[i].x, corners[i].y), 5, Scalar(0, 255, 0), 2);
}
imshow("img", img);
waitKey();
destroyAllWindows();
}
The solution was to iterate over the centroids to build the corners vector before passing the corners variable to the cornerSubPix(...) function.
std::vector<Point2f> corners = std::vector<Point2f>();
for (int i = 0; i < centroids.rows; i++)
{
double x = centroids.at<double>(i, 0);
double y = centroids.at<double>(i, 1);
corners.push_back(Point2f(x, y));
}
The output of the solution is still not exactly what the python output is, regardless it fixed this question in case anyone else ran across this issue.

Detecting slightly bright areas (fawn of deer) in thermal images

I am looking into detecting slightly bright areas (fawns from the roe deer) in thermal images with openCV.
So far I managed to get some code that works somehow, but with to many false negatives and false positives.
I basically know my way around openCV. But from the algorithmic side I a not sure what the best solution should be to result in a most perfect detection.
So far I use a cascade of something like this
gaussion blur
some sore of hysteresis thesholding
blob detection
Code snipped:
cv::GaussianBlur(gray, gray, cv::Size(gauss_size, gauss_size), 0);
Mat threshUpper, threshLower;
threshold(gray, threshUpper, mask_min, mask_max, cv::THRESH_BINARY);
threshold(gray, threshLower, mask_min-mask_thresh, mask_max, cv::THRESH_BINARY);
imshow("threshUpper", threshUpper);
imshow("threshLower", threshLower);
vector<vector<Point>> contoursUpper;
cv::findContours(threshUpper, contoursUpper, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE);
for(auto cnt : contoursUpper){
cv::floodFill(threshLower, cnt[0], 255, 0, 2, 2, cv::FLOODFILL_FIXED_RANGE);
}
threshold(threshLower, out, 200, 255, cv::THRESH_BINARY);
vector<vector<Point>> contours2clean;
cv::findContours(out, contours2clean, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_NONE);
for(const auto& cnt : contours2clean) {
double area = cv::contourArea(cnt);
if ( area > cut_max_size || area < cut_min_size) {
cv::floodFill(out, cnt[0], 0, 0, 2, 2, cv::FLOODFILL_FIXED_RANGE);
}
else {
cv::floodFill(out, cnt[0], 255, 0, 2, 2, cv::FLOODFILL_FIXED_RANGE);
}
}
std::vector<cv::KeyPoint> points;
detector_->detect(out, points);
cv::drawKeypoints(out, points, out, cv::Scalar(0, 0, 255), cv::DrawMatchesFlags::DRAW_RICH_KEYPOINTS);
I am looking for some advice for better approaches. Two images (raw and marked) are here:
Thanks!

Perfomance Issues while capturing and processing a video

I'm currently working on a project where I need to display a processed live video capture. Therefore, I'm using something similar to this:
cv::VideoCapture cap(0);
if (!cap.isOpened())
return -1;
cap.set(CV_CAP_PROP_FRAME_WIDTH, 1280);
cap.set(CV_CAP_PROP_FRAME_HEIGHT, 720);
cv::namedWindow("Current Capture");
for (;;)
{
cv::Mat frame;
cap >> frame;
cv::Mat mirrored;
cv::flip(frame, mirrored, 1);
cv::imshow("Current Capture", process_image(mirrored));
if (cv::waitKey(30) >= 0) break;
}
The problem I have is, that process_image, which perfomes a circle detection in the image, needs some time to finish and causes the displaying to be rather a slideshow then a video.
My Question is: How can I speed up the processing without manipulating the process_image function?
I thought about performing the image processing in another thread, but I'm not really sure how to start. Do you have any other idea than this?
PS.: I'm not expecting you to write code for me, I only need a point to start from ;)
EDIT:
Ok, if there is nothing i can do about the performance while capturing, I will need to change the process_image function.
cv::Mat process_image(cv::Mat img)
{
cv::Mat hsv;
cv::medianBlur(img, img, 7);
cv::cvtColor(img, hsv, cv::COLOR_BGR2HSV);
cv::Mat lower_hue_range; // lower and upper hue range in case of red color
cv::Mat upper_hue_range;
cv::inRange(hsv, cv::Scalar(LOWER_HUE1, 100, 100), cv::Scalar(UPPER_HUE1, 255, 255), lower_hue_range);
cv::inRange(hsv, cv::Scalar(LOWER_HUE2, 100, 100), cv::Scalar(UPPER_HUE1, 255, 255), upper_hue_range);
/// Combine the above two images
cv::Mat hue_image;
cv::addWeighted(lower_hue_range, 1.0, upper_hue_range, 1.0, 0.0, hue_image);
/// Reduce the noise so we avoid false circle detection
cv::GaussianBlur(hue_image, hue_image, cv::Size(13, 13), 2, 2);
/// store all found circles here
std::vector<cv::Vec3f> circles;
cv::HoughCircles(hue_image, circles, CV_HOUGH_GRADIENT, 1, hue_image.rows / 8, 100, 20, 0, 0);
for (size_t i = 0; i < circles.size(); i++)
{
/// circle center
cv::circle(hsv, cv::Point(circles[i][0], circles[i][1]), 3, cv::Scalar(0, 255, 0), -1, 8, 0);
/// circle outline
cv::circle(hsv, cv::Point(circles[i][0], circles[i][1]), circles[i][2], cv::Scalar(0, 0, 255), 3, 8, 0);
}
cv::Mat newI;
cv::cvtColor(hsv, newI, cv::COLOR_HSV2BGR);
return newI;
}
Is there a huge perfomance issue I can do anything about?
If you are sure that the process_image function is what is causing the bottle neck in your program, but you can't modify it, then there's not really a lot you can do. If that function takes longer to execute than the duration of a video frame then you will never get what you need.
How about reducing the quality of the video capture or reducing the size? At the moment I can see you have it set to 1280*720. If the process_image function has less data to work with it should execute faster.

opencv houghcircles differences c c++

I'm introducing myself in OpenCV (in order for an software project at university) and found a tutorial for color circle detection which I adapted and tested. It was written with OpenCV 1 in C. So I tried to convert it to OpenCv 2 classes API and everything was fine, but I ran into one problem:
The C function cvHoughCircles produces other results than the C++ function HoughCircles.
The C version finds my test circle and has a low rate of false positives, but the C++ version has a significantly higher mistake rate.
//My C implementation
IplImage *img = cvQueryFrame( capture );
CvSize size = cvGetSize(img);
IplImage *hsv = cvCreateImage(size, IPL_DEPTH_8U, 3);
cvCvtColor(img, hsv, CV_BGR2HSV);
CvMat *mask = cvCreateMat(size.height, size.width, CV_8UC1);
cvInRangeS(hsv, cvScalar(107, 61, 0, 0), cvScalar(134, 255, 255, 0), mask);
/* Copy mask into a grayscale image */
IplImage *hough_in = cvCreateImage(size, 8, 1);
cvCopy(mask, hough_in, NULL);
cvSmooth(hough_in, hough_in, CV_GAUSSIAN, 15, 15, 0, 0);
cvShowImage("mask",hough_in);
/* Run the Hough function */
CvMemStorage *storage = cvCreateMemStorage(0);
CvSeq *circles = cvHoughCircles(hough_in, storage, CV_HOUGH_GRADIENT,
4, size.height/4, 100, 40, 0, 0);
// ... iterating over all found circles
this works pretty well
//My C++ implementation
cv::Mat img;
cap.read(img);
cv::Size size(img.cols,img.rows);
cv::Mat hsv(size, IPL_DEPTH_8U, 3);
cv::cvtColor(img, hsv, CV_BGR2HSV);
cv::Mat mask(size.height, size.width, CV_8UC1);
cv::inRange(hsv, cv::Scalar(107, 61, 0, 0), cv::Scalar(134, 255, 255, 0), mask);
GaussianBlur( mask, mask, cv::Size(15, 15), 0, 0 );
/* Run the Hough function */
imshow("mask",mask);
vector<cv::Vec3f> circles;
cv::HoughCircles(mask, circles, CV_HOUGH_GRADIENT,
4, size.height/4, 100, 140, 0, 0);
// ... iterating over all found circles
As you can see, I use same arguments to all calls. I tested this with a webcam and a static sample object.One requirement is to use OpenCV2 C++ API.
Does anybody know, why I get so different results under equivalent conditions?
Edit
The different threshold values was just a mistake when I tested to make results more equally. These screenshots are taken with threshold set to 40 for both versions:
Screenshots: (Sorry, cannot yet post images)
C and C++ version
I see Hough parameters in C version as "..., 100, 40, 0, 0); " while in C++ version as "... 100, 140, 0, 0);" This difference in thresholds probably explains the difference in results.