轮廓处理之二

目前,使用opencv的目标是跟踪一个规则物体(比如圆形的药片),需要得到它的位置,以及移动的速度等。有前面得到的轮廓,我下面需要解决的是 它的重心位置以及半径。轮廓的矩提供了我需要的基本参数。

轮廓的长度(曲线长度或闭合曲线周长)求取

double cvArcLength(const void* curve, CvSlice slice=CV_WHOLE_SEQ, int isClosed=-1 )

轮廓的矩

void cvMoments(const CvArr* array, CvMoments* moments, int binary=0 )

array 图像 (1-通道或3-通道,有COI设置) 或多边形(点的 CvSeq 或一族点的向量).

moments 返回的矩状态接口的指针

binary (仅对图像) 如果标识为非零,则所有零象素点被当成零,其它的被看成 1.

函数 cvMoments 计算最高达三阶的空间和中心矩,并且将结果存在结构 moments 中。矩用来计算形状的重心,面积,主轴和其它的形状特征

用cvMoments函数时有一个参数是CvMoments * 结构,但是需要对这个结构初始化,也就是申请内存,用moment = (CvMoments*)malloc( sizeof(CvMoments).

 

在尝试上述目标时,发现有时得到的轮廓并非我想要的轮廓,立刻着手研究这问题,发现了mode变量: CV_RETR_ExTERNAL, CV_RETR_LIST, CV_RETR_CCOMP或CV_RETR_TREE.mode的值影响向cvFindeContours()。详见技术蛀虫的文章:http://www.cnblogs.com/nktblog/p/4027137.html。本文有两图来至于这片文章

 

以下程序描述了面积以及周长的求法(存在误差), 参考了morewindows的程序代码,做了调整,尝试去了解cvFindContours函数。

 

//图像的轮廓检测上
//By pengjc2001 (http://blog.csdn.net/pengjc2001)
#include <opencv2/opencv.hpp>
#include <stdlib.h>
#include "cxcore.h"  
#include "cv.h"  
#include "highgui.h"

double area = 0;
double perimeter = 0;


int main(int argc, char** argv)
{
 const char *pstrWindowsSrcTitle = "原图(http://blog.csdn.net/pengjc2001)";
 const char *pstrWindowsOutLineTitle = "轮廓图(http://blog.csdn.net/pengjc2001)";
 const char *pstrWindowsBinaryTitle = "Binary(http://blog.csdn.net/pengjc2001)";
 const char *pstrWindowsGrayTitle = "Gray(http://blog.csdn.net/pengjc2001)";

 const int IMAGE_WIDTH = 400;
 const int IMAGE_HEIGHT = 200;
 printf("\IMAGE height : %d\n\tvideo width : %d\n", IMAGE_WIDTH, IMAGE_HEIGHT);


 // 创建图像
 IplImage *pSrcImage = cvCreateImage(cvSize(IMAGE_WIDTH, IMAGE_HEIGHT), IPL_DEPTH_8U, 3);
 // 填充成白色
 cvRectangle(pSrcImage, cvPoint(0, 0), cvPoint(pSrcImage->width, pSrcImage->height), CV_RGB(255, 255, 255), CV_FILLED);
 float S = (float)IMAGE_WIDTH*(float)IMAGE_HEIGHT;
 float P = 2 * ((float)IMAGE_WIDTH + (float)IMAGE_HEIGHT);
 printf("c0_Rectangle area:%f, perimeter:%f\n",S,P);
 // 画圆
 CvPoint ptCircleCenter = cvPoint(IMAGE_WIDTH / 4, IMAGE_HEIGHT / 2);
 int nRadius = 80;
 cvCircle(pSrcImage, ptCircleCenter, nRadius, CV_RGB(255, 255, 0), CV_FILLED);
 S = 3.14*nRadius*nRadius;
 P = 2 * 3.14*nRadius;
 printf("h00_Circle1 area:%f, perimeter:%f\n", S, P);
 ptCircleCenter = cvPoint(IMAGE_WIDTH / 4, IMAGE_HEIGHT / 2);
    nRadius = 30;
 cvCircle(pSrcImage, ptCircleCenter, nRadius, CV_RGB(255, 255, 255), CV_FILLED);
 S = 3.14*nRadius*nRadius;
 P = 2 * 3.14*nRadius;
 printf("c000_Circle2 area:%f, perimeter:%f\n", S, P);

 // 画矩形
 CvPoint ptLeftTop = cvPoint(IMAGE_WIDTH / 2 + 40, 40);
 CvPoint ptRightBottom = cvPoint(IMAGE_WIDTH - 40, IMAGE_HEIGHT - 40);
 cvRectangle(pSrcImage, ptLeftTop, ptRightBottom, CV_RGB(0, 255, 255), CV_FILLED);
 // 画圆
 S = 120*120;
 P = 2 * (120 + 120);
 printf("h01_Rectangle area:%f, perimeter:%f\n", S, P);

 ptCircleCenter = cvPoint(IMAGE_WIDTH * 3 / 4-20, IMAGE_HEIGHT / 2);
 nRadius = 15;
 cvCircle(pSrcImage, ptCircleCenter, nRadius, CV_RGB(255, 255, 255), CV_FILLED);
 S = 3.14*nRadius*nRadius;
 P = 2 * 3.14*nRadius;
 printf("c010_Circle2 area:%f, perimeter:%f\n", S, P);

 ptCircleCenter = cvPoint(IMAGE_WIDTH * 3 / 4 + 20, IMAGE_HEIGHT / 2);
 nRadius = 10;
 cvCircle(pSrcImage, ptCircleCenter, nRadius, CV_RGB(255, 255, 255), CV_FILLED);
 S = 3.14*nRadius*nRadius;
 P = 2 * 3.14*nRadius;
 printf("c011_Circle2 area:%f, perimeter:%f\n", S, P);

 // 显示原图
 cvNamedWindow(pstrWindowsSrcTitle, CV_WINDOW_AUTOSIZE);
 cvShowImage(pstrWindowsSrcTitle, pSrcImage);

 // 转为灰度图
 IplImage *pGrayImage = cvCreateImage(cvGetSize(pSrcImage), IPL_DEPTH_8U, 1);
 cvCvtColor(pSrcImage, pGrayImage, CV_BGR2GRAY);
 cvNamedWindow(pstrWindowsGrayTitle, CV_WINDOW_AUTOSIZE);
 cvShowImage(pstrWindowsGrayTitle, pGrayImage);

 // 转为二值图
 IplImage *pBinaryImage = cvCreateImage(cvGetSize(pGrayImage), IPL_DEPTH_8U, 1);
 cvThreshold(pGrayImage, pBinaryImage, 250, 255, CV_THRESH_BINARY);

 cvNamedWindow(pstrWindowsBinaryTitle, CV_WINDOW_AUTOSIZE);
 cvShowImage(pstrWindowsBinaryTitle, pBinaryImage);


 // 检索轮廓并返回检测到的轮廓的个数
 CvMemStorage *pcvMStorage = cvCreateMemStorage();
 CvSeq *pcvSeq = NULL;
 cvFindContours(pBinaryImage, pcvMStorage, &pcvSeq, sizeof(CvContour), CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE, cvPoint(0, 0));

 
 // 画轮廓图
 IplImage *pOutlineImage = cvCreateImage(cvGetSize(pSrcImage), IPL_DEPTH_8U, 3);
 int nLevels = 3;
 // 填充成白色
 cvRectangle(pOutlineImage, cvPoint(0, 0), cvPoint(pOutlineImage->width, pOutlineImage->height), CV_RGB(255, 255, 255), CV_FILLED);
 cvDrawContours(pOutlineImage, pcvSeq, CV_RGB(255, 0, 0), CV_RGB(0, 0, 0), nLevels, 1);
 // 显示轮廓图
 cvNamedWindow(pstrWindowsOutLineTitle, CV_WINDOW_AUTOSIZE);
 cvShowImage(pstrWindowsOutLineTitle, pOutlineImage);

 CvSeq *pcvSeqInner = NULL;
 int inner = 0;
 int external = 0;
 area = cvContourArea(pcvSeq);
 perimeter = cvArcLength(pcvSeq);

 
 for (; pcvSeq != NULL; pcvSeq = pcvSeq->h_next)
 {
  external++;
  area = cvContourArea(pcvSeq);
  perimeter = cvArcLength(pcvSeq);

  CvMoments *moments = (CvMoments*)malloc(sizeof(CvMoments));
  cvMoments(pcvSeq, moments, 1);
  double moment10 = cvGetSpatialMoment(moments, 1, 0);
  double moment01 = cvGetSpatialMoment(moments, 0, 1);
  area = cvGetCentralMoment(moments, 0, 0);
  printf("area:%f\t perimeter:%f\n", area,perimeter );
  printf("external:%d\t inner = %d\t h_next\n", external, inner);
  for (pcvSeqInner = pcvSeq->v_next; pcvSeqInner != NULL; pcvSeqInner = pcvSeqInner->h_next)
  {
   inner++;
   double area = cvContourArea(pcvSeqInner);
   double perimeter = cvArcLength(pcvSeqInner);

   CvMoments *moments = (CvMoments*)malloc(sizeof(CvMoments));
   cvMoments(pcvSeqInner, moments, 1);
   double moment10 = cvGetSpatialMoment(moments, 1, 0);
   double moment01 = cvGetSpatialMoment(moments, 0, 1);
   area = cvGetCentralMoment(moments, 0, 0);
   printf("area:%f\t perimeter:%f\n", area,perimeter );
   printf("external:%d\t inner = %d\t \n", external, inner);

  }
  
 }

 

 cvWaitKey(0);

 cvReleaseMemStorage(&pcvMStorage);

 cvDestroyWindow(pstrWindowsSrcTitle);
 cvDestroyWindow(pstrWindowsOutLineTitle);
 cvReleaseImage(&pSrcImage);
 cvReleaseImage(&pGrayImage);
 cvReleaseImage(&pBinaryImage);
 cvReleaseImage(&pOutlineImage);
 return 0;

}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值