I'm using OpenCv to detect fingertips, but now I meet with some obstacles!
The findContours & convexHull & convexityDefects method doesn't work with my project.
It's my first time to ask a question. Thanks everybody!
My code is below:
int main()
{
CvScalar white = cvRealScalar(255);
CvScalar black = cvRealScalar(0);
CvSeq* contours = 0;
CvMemStorage* storage = cvCreateMemStorage(0);
IplImage* img = cvLoadImage("h.jpg");
IplImage* imgGray = cvCreateImage(cvGetSize(img), img->depth, 1);
IplImage* contoursImg = cvCreateImage(cvGetSize(img), img->depth, 1);
cvZero(contoursImg);
int nWidth = contoursImg->width;
int nHeight = contoursImg->height;
int nChannels = contoursImg->nChannels;
int nStep = contoursImg->widthStep;
for (int i=0; i<nHeight; i++)
for(int j=0; j<nWidth; j++)
contoursImg->imageData[i*nStep + j*nChannels] = 255 - contoursImg->imageData[i*nStep + j*nChannels];
cvCvtColor(img, imgGray, CV_BGR2GRAY);
cvThreshold(imgGray, imgGray, 230, 255, CV_THRESH_BINARY);
cvSmooth(imgGray, imgGray);
cvFindContours(imgGray, storage, &contours, sizeof(CvContour), CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0));
contours = cvApproxPoly(contours, sizeof(CvContour), storage, CV_POLY_APPROX_DP, 35, 1);
cvDrawContours(contoursImg, contours, CV_RGB(0, 0, 0), CV_RGB(0, 0, 0), 1, 1, 8, cvPoint(0, 0));
CvSeq* hull = cvConvexHull2(contours, 0, CV_CLOCKWISE, 0);
CvSeq* defect = cvConvexityDefects(contours, hull, NULL);
for(; defect; defect = defect->h_next)
{
int nomdef = defect->total;
if(!nomdef)
continue;
CvConvexityDefect* defectArray = (CvConvexityDefect*)malloc(sizeof(CvConvexityDefect)*nomdef);
cvCvtSeqToArray(defect, defectArray, CV_WHOLE_SEQ);
for(int i = 0; i < nomdef; i++)
{
cvCircle(contoursImg, *(defectArray[i].end), 5, CV_RGB(255, 0, 0), -1, 8, 0);
cvCircle(contoursImg, *(defectArray[i].start), 5, CV_RGB(0, 255, 0), -1, 8, 0);
cvCircle(contoursImg, *(defectArray[i].depth_point), 5, CV_RGB(0, 0, 255), -1, 8, 0);
}
free(defectArray);
}
cvNamedWindow("image", 1);
cvShowImage("image", contoursImg);
cvWaitKey(0);
cvReleaseMemStorage(&storage);
cvReleaseImage(&img);
cvReleaseImage(&imgGray);
cvReleaseImage(&contoursImg);
cvDestroyWindow("image");
return 0;
}
This is my hand picture:
http://www.billwang.net/bbs/oldattach/2006/12/29/billwang_5315954-038-embed.jpg
The methods are working fine. You have one rectangular contour detected on the outside of the image. As this covers the entire image, there are no defects and so, none detected. See attached image.
Related
I have error on absdiff(grayImg, bgImg, diffImg);
and I don't understand why this is wrong.
VideoCapture capture;
capture.open(0);
if (!capture.isOpened()) {
printf("error\n");
return -1;
}
Mat grayImg;
Mat diffImg;
Mat bgImg = imread("BgImg.jpg");
Mat frame;
std::vector<std::vector<cv::Point> > contours;
for (;;) {
capture >> frame;
cvtColor(frame, grayImg, CV_RGB2GRAY);
absdiff(grayImg, bgImg, diffImg);
threshold(diffImg, diffImg, 50, 255, CV_THRESH_BINARY);
findContours(diffImg, contours, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE);
drawContours(frame, contours, -1, CV_RGB(255, 0, 0), 1, 8);
imshow("capture", frame);
imshow("diffImg", diffImg);
char chKey = waitKey(10);
if (chKey == 27) break;
}
destroyAllWindows();
return 0;
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));
}
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
}
I have an image with detected circles and am trying to read value of these circles in HSV format. I can get the BGR values but not HSv. is there any way to convert bgr to hsv after getting bgr value or what?
source code below
#include <stdio.h>
#include <cv.h>
#include <highgui.h>
#include <math.h>
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 c;
//if(center.x > 0 && center.x < 1280 && center.y > 0 && center.y < 720)
//{
//c = cvGet2D(img,center.x, center.y);//colour of circle
//}
// 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;
}
OpenCV comes with a utility function to convert between colorspaces called cvCvtColor().
I have detected 22 balls and am struggling to find a way to run a color detection algorithm on these circles to get their colors. I am using HoughCircles to detect the circles but don't know how to check what color these circles are?
Source Code:
#include <stdio.h>
#include <cv.h>
#include <highgui.h>
#include <math.h>
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]);
cvScalar c = cvGet2D(center.x, center.y);//colour of circle
// 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", rgbcanny);
cvWaitKey(0);
return 0;
}
If the balls each have a uniform color, you can check the color at the center:
CvMemStorage* storage = cvCreateMemStorage(0);
cvSmooth(image, image, CV_GAUSSIAN, 5, 5 );
CvSeq* results = cvHoughCircles(
image,
storage,
CV_HOUGH_GRADIENT,
2,
image->width/10
);
for( int i = 0; i < results->total; i++ )
{
float* p = (float*) cvGetSeqElem( results, i );
CvPoint center = cvPoint( cvRound( p[0] ), cvRound( p[1] ) );
CvScalar c = cvGet2D(image, center.x, center.y); //color of the center
}
Haven't tested the code but it should be ok.
EDIT:
Ooops, I forgot one parameter from the Get2D method, the actual image from which to get the color. Changed to the correct form.
We have written our own blob detection library in the open source vision framework:
http://www.simplecv.org
The code to do what you want is as easy as:
img = Image("/path/to/image.png")
blobs = img.findBlobs()
circle_blobs = blobs.filter(blobs.isCircle() == True)
list_of_blobs_colors = circle_blobs.meanColor()