识别球体(圆)
// StreamMatchPicture.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <assert.h>
#include <float.h>
#include <limits.h>
#include <ctype.h>
#include <opencv/cv.h>
#include <opencv/cxcore.h>
#include <opencv/highgui.h>
#include <atlstr.h>
#include "opencv2/core/core.hpp"
#include "opencv2/features2d/features2d.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/nonfree/features2d.hpp"
#define nPixelValues 100 //检测黑白边界点像素差阈值
#define nInnerPixelValue 30 //检测球心周围点像素差阈值
using namespace cv;
using namespace std;
static CvMemStorage* storage = 0;
static int nFeaturePointx = 0;//顶点x坐标
static int nFeaturePointy = 0;//顶点y坐标
static int nBottomFeaturePointy = 0;//底部端点y坐标
static bool bFeatureTopPoint = false;//球体顶点,底部端点匹配成功
void VideoFrameDrawCircle(IplImage* pFrame, IplImage* imgSrc);
void SearchForBottomPoint(IplImage* pFrame, IplImage* pBkImg, int nHeight, int nWidth, bool bFeatureBottomPoint);
int main(int argc, char** argv)
{
IplImage* pFrame = NULL;
IplImage* pBkImg = NULL;
CvMat* pBkMat = NULL;
CvCapture* pCapture = NULL;
int nFrmNum = 0;
if (!(pCapture = cvCaptureFromCAM(0)))//通过摄像头获取视频
{
fprintf(stderr, "Can not open camera.\n");
return -1;
}
storage = cvCreateMemStorage(0);//创建一个内存存储器
Sleep(1000);//打开摄像头之后需要等待1s
for (;;)
{
pFrame = cvQueryFrame(pCapture);//获取帧图片
if (!pFrame)
{
CString str;
str.Format(_T("lost the frams %d\n"), nFrmNum);
OutputDebugString(str);
break;
}
pFrame->origin = 1;
nFrmNum++;
if (nFrmNum == 1)
{
pBkImg = cvCreateImage(cvSize(pFrame->width, pFrame->height), IPL_DEPTH_8U, 1);
pBkImg->origin = 1;
// //转换成单通道图像
cvCvtColor(pFrame, pBkImg, CV_BGR2GRAY);
}
else
{
cvCvtColor(pFrame, pBkImg, CV_BGR2GRAY);
cvSmooth(pBkImg, pBkImg, CV_MEDIAN, 3, 0, 0, 0);//中值滤波
CString strFrame;
strFrame.Format(_T("Begin frames:%d\n"), nFrmNum);
OutputDebugString(strFrame);
Mat FrameMat(pBkImg);
imshow("Frame", FrameMat);
VideoFrameDrawCircle(pFrame, pBkImg);
strFrame.Format(_T("End the frams %d\n"), nFrmNum);
OutputDebugString(strFrame);
if (cvWaitKey(10) >= 0)
break;
}
if (cvWaitKey(1) == 27)//check out never use ese key
break;
}
cvReleaseImage(&pBkImg);
cvReleaseImage(&pFrame);
cvReleaseCapture(&pCapture);
return 0;
}
//检测视频中的球体
void VideoFrameDrawCircle(IplImage* pFrame, IplImage* pBkImg)
{
Mat firstFrame(pBkImg);
if (!firstFrame.data)
{
std::cout << "Error reading the image!" << endl;
return;
}
Mat lastFrame(pFrame);
if (!lastFrame.data)
{
std::cout << "Error reading last frame!" << endl;
return;
}
cvClearMemStorage(storage);
int nWidth = pBkImg->width;
int nHeight = pBkImg->height;
nFeaturePointx = 0;
nFeaturePointy = 0;
nBottomFeaturePointy = 0;
double R1 = 0.000000, G1 = 0.000000, B1 = 0.000000;
double R2 = 0.000000, G2 = 0.000000, B2 = 0.000000;
double R3 = 0.000000, G3 = 0.000000, B3 = 0.000000;
bFeatureTopPoint = false;
bool bFeatureBottomPoint = false;//bool:find bottom featurepoint
for (int i = 0; i<nHeight; i++)//检测圆形的顶点坐标位置
{
if (bFeatureTopPoint)
break;
if (i + 1 <nHeight)
{
for (int j = 0; j<nWidth; j++)
{
if (bFeatureTopPoint)
break;
CvScalar s = cvGet2D(pFrame, i, j);// loop first point pixel value p(j,i)
R1 = s.val[2];
G1 = s.val[1];
B1 = s.val[0];
if (j + 1<nWidth - 1)
{
CvScalar s2 = cvGet2D(pFrame, i + 1, j);//get loop next point pixel value p(j,i+1)
R2 = s2.val[2];
G2 = s2.val[1];
B2 = s2.val[0];
if (/*fabs*/(R2 - R1)> nPixelValues && /*fabs*/(G2 - G1)>nPixelValues && /*fabs*/(B2 - B1)>nPixelValues)
{
//处理球体是否和顶部边界相交的情况
CvScalar s3 = cvGet2D(pFrame, i, j + 1);
R3 = s3.val[2];
G3 = s3.val[1];
B3 = s3.val[0];
if (fabs(R3 - R2)> nPixelValues && fabs(G3 - G2)>nPixelValues && fabs(B3 - B2)>nPixelValues)
{
cout << "circle is intersect with the top line" << std::endl;
continue;
}
nFeaturePointx = j;
nFeaturePointy = i + 1;
SearchForBottomPoint(pFrame, pBkImg, nHeight, nWidth, false);//检测球体的底部顶点,左右边界顶点:画球体投影轮廓
}
else
{
continue;
}
}
else
{
break;//宽度越界
}
}
}
else
{
break;//高度越界
}
}
}
void SearchForBottomPoint(IplImage* pFrame, IplImage* pBkImg, int nHeight, int nWidth, bool bFeatureBottomPoint = false)//画球体轮廓:检测球底部顶点
{
double R1 = 0.000000, G1 = 0.000000, B1 = 0.000000;
double R2 = 0.000000, G2 = 0.000000, B2 = 0.000000;
int nstep = 20;
int nBottomPointy = nFeaturePointy + 2;
if (nBottomPointy >= nHeight - 1)
nBottomPointy = nHeight - 2;
bool bExist = false;
CvScalar s = cvGet2D(pFrame, nBottomPointy, nFeaturePointx);
R1 = s.val[2];
G1 = s.val[1];
B1 = s.val[0];
for (;;)
{
if (bFeatureBottomPoint)//success for searching the last bottom feature point
break;
for (int k = nBottomPointy; k<nHeight - 2; k += nstep)
{
if (k + 1<nHeight - 2)
{
CvScalar s2 = cvGet2D(pFrame, k + 1, nFeaturePointx);
R2 = s2.val[2];
G2 = s2.val[1];
B2 = s2.val[0];
if (fabs(R2 - R1)> nPixelValues && fabs(G2 - G1)>nPixelValues && fabs(B2 - B1)>nPixelValues)
{
if (nstep == 1)//最后一遍遍历:遍历递增单位值为1个像素
{
bFeatureBottomPoint = true;
nBottomFeaturePointy = k;//底部特征点的y坐标值
}
else//否则,缩小递归变量单位值,循环初始值为上一次最后y坐标值
{
nBottomPointy = (k - nstep);//退回上次循环点位置
if (nBottomPointy<0)
nBottomPointy = 0;
nstep = (int)nstep / 2;//缩小递归单位量
}
bExist = true;//遍历一边,存在特征点
break;
}
}
else//图像高度越界:
{
if (nstep == 1)//球的底部顶点正好与图像的下方边界相切
{
bFeatureBottomPoint = true;
nBottomFeaturePointy = nHeight - 1;
}
else if (bExist && nstep == 2)
{
bFeatureBottomPoint = true;
nBottomFeaturePointy = nHeight - 2;
}
break;
}
}
if (!bExist)//确定了顶部特征点的情况下,如果一轮下来没有区别的像素值发现:则终点是底部点
{
bFeatureBottomPoint = true;//直接退出
break;//如果球体与底边相交,直接退出
}
}
//draw circle
int pointy = (int)((nFeaturePointy + nBottomFeaturePointy) / 2);
int radius = (int)((nBottomFeaturePointy - nFeaturePointy) / 2);
cvZero(pBkImg);
if (radius < 0)
return;
if (nFeaturePointx <radius + 2)//如果球体与边界左右相交,不做处理,退出
return;
if (nFeaturePointx + radius + 2>(nWidth - 2))
return;
bFeatureTopPoint = true;//顶点和底部端点匹配成功,符合球体规则
cvCircle(pBkImg, cvPoint(nFeaturePointx, pointy), radius, CV_RGB(0, 255, 255), 1, 8, 0);//画圆
CString str1;
str1.Format(_T("circle point(%d,%d) radius = %d successful \n"), nFeaturePointx, pointy, radius);
OutputDebugString(str1);
cvFlip(pBkImg, NULL, 0);
cvShowImage("circle", pBkImg);
}
【问题】:不稳定,太近不准确。