【原創】 opencv 實現特定形狀視頻跟蹤,圖像裁剪
Author: chad
Mail: [email protected]
先看效果:
如上圖所示,程序通過攝像頭採集圖像,然後使用cvCanny算子實現邊緣檢測,最後使用cvFindContours查找輪廓,進而根據預設參數尋找對應圖像區域.並完成圖像裁剪與選裝.
程序如下:
/*
2015-07-24 [email protected]
編譯命令如下:
g++ `pkg-config opencv --cflags` main.c -o meter `pkg-config opencv --libs`
*/
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cv.h>
#include <highgui.h>
#include <cmath>
#include <opencv/highgui.h>
#include <stdio.h>
using namespace std;
//旋轉,縮放
int WarpAffine(IplImage *src, double angle, double scale )
{
CvPoint2D32f srcTri[3], dstTri[3];
CvMat* rot_mat = cvCreateMat(2,3,CV_32FC1);
IplImage *dst;
dst = cvCloneImage(src);
dst->origin = src->origin;
cvZero(dst);
//COMPUTE ROTATION MATRIX
CvPoint2D32f center = cvPoint2D32f(src->width/2,
src->height/2);
cv2DRotationMatrix(center,angle,scale,rot_mat);
cvWarpAffine(src,dst,rot_mat);
cvCopy(dst,src);
cvReleaseImage(&dst);
cvReleaseMat(&rot_mat);
return 0;
}
//void callTrackbar( int position )
//{
//}
int main(int argc,char *argv[])
{
char tmpbuf[100];
CvCapture* capture ;
cvNamedWindow("out");
if( argc != 1 )
capture = cvCreateFileCapture( argv[1] ); //從視頻文件獲取圖像
else
capture = cvCreateCameraCapture( 1 ); //從視頻設備獲取圖像
IplImage *frame;
IplImage *out = NULL;
IplImage *grayimg = NULL;
int i = 0;
double length,area,rectArea;
double rectDegree = 0.0; //矩形度
double long2Short = 1.0; //體態比
int DirectFlag = 0; //長寬顛倒標準
//計算邊界序列的參數 長度 面積 矩形 最小矩形
//並輸出每個邊界的參數
CvRect rect;
CvBox2D box;
int imageCnt = 1;
double axisLong = 0.0, axisShort = 0.0;
double temp;
frame = cvQueryFrame( capture ); //讀取一幀數據
if( !frame ) {
cerr<<"cvQueryFrame fail!"<<endl;
return -1;
}
out = cvCreateImage(cvGetSize(frame),IPL_DEPTH_8U,1); //深度8bit 單通道
grayimg = cvCreateImage(cvGetSize(frame),IPL_DEPTH_8U,1);
int cannyMax,cannyMin,threshod;
cannyMax = 0;
cannyMin = 50;
threshod = 0;
while(1)
{
frame = cvQueryFrame( capture ); //讀取一幀數據
if( !frame ) break;
cvCvtColor( frame, grayimg, CV_RGB2GRAY ); //rgb轉換爲灰度圖像
cvCanny( grayimg, out, cannyMin, cannyMax, 3 ); //邊緣檢測處理
cvShowImage("cvCanny",out); //顯示圖像
if( !cannyMax ) {
cannyMax = 150;
cannyMin = 50;
cvCreateTrackbar("cannyMax", "cvCanny", &cannyMax, 255, NULL );
cvSetTrackbarPos( "cannyMax", "cvCanny", cannyMax );
cvCreateTrackbar("cannyMin", "cvCanny", &cannyMin, 255, NULL );
cvSetTrackbarPos( "cannyMin", "cvCanny", cannyMin );
}
//尋找輪廓
CvMemStorage *storage = cvCreateMemStorage(0);
CvSeq * seq = cvCreateSeq(CV_SEQ_ELTYPE_POINT, sizeof(CvSeq), sizeof(CvPoint), storage);
CvSeq * tempSeq = cvCreateSeq(CV_SEQ_ELTYPE_POINT, sizeof(CvSeq), sizeof(CvPoint), storage);
int cnt = cvFindContours( out, storage, &seq );//返回輪廓的數目
cout<<"number of contours "<<cnt<<endl;
for (tempSeq = seq;tempSeq != NULL; tempSeq = tempSeq->h_next)
{
length = cvArcLength(tempSeq);
area = cvContourArea(tempSeq);
//篩選面積比較大的區域
if( area > 10000 ) {
//外接矩形
rect = cvBoundingRect(tempSeq,1);
//繪製輪廓和外接矩形
//cvDrawContours(frame,tempSeq,CV_RGB(255,0,0),CV_RGB(255,0,0),0);
//cvRectangleR(frame,rect,CV_RGB(0,255,0));
//cvShowImage("dst",frame);
//cvWaitKey(0);
//繪製外接最小矩形
CvPoint2D32f pt[4];
box = cvMinAreaRect2(tempSeq,0);
cvBoxPoints(box,pt);
//下面開始分析圖形的形狀特徵
//長軸 短軸
axisLong = sqrt(pow(pt[1].x -pt[0].x,2) + pow(pt[1].y -pt[0].y,2));
axisShort = sqrt(pow(pt[2].x -pt[1].x,2) + pow(pt[2].y -pt[1].y,2));
DirectFlag = 0;
if( axisShort > axisLong ) {
temp = axisLong;
axisLong = axisShort;
axisShort= temp;
DirectFlag = 1;
}
rectArea = axisLong * axisShort;
rectDegree = area / rectArea;
//體態比or長寬比 最下外接矩形的長軸和短軸的比值
long2Short = axisLong/axisShort;
cout<<"long2Short: "<<long2Short<<endl;
cout<<"rectDegree: "<<rectDegree<<endl;
cout<<"rectArea : "<<rectArea<<endl;
if( long2Short> 1.5 && long2Short < 1.8 && rectDegree > 0.9 && rectArea > 10000 && rectArea < 80000 )
{
cout<<"Length: "<<length<<endl;
cout<<"Area : "<<area<<endl;
cout<<"long axis : "<<axisLong<<endl;
cout<<"short axis: "<<axisShort<<endl;
cout<<"long2Short: "<<long2Short<<endl;
cout<<"rectArea : "<<rectArea<<endl;
cout<<"rectDegree: "<<rectDegree<<endl;
for(int i = 0;i<4;++i) {
cvLine(frame,cvPointFrom32f(pt[i]),cvPointFrom32f(pt[((i+1)%4)?(i+1):0]),CV_RGB(255,0,0));
}
cvShowImage("out",frame);
IplImage *cutimg = NULL;
IplImage *cutthreshimg = NULL,*cuttmpimg;
cvSetImageROI(frame,rect);
cutimg = cvCreateImage(cvSize(rect.width,rect.height),IPL_DEPTH_8U,3);
cutthreshimg = cvCreateImage(cvGetSize(cutimg),IPL_DEPTH_8U,1);
cuttmpimg = cvCreateImage(cvGetSize(cutimg),IPL_DEPTH_8U,1);
cvCopy(frame,cutimg,0);
//cvCvtColor( cutimg, cutthreshimg, CV_RGB2GRAY ); //rgb轉換爲灰度圖像
//cvThreshold( cuttmpimg, cutthreshimg, threshod, 255, CV_THRESH_BINARY );//圖像二值化
//cvAdaptiveThreshold( cuttmpimg, cutthreshimg, 255, CV_ADAPTIVE_THRESH_GAUSSIAN_C/*CV_ADAPTIVE_THRESH_MEAN_C*/,
// CV_THRESH_BINARY, 3, 5 ); //自適應閾值化
//cout<<"box.angle: "<<box.angle<<endl;
//圖像旋轉
if( abs(box.angle) < 90 ) //旋轉角度在0度附近時會出現0<>90 震盪! 實際使用時旋轉角度也不會超過30度!
WarpAffine( cutimg, DirectFlag ?box.angle:box.angle+90, 1.0 );
//WarpAffine( cutthreshimg, DirectFlag ?box.angle:box.angle+90, 1.0 );
cvShowImage("cutimg",cutimg);
if( !threshod ) {
threshod = 150;
cvCreateTrackbar("cvThreshold", "cutimg", &threshod, 255, NULL );
cvSetTrackbarPos( "cvThreshold", "cutimg", threshod );
}
cvResetImageROI(frame);
cvReleaseImage( &cutimg );
cvReleaseImage( &cuttmpimg );
cvReleaseImage( &cutthreshimg );
}
}
}
char c = cvWaitKey(50); //等待按鍵輸入
if( c == 27 ) {
cvReleaseMemStorage( &storage );
break;
}
}
cvReleaseCapture( &capture );
cvReleaseImage( &frame );
cvReleaseImage( &out );
cvReleaseImage( &grayimg );
cvDestroyWindow("out");
return 0;
}