【OpenCV】6th-识别球体

识别球体(圆)

// 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);

}

【问题】:不稳定,太近不准确。


opencv中cvCircle的使用方法

  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值