labeling the connected component in an image in opencv - opencv

I have written a piece of code that finds the connected components and labels the connected components with letter 'R' using cvPutText. Now instead of Letter'R' i need to print the numbers like 1,2,3,....etc according the no.of connected components. After that i need to find area and print the area of connected components as a text. Can anyone help me with this?
Here is my code:
imagelab=cvCreateImage(cvGetSize(mor),IPL_DEPTH_8U,3);
CvMemStorage* contour_storage = cvCreateMemStorage(0);
CvSeq* contours;
CvFont font;
cvInitFont(&font, CV_FONT_HERSHEY_SIMPLEX, 0.6f, 0.6f, 0, 2);
cvFindContours(mor, contour_storage, &contours, sizeof (CvContour), CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE,cvPoint(0,0));
cvZero(imagelab);
for( ; contours != NULL; contours = contours->h_next )
{
CvScalar color = CV_RGB( rand()&255, rand()&255, rand()&255 );
cvDrawContours( imagelab, contours, color, CV_RGB(255,255,255), -1, CV_FILLED, 8 ,cvPoint(0,0));
CvRect iconBox = cvBoundingRect(contours, 0);
CvPoint center = cvPoint(iconBox.x + (iconBox.width / 2), iconBox.y + (iconBox.height / 2));
int area = abs(cvContourArea(contours, CV_WHOLE_SEQ));
cvPutText(imagelab,"R", center, &font, CV_RGB(255, 255, 255));
}
Thanx.

There are many way's to do that what you need is to convert an integer to a string. Just use a counter. My favorit is using stringstreams
for(int ncount = 0 ; contours != NULL; contours = contours->h_next, ncount++ )
...
std::stringstream str;
str << ncount;
cvPutText(imagelab,str.str(), center, &font, CV_RGB(255, 255, 255));

Related

object detection of various shapes in opencv

I have an image and want to detect various objects at a time using opencv methods.
I have tried detecting one object using contouring and using the area to filter other counters. But I need to detect other objects too but they vary in area and length.
Can anyone help me to use any methods for detecting it.
This is the original image:
this is the code that I have tried for detection:
int main()
{
Mat msrc = imread("Task6_Resources/Scratch.jpg", 1);
Mat src = imread("Task6_Resources/Scratch.jpg", 0);
Mat imgblur;
GaussianBlur(src, imgblur, Size(13,13), 0);
cv::Ptr<cv::CLAHE> clahe = cv::createCLAHE();
clahe->setClipLimit(8);
cv::Mat gcimg;
clahe->apply(imgblur, gcimg);
Mat thresh;
threshold(gcimg, thresh, 55, 255, THRESH_BINARY_INV);
Mat th_mina = minareafilter(thresh, 195); //function used to filter small and large blobs
Mat th_maxa = maxareafilter(th_mina, 393);
Mat imdilate;
dilate(th_maxa, imdilate, getStructuringElement(MORPH_RECT, Size(3, 1)), Point(-1, -1), 7);
int largest_area = 0;
int largest_contour_index = 0;
Rect bounding_rect;
vector<vector<Point>> contours;
vector<Vec4i> hierarchy;
findContours(imdilate, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE);
cout << "Number of contours" << contours.size() << endl;
//Largest contour according to area
for (int i = 0; i < contours.size(); i++){
double a = contourArea(contours[i], false);
if (a > largest_area) {
largest_area = a;
largest_contour_index = i;
bounding_rect = boundingRect(contours[i]);
}
}
for (int c = 0; c < contours.size(); c++){
printf(" * Contour[%d] Area OpenCV: %.2f - Length: %.2f \n",
c,contourArea(contours[c]), arcLength(contours[c], true));
}
rectangle(msrc, bounding_rect, Scalar(0, 255, 0), 2, 8, 0);
imshow("largest contour", msrc);
waitKey(0);
destroyAllWindows();
return 0;
}
This is the image on which I am applying contouring
After the code I am able to detect the green box using largest area in contouring, but I need to detect those red boxes too. (only the region of red boxes)
The problem is here I cannot apply again area parameter to filter the contours as some other contours have same area as the resultant contour.
The image result required:

Opencv app crashes when using external camera

was using contours for object identification. The code worked well with images and I modified the code to identify objects in real time with camera input. Things work well with my laptop's integrated cam but crashes after a few seconds when using an external camera. The external camera worked fine with a few other applications I developed using opencv. The camera is a 20MP camera. Please look at the code and help me figure out what might be wrong. My processor is good enough to handle images with high resolutions. It seems that the app crashes when I introduce an object in front of the cam which was not there before when the app started up.
include <iostream>
include "opencv2/highgui/highgui.hpp"
include "opencv2/imgproc/imgproc.hpp"
using namespace cv; using namespace std;
int main()
{
int largest_area = 0;
int largest_contour_index = 0;
Rect bounding_rect;
int x = 0;
int y = 0;
VideoCapture xps(0);
Mat src;
while (1)
{
xps.read(src);
vector<vector<Point>> contours; // Vector for storing contour
vector<Vec4i> hierarchy;
Mat thr(src.rows, src.cols, CV_8UC1);
Mat dst(src.rows, src.cols, CV_8UC1, Scalar::all(0));
cvtColor(src, thr, CV_BGR2GRAY); //Convert to gray
threshold(thr, thr, 80, 255, THRESH_BINARY_INV);
findContours(thr, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE);
for (int i = 0; i< contours.size(); i++) // iterate through each contour.
{
double a = contourArea(contours[i], false); // Find the area of contour
if (a>largest_area)
{
largest_area = a;
largest_contour_index = i;
bounding_rect = boundingRect(contours[i]);
}
}
Scalar color(255, 255, 255);
drawContours(dst, contours, largest_contour_index, color, CV_FILLED, 8, hierarchy);
rectangle(src, bounding_rect, Scalar(0, 255, 0), 1, 8, 0);
x = bounding_rect.x + bounding_rect.width / 2;
y = bounding_rect.y + bounding_rect.height / 2;
circle(src, Point(x, y), 1, Scalar(0, 0, 255));
imshow("src", src);
imshow("largest Contour", dst);
waitKey(2);
}
}
I believe the crashes are due the contours which might not be found. To avoid this problem, use a flag and if the contours are found, then draw them.
bool found = findContours(thr, contours, hierarchy, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE);
/* for loop */
if(found)
{
drawContours(dst, contours, largest_contour_index, color, CV_FILLED, 8, hierarchy);
rectangle(src, bounding_rect, Scalar(0, 255, 0), 1, 8, 0);
x = bounding_rect.x + bounding_rect.width / 2;
y = bounding_rect.y + bounding_rect.height / 2;
circle(src, Point(x, y), 1, Scalar(0, 0, 255));
}

OpenCV: Retrieving color of the center of a contour

Im trying to detect the colour of a set of shapes in a black image using OpenCV, for which I use Canny detection. However the color output always comes back as black.
std::vector<std::pair<cv::Point, cv::Vec3b> > Asteroids::DetectPoints(const cv::Mat &image)
{
cv::Mat imageGray;
cv::cvtColor( image, imageGray, CV_BGR2GRAY );
cv::threshold(imageGray, imageGray, 1, 255, cv::THRESH_BINARY);
cv::Mat canny_output;
std::vector<std::vector<cv::Point> > contours;
std::vector<cv::Vec4i> hierarchy;
int thresh = 10;
// Detect edges using canny
cv::Canny( imageGray, canny_output, thresh, thresh*2, 3 );
// Find contours
cv::findContours( canny_output, contours, hierarchy, CV_RETR_LIST, CV_CHAIN_APPROX_NONE, cv::Point(0, 0) );
std::vector<std::pair<cv::Point, cv::Vec3b> > points;
for(unsigned int i = 0; i < contours.size(); i++ )
{
cv::Rect rect = cv::boundingRect(contours[i]);
std::pair<cv::Point, cv::Vec3b> posColor;
posColor.first = cv::Point( rect.tl().x + (rect.size().width / 2), rect.tl().y + (rect.size().height / 2));
posColor.second = image.at<cv::Vec3b>( posColor.first.x, posColor.first.y );
//Dont add teh entry to the list if one with the same color and position is already pressent,
//The contour detection sometimes returns duplicates
bool isInList = false;
for(unsigned int j = 0; j < points.size(); j++)
if(points[j].first == posColor.first && points[j].second == posColor.second)
isInList = true;
if(!isInList)
points.push_back( posColor );
}
return points;
}
I know it has to be an issue with the positions or something along those lines, but I cant figure out what
I might be wrong, but off the top of my head :
Shouldn't this read
posColor.second = image.at<cv::Vec3b>(posColor.first.y, posColor.first.x);
and not the other way around like you did it ?
Matrix notation, not cartesian notation ?

Using cvFindContour with cvMinAreaRect2

I succeeded in using cvDrawContour but when I try to use cvMinRectArea2, it only shows one dot. Any ideas? Here's the source code.
IplImage *src = cvLoadImage("SignImg.jpg",0);
IplImage *dst_img = 0;
IplImage *img = cvCreateImage(cvGetSize(src),8,3);
CvBox2D rect;
CvMemStorage *storage = cvCreateMemStorage ();
CvSeq *contours = 0;
char a[255];
sprintf(&a[0],"%s",openFileDialog1->FileName);
dst_img = cvLoadImage(a,0);
cvFindContours (src, storage, &contours, sizeof(CvContour), CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE ,cvPoint(0,0));
cvCvtColor(dst_img,img,CV_GRAY2BGR);
cvDrawContours (img, contours, CV_RGB(255,0,0), cvScalarAll(255),1,1,8,cvPoint(0,0));
rect=cvMinAreaRect2 (contours,0);
cvEllipseBox(img,rect,cvScalarAll(0),5,8,0);
The right way to use cvDrawContours is shown here:
for( ; contour != 0; contour = contour->h_next )
{
CvScalar color = CV_RGB( rand()&255, rand()&255, rand()&255 );
/* replace CV_FILLED with 1 to see the outlines */
cvDrawContours( dst, contour, color, color, -1, CV_FILLED, 8 );
}
If it's not obvious enough, your variable contours is an array and you need to iterate over it and draw each element! Else you will be drawing only the first element of the array.

Read HSV value of pixel in opencv

how would you go about reading the pixel value in HSV format rather than RGB? The code below reads the pixel value of the circles' centers in RGB format. Is there much difference when it comes to reading value in HSV?
int main(int argc, char** argv)
{
//load image from directory
IplImage* img = cvLoadImage("C:\\Users\\Nathan\\Desktop\\SnookerPic.png");
IplImage* gray = cvCreateImage(cvGetSize(img), IPL_DEPTH_8U, 1);
CvMemStorage* storage = cvCreateMemStorage(0);
//covert to grayscale
cvCvtColor(img, gray, CV_BGR2GRAY);
// This is done so as to prevent a lot of false circles from being detected
cvSmooth(gray, gray, CV_GAUSSIAN, 7, 7);
IplImage* canny = cvCreateImage(cvGetSize(img),IPL_DEPTH_8U,1);
IplImage* rgbcanny = cvCreateImage(cvGetSize(img),IPL_DEPTH_8U,3);
cvCanny(gray, canny, 50, 100, 3);
//detect circles
CvSeq* circles = cvHoughCircles(gray, storage, CV_HOUGH_GRADIENT, 1, 35.0, 75, 60,0,0);
cvCvtColor(canny, rgbcanny, CV_GRAY2BGR);
//draw all detected circles
for (int i = 0; i < circles->total; i++)
{
// round the floats to an int
float* p = (float*)cvGetSeqElem(circles, i);
cv::Point center(cvRound(p[0]), cvRound(p[1]));
int radius = cvRound(p[2]);
//uchar* ptr;
//ptr = cvPtr2D(img, center.y, center.x, NULL);
//printf("B: %d G: %d R: %d\n", ptr[0],ptr[1],ptr[2]);
CvScalar s;
s = cvGet2D(img,center.y, center.x);//colour of circle
printf("B: %f G: %f R: %f\n",s.val[0],s.val[1],s.val[2]);
// draw the circle center
cvCircle(img, center, 3, CV_RGB(0,255,0), -1, 8, 0 );
// draw the circle outline
cvCircle(img, center, radius+1, CV_RGB(0,0,255), 2, 8, 0 );
//display coordinates
printf("x: %d y: %d r: %d\n",center.x,center.y, radius);
}
//create window
//cvNamedWindow("circles", 1);
cvNamedWindow("SnookerImage", 1);
//show image in window
//cvShowImage("circles", rgbcanny);
cvShowImage("SnookerImage", img);
cvSaveImage("out.png", img);
//cvDestroyWindow("SnookerImage");
//cvDestroyWindow("circles");
//cvReleaseMemStorage("storage");
cvWaitKey(0);
return 0;
}
If you use the C++ interface, you can use
cv::cvtColor(img, img, CV_BGR2HSV);
See the documentation for cvtColor for more information.
Update:
Reading and writing pixels the slow way (assuming that the HSV values are stored as a cv::Vec3b (doc))
cv::Vec3b pixel = image.at<cv::Vec3b>(0,0); // read pixel (0,0) (make copy)
pixel[0] = 0; // H
pixel[1] = 0; // S
pixel[2] = 0; // V
image.at<cv::Vec3b>(0,0) = pixel; // write pixel (0,0) (copy pixel back to image)
Using the image.at<...>(x, y) (doc, scroll down a lot) notation is quite slow, if you want to manipulate every pixel. There is an article in the documentation on how to access the pixels faster. You can apply the iterator method also like this:
cv::MatIterator_<cv::Vec3b> it = image.begin<cv::Vec3b>(),
it_end = image.end<cv::Vec3b>();
for(; it != it_end; ++it)
{
// work with pixel in here, e.g.:
cv::Vec3b& pixel = *it; // reference to pixel in image
pixel[0] = 0; // changes pixel in image
}

Resources