最近在做的工作是在一张红外图像中提取人脸区域,由于该区域是不规则的,所以一时找不到头绪。初步思路是:先将其转换成灰度图,对其使用形态学操作,接着使用Canny提取边缘,最后使用FindContours寻找轮廓。问题是寻找到轮廓后如何将其提取出来,暂时真正探索,神啊,Help me......
以下是在网上找到的一篇提取不规则图像的代码,参考一下:
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
程序要求:请自备同大小同的图片两张,一张为原图srcImg,为三通道图片,另一张为mask图,为单通道图片。
下面是Opencv官方手册的对cvCopy的说明:
Copy
拷贝一个数组给另一个数组
void cvCopy( const CvArr* src, CvArr* dst, const CvArr* mask=NULL );
src
输入数组。
dst
输出数组。
mask
操作掩码是8比特单通道的数组,它指定了输出数组中被改变的元素。
函数cvCopy从输入数组中复制选定的成分到输出数组:
如果mask(I)!=0,则dst(I)=src(I)。
如果输入输出数组中的一个是IplImage类型的话,其ROI和COI将被使用。输入输出数组必须是同样的类型、维数和大小。函数也可以用来复制散列数组(这种情况下不支持mask)。
用cvCopy的mask进行对不规制的提取程序截图:
以下是代码:
#include "stdafx.h"
int _tmain(int argc, _TCHAR* argv[])
{
IplImage *pImg=cvLoadImage("c://capture.bmp",1);
IplImage *mask=cvLoadImage("c://mask.bmp",0);
IplImage *dstImg=cvCreateImage(cvGetSize(pImg),8,3);
cvSetZero( dstImg );
cvNot( mask,mask);
cvCopy(pImg,dstImg,mask);
cvNamedWindow("srcShow",1);
cvNamedWindow("dstShow",1);
cvNamedWindow("maskShow",1);
cvShowImage("srcShow",pImg);
cvShowImage("dstShow",dstImg);
cvShowImage("maskShow",mask);
cvWaitKey(0);
cvReleaseImage(&pImg);
cvDestroyWindow("srcShow");
cvDestroyWindow("dstShow");
cvDestroyWindow("maskShow");
return 0;
}
////////////////////////////////////另一个例子///////////////////////////////////////////////////////////
opencv例子里没有提供cvsnakeimage的使用方法,在此整理一个例子,可以形象的看看snake算法的结果,大致做法是:
首先设定域值分割,把基本的轮廓找出来,见图中蓝色轮廓线,再将轮廓点传入cvSnakeImage函数,计算出绿色的snake轮廓线。
其中参数alpha代表点相互靠拢的权值(0-1.0),beta表示弯曲能量(越小越容易弯曲)(0-1.0),gamma表示整体能量(0-1.0)。其中参数我自己也不确定具体的范围,最好自己更改不同的范围试试.
// TrainingTools.cpp : 定义控制台应用程序的入口点。 // #include "stdafx.h" #include <iostream> #include <string.h> #include <cxcore.h> #include <cv.h> #include <highgui.h> #include <fstream> IplImage *image = 0 ; //原始图像 IplImage *image2 = 0 ; //原始图像copy using namespace std; int Thresholdness = 141; int ialpha = 20; int ibeta=20; int igamma=20; void onChange(int pos) { if(image2) cvReleaseImage(&image2); if(image) cvReleaseImage(&image); image2 = cvLoadImage("grey.bmp",1); //显示图片 image= cvLoadImage("grey.bmp",0); cvThreshold(image,image,Thresholdness,255,CV_THRESH_BINARY); //分割域值 CvMemStorage* storage = cvCreateMemStorage(0); CvSeq* contours = 0; cvFindContours( image, storage, &contours, sizeof(CvContour), //寻找初始化轮廓 CV_RETR_EXTERNAL , CV_CHAIN_APPROX_SIMPLE ); if(!contours) return ; int length = contours->total; if(length<10) return ; CvPoint* point = new CvPoint[length]; //分配轮廓点 CvSeqReader reader; CvPoint pt= cvPoint(0,0);; CvSeq *contour2=contours; cvStartReadSeq(contour2, &reader); for (int i = 0; i < length; i++) { CV_READ_SEQ_ELEM(pt, reader); point[i]=pt; } cvReleaseMemStorage(&storage); //显示轮廓曲线 for(int i=0;i<length;i++) { int j = (i+1)%length; cvLine( image2, point[i],point[j],CV_RGB( 0, 0, 255 ),1,8,0 ); } float alpha=ialpha/100.0f; float beta=ibeta/100.0f; float gamma=igamma/100.0f; CvSize size; size.width=3; size.height=3; CvTermCriteria criteria; criteria.type=CV_TERMCRIT_ITER; criteria.max_iter=1000; criteria.epsilon=0.1; cvSnakeImage( image, point,length,&alpha,&beta,&gamma,CV_VALUE,size,criteria,0 ); //显示曲线 for(int i=0;i<length;i++) { int j = (i+1)%length; cvLine( image2, point[i],point[j],CV_RGB( 0, 255, 0 ),1,8,0 ); } delete []point; } int main(int argc, char* argv[]) { cvNamedWindow("win1",0); cvCreateTrackbar("Thd", "win1", &Thresholdness, 255, onChange); cvCreateTrackbar("alpha", "win1", &ialpha, 100, onChange); cvCreateTrackbar("beta", "win1", &ibeta, 100, onChange); cvCreateTrackbar("gamma", "win1", &igamma, 100, onChange); cvResizeWindow("win1",300,500); onChange(0); for(;;) { if(cvWaitKey(40)==27) break; cvShowImage("win1",image2); } return 0; }