cv1.2

图像去噪声

添加高斯噪声

// cv2.cpp : Defines the entry point for the console application.
//
#include <opencv2/opencv.hpp> 

    #include <iostream>  

    using namespace cv;
    using namespace std;  

    #define TWO_PI 6.2831853071795864769252866  

    double generateGaussianNoise()
    {
        static bool hasSpare = false;
        static double rand1, rand2;  

        if(hasSpare)
        {
            hasSpare = false;
            return sqrt(rand1) * sin(rand2);
        }  

        hasSpare = true;  

        rand1 = rand() / ((double) RAND_MAX);
        if(rand1 < 1e-100) rand1 = 1e-100;
        rand1 = -2 * log(rand1);
        rand2 = (rand() / ((double) RAND_MAX)) * TWO_PI;  

        return sqrt(rand1) * cos(rand2);
    }  

    void AddGaussianNoise(Mat& I)
    {
        // accept only char type matrices
        CV_Assert(I.depth() != sizeof(uchar));  

        int channels = I.channels();  

        int nRows = I.rows;
        int nCols = I.cols * channels;  

        if(I.isContinuous()){
            nCols *= nRows;
            nRows = 1;
        }  

        int i,j;
        uchar* p;
        for(i = 0; i < nRows; ++i){
            p = I.ptr<uchar>(i);
            for(j = 0; j < nCols; ++j){
                double val = p[j] + generateGaussianNoise() * 128;
                if(val < 0)
                    val = 0;
                if(val > 255)
                    val = 255;  

                p[j] = (uchar)val;  

            }
        }  

    }  

    int main( int argc, char** argv )
    {  

        Mat image;
        image = imread("f:\\img\\lena.jpg", 1); // Read the file  

        if(! image.data ) // Check for invalid input
        {
            cout << "Could not open or find the image" << std::endl ;
            return -1;
        }  

        namedWindow( "Display window", WINDOW_AUTOSIZE ); // Create a window for display.
        imshow( "Display window", image ); // Show our image inside it.  

        // Add Gaussian noise here
        AddGaussianNoise(image);  

        namedWindow( "Noisy image", WINDOW_AUTOSIZE ); // Create a window for display.
        imshow( "Noisy image", image ); // Show our image inside it.
        waitKey(0); // Wait for a keystroke in the window  

        return 0;
    }  

椒盐噪声

// cv2.cpp : Defines the entry point for the console application.
//
#include <opencv2/opencv.hpp> 

    #include <iostream>  

void salt(cv::Mat&, int n=3000);

int main(){
    cv::Mat image = cv::imread("f:\\img\\Lena.jpg");
    salt(image, 10000);
    cv::namedWindow("image");
    cv::imshow("image",image);
    cv::waitKey(0);
}

void salt(cv::Mat& image, int n){
    for(int k=0; k<n; k++){
        int i = rand()%image.cols;
        int j = rand()%image.rows;

        if(image.channels() == 1){
            image.at<uchar>(j,i) = 255;
        }else{
            image.at<cv::Vec3b>(j,i)[0] = 255;
            image.at<cv::Vec3b>(j,i)[1] = 255;
            image.at<cv::Vec3b>(j,i)[2] = 255;
        }
    }
}

去除噪声

1掌握算术均值滤波器、几何均值滤波器、谐波和逆谐波均值滤波器进行图像去噪的算法

2掌握利用中值滤波器进行图像去噪的算法

3掌握自适应中值滤波算法

4掌握自适应局部降低噪声滤波器去噪算法

5掌握彩色图像去噪步骤

1、均值滤波

具体内容:利用OpenCV 对灰度图像像素进行操作,分别利用算术均值滤波器、几何均值滤波器、谐波和逆谐波均值滤波器进行图像去噪。模板大小为5*5。(注:请分别为图像添加高斯噪声、胡椒噪声、盐噪声和椒盐噪声,并观察滤波效果)

2、中值滤波

具体内容:利用OpenCV 对灰度图像像素进行操作,分别利用5*5 和9*9尺寸的模板对图像进行中值滤波。(注:请分别为图像添加胡椒噪声、盐噪声和椒盐噪声,并观察滤波效果)

3、自适应均值滤波。

具体内容:利用OpenCV 对灰度图像像素进行操作,设计自适应局部降低噪声滤波器去噪算法。模板大小7*7(对比该算法的效果和均值滤波器的效果)

4、自适应中值滤波

具体内容:利用OpenCV 对灰度图像像素进行操作,设计自适应中值滤波算法对椒盐图像进行去噪。模板大小7*7(对比中值滤波器的效果)

5、彩色图像均值滤波

具体内容:利用

OpenCV 对彩色图像RGB 三个通道的像素进行操作,利用算术均值滤波器和几何均值滤波器进行彩色图像去噪。模板大小为5*5

// cv2.cpp : Defines the entry point for the console application.
//
#include<opencv\\cv.h>
#include<opencv\\highgui.h>

    #include <iostream>
//1、	实验步骤:先为灰度图像添加高斯噪声、胡椒噪声、盐噪声和椒盐噪声,再分别利用算术均值滤波器、几何均值滤波器、谐波和逆谐波均值滤波器进行图像去噪。模板大小为5*5。
//核心代码如下:
//添加各类噪声:

IplImage* AddGuassianNoise(IplImage* src)    //添加高斯噪声
{
    IplImage* dst = cvCreateImage(cvGetSize(src),src->depth,src->nChannels);
	IplImage* noise = cvCreateImage(cvGetSize(src),src->depth,src->nChannels);
	CvRNG rng = cvRNG(-1);
	cvRandArr(&rng,noise,CV_RAND_NORMAL,cvScalarAll(0),cvScalarAll(15));
	cvAdd(src,noise,dst);
	return dst;
}
IplImage* AddPepperNoise(IplImage* src)      //添加胡椒噪声,随机黑色点
{
    IplImage* dst = cvCreateImage(cvGetSize(src),src->depth,src->nChannels);
	cvCopy(src, dst);
	for(int k=0; k<8000; k++)
    {
	   int i = rand()%src->height;
	   int j = rand()%src->width;
       CvScalar s = cvGet2D(src, i, j);
	   if(src->nChannels == 1)
       {
	      s.val[0] = 0;
	   }
       else if(src->nChannels==3)
       {
	      s.val[0]=0;
	      s.val[1]=0;
	      s.val[2]=0;
       }
	   cvSet2D(dst, i, j, s);
    }
	return dst;
}
IplImage* AddSaltNoise(IplImage* src)       //添加盐噪声,随机白色点
{
    IplImage* dst = cvCreateImage(cvGetSize(src),src->depth,src->nChannels);
	cvCopy(src, dst);
	for(int k=0; k<8000; k++)
    {
	    int i = rand()%src->height;
	    int j = rand()%src->width;
        CvScalar s = cvGet2D(src, i, j);
	    if(src->nChannels == 1)
        {
		    s.val[0] = 255;
	    }
        else if(src->nChannels==3)
        {
		    s.val[0]=255;
		    s.val[1]=255;
		    s.val[2]=255;
        }
	    cvSet2D(dst, i, j, s);
    }
	return dst;
}
IplImage* AddPepperSaltNoise(IplImage* src)    //添加椒盐噪声,随机黑白点
{
    IplImage* dst = cvCreateImage(cvGetSize(src),src->depth,src->nChannels);
	cvCopy(src, dst);
	for(int k=0; k<8000; k++)
    {
	    int i = rand()%src->height;
	    int j = rand()%src->width;
	    int m = rand()%2;
        CvScalar s = cvGet2D(src, i, j);
	    if(src->nChannels == 1)
        {
		   if(m==0)
           {
	           s.val[0] = 255;
		   }
           else
           {
		       s.val[0] = 0;
		   }
	    }
        else if(src->nChannels==3)
        {
		   if(m==0)
           {
		      s.val[0]=255;
		      s.val[1]=255;
		      s.val[2]=255;
		   }
           else
           {
	          s.val[0]=0;
		      s.val[1]=0;
		      s.val[2]=0;
		   }
        }
	    cvSet2D(dst, i, j, s);
    }
	return dst;
}
//各类滤波器实现:
//算术均值滤波器——模板大小5*5
IplImage* ArithmeticMeanFilter(IplImage* src)
{
    IplImage* dst = cvCreateImage(cvGetSize(src),src->depth,src->nChannels);
    cvSmooth(src,dst,CV_BLUR,5);
    return dst;
}
//几何均值滤波器——模板大小5*5
IplImage* GeometryMeanFilter(IplImage* src)
{
	IplImage* dst = cvCreateImage(cvGetSize(src),src->depth,src->nChannels);
	int row, col;
	int h=src->height;
	int w=src->width;
	double mul[3];
	double dc[3];
	int mn;
	//计算每个像素的去噪后color值
	for(int i=0;i<src->height;i++){
		for(int j=0;j<src->width;j++){
			mul[0]=1.0;
			mn=0;
			//统计邻域内的几何平均值,邻域大小5*5
			for(int m=-2;m<=2;m++){
				row = i+m;
				for(int n=-2;n<=2;n++){
					col = j+n;
					if(row>=0&&row<h && col>=0 && col<w){
						CvScalar s = cvGet2D(src, row, col);
						mul[0] = mul[0]*(s.val[0]==0?1:s.val[0]);   //邻域内的非零像素点相乘
						mn++;
					}
				}
			}
			//计算1/mn次方
			CvScalar d;
			dc[0] = pow(mul[0], 1.0/mn);
			d.val[0]=dc[0];
			//统计成功赋给去噪后图像。
			cvSet2D(dst, i, j, d);
		}
	}
	return dst;
}
//谐波均值滤波器——模板大小5*5
IplImage* HarmonicMeanFilter(IplImage* src)
{
	IplImage* dst = cvCreateImage(cvGetSize(src),src->depth,src->nChannels);
	int row, col;
	int h=src->height;
	int w=src->width;
	double sum[3];
	double dc[3];
	int mn;
	//计算每个像素的去噪后color值
	for(int i=0;i<src->height;i++){
		for(int j=0;j<src->width;j++){
			sum[0]=0.0;
			mn=0;
			//统计邻域,5*5模板
			for(int m=-2;m<=2;m++){
				row = i+m;
				for(int n=-2;n<=2;n++){
					col = j+n;
					if(row>=0&&row<h && col>=0 && col<w){
						CvScalar s = cvGet2D(src, row, col);
						sum[0] = sum[0]+(s.val[0]==0?255:255/s.val[0]);
						mn++;
					}
				}
			}
			CvScalar d;
			dc[0] = mn*255/sum[0];
			d.val[0]=dc[0];
			//统计成功赋给去噪后图像。
			cvSet2D(dst, i, j, d);
		}
	}
	return dst;
}
//逆谐波均值大小滤波器——模板大小5*5
IplImage* InverseHarmonicMeanFilter(IplImage* src)
{
	IplImage* dst = cvCreateImage(cvGetSize(src),src->depth,src->nChannels);
	//cvSmooth(src,dst,CV_BLUR,5);
	int row, col;
	int h=src->height;
	int w=src->width;
	double sum[3];
	double sum1[3];
	double dc[3];
	double Q=2;
	//计算每个像素的去噪后color值
	for(int i=0;i<src->height;i++){
		for(int j=0;j<src->width;j++){
			sum[0]=0.0;
			sum1[0]=0.0;
			//统计邻域
			for(int m=-2;m<=2;m++){
				row = i+m;
				for(int n=-2;n<=2;n++){
					col = j+n;
					if(row>=0&&row<h && col>=0 && col<w){
						CvScalar s = cvGet2D(src, row, col);
						sum[0] = sum[0]+pow(s.val[0]/255, Q+1);
						sum1[0] = sum1[0]+pow(s.val[0]/255, Q);
					}
				}
			}
			//计算1/mn次方
			CvScalar d;
			dc[0] = (sum1[0]==0?0:(sum[0]/sum1[0]))*255;
			d.val[0]=dc[0];
			//统计成功赋给去噪后图像。
			cvSet2D(dst, i, j, d);
		}
	}
	return dst;
}

//2、	实验步骤:先为灰度图像添加胡椒噪声、盐噪声和椒盐噪声,再分别利用5*5 和 9*9尺寸的模板对图像进行中值滤波。
//核心代码如下:
IplImage* MedianFilter_5_5(IplImage* src){
	IplImage* dst = cvCreateImage(cvGetSize(src),src->depth,src->nChannels);
	cvSmooth(src,dst,CV_MEDIAN,5);
	return dst;
}
IplImage* MedianFilter_9_9(IplImage* src){
	IplImage* dst = cvCreateImage(cvGetSize(src),src->depth,src->nChannels);
	cvSmooth(src,dst,CV_MEDIAN,9);
	return dst;
}

//3、	实验步骤:自适应均值滤波(以高斯噪声为例),先为灰度图像添加高斯噪声,再利用7*7尺寸的模板对图像进行自适应均值滤波。
//核心代码如下:
IplImage* SelfAdaptMeanFilter(IplImage* src){
	IplImage* dst = cvCreateImage(cvGetSize(src),src->depth,src->nChannels);
	cvSmooth(src,dst,CV_BLUR,7);
	int row, col;
	int h=src->height;
	int w=src->width;
	int mn;
	double Zxy;
	double Zmed;
	double Sxy;
	double Sl;
	double Sn=100;
	for(int i=0;i<src->height;i++){
		for(int j=0;j<src->width;j++){
			CvScalar xy = cvGet2D(src, i, j);
			Zxy = xy.val[0];
			CvScalar dxy = cvGet2D(dst, i, j);
			Zmed = dxy.val[0];
			Sl=0;
			mn=0;
			for(int m=-3;m<=3;m++){
				row = i+m;
				for(int n=-3;n<=3;n++){
					col = j+n;
					if(row>=0&&row<h && col>=0 && col<w){
						CvScalar s = cvGet2D(src, row, col);
						Sxy = s.val[0];
						Sl = Sl+pow(Sxy-Zmed, 2);
						mn++;
					}
				}
			}
			Sl=Sl/mn;
			CvScalar d;
			d.val[0]=Zxy-Sn/Sl*(Zxy-Zmed);
			cvSet2D(dst, i, j, d);
		}
	}
	return dst;
}
//4、	实验步骤:自适应中值滤波(以椒盐噪声为例),先为灰度图像添加椒盐噪声,再利用7*7尺寸的模板对图像进行自适应中值滤波。
//核心代码如下:
IplImage* SelfAdaptMedianFilter(IplImage* src){
	IplImage* dst = cvCreateImage(cvGetSize(src),src->depth,src->nChannels);
	int row, col;
	int h=src->height;
	int w=src->width;
	double Zmin,Zmax,Zmed,Zxy,Smax=7;
	int wsize;
	//计算每个像素的去噪后color值
	for(int i=0;i<src->height;i++){
		for(int j=0;j<src->width;j++){
			//统计邻域
			wsize=1;
			while(wsize<=3){
				Zmin=255.0;
				Zmax=0.0;
				Zmed=0.0;
				CvScalar xy = cvGet2D(src, i, j);
				Zxy=xy.val[0];
				int mn=0;
				for(int m=-wsize;m<=wsize;m++){
					row = i+m;
					for(int n=-wsize;n<=wsize;n++){
						col = j+n;
						if(row>=0&&row<h && col>=0 && col<w){
							CvScalar s = cvGet2D(src, row, col);
							if(s.val[0]>Zmax){
								Zmax=s.val[0];
							}
							if(s.val[0]<Zmin){
								Zmin=s.val[0];
							}
							Zmed=Zmed+s.val[0];
							mn++;
						}
					}
				}
				Zmed = Zmed/mn;
				CvScalar d;
				if((Zmed-Zmin)>0 && (Zmed-Zmax)<0){
					if((Zxy-Zmin)>0 && (Zxy-Zmax)<0){
						d.val[0]=Zxy;
					}else{
						d.val[0]=Zmed;
					}
					cvSet2D(dst, i, j, d);
					break;
				} else {
					wsize++;
					if(wsize>3){
						CvScalar d;
						d.val[0]=Zmed;
						cvSet2D(dst, i, j, d);
						break;
					}
				}
			}
		}
	}
	return dst;
}
int main()
{
	IplImage*img=cvLoadImage("F:\\img\\lena.jpg",1);
	if(NULL==img)  exit(1);
	IplImage  * noise=AddPepperNoise(img);
	IplImage  * imgfil=MedianFilter_5_5(noise);

     cvNamedWindow("src",1);
     cvShowImage("src",img);
	 cvNamedWindow("noise",1);
     cvShowImage("noise",noise);
	  cvNamedWindow("filter",1);
     cvShowImage("filter",imgfil);
     cvWaitKey(0);
     cvReleaseImage(&img);
	 cvReleaseImage(&noise);
	 cvReleaseImage(&imgfil);
     cvDestroyWindow("src");
	 cvDestroyWindow("noise");
	 cvDestroyWindow("filter");
return 0;
}

图像倾斜扶正

识别倾斜图像运动物体跟踪

去除背景

图像拼接

图像去抖

画轮廓包络

人脸检测

// cv2.cpp : Defines the entry point for the console application.
//
#include "opencv2/objdetect/objdetect.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/ml/ml.hpp"  

#include <iostream>
#include <stdio.h>  

using namespace std;
using namespace cv;  

void detectAndDraw( Mat& img,
                   CascadeClassifier& cascade, CascadeClassifier& nestedCascade,
                   double scale);  

String cascadeName = "F:\\opencv\\sources\\data\\haarcascades\\haarcascade_frontalface_alt2.xml";//人脸的训练数据
//String nestedCascadeName = "./haarcascade_eye_tree_eyeglasses.xml";//人眼的训练数据
String nestedCascadeName = "F:\\opencv\\sources\\data\\haarcascades\\haarcascade_eye.xml";//人眼的训练数据  

int main( int argc, const char** argv )
{
    Mat image;
    CascadeClassifier cascade, nestedCascade;//创建级联分类器对象
    double scale = 1.3;  

    //image = imread( "lena.jpg", 1 );//读入lena图片
    image = imread("f:\\img\\lena.jpg",1);
    namedWindow( "result", 1 );//opencv2.0以后用namedWindow函数会自动销毁窗口  

    if( !cascade.load( cascadeName ) )//从指定的文件目录中加载级联分类器
    {
         cerr << "ERROR: Could not load classifier cascade唉唉出错了" << endl;
         return 0;
    }  

    if( !nestedCascade.load( nestedCascadeName ) )
    {
         cerr << "WARNING: Could not load classifier cascade for nested objects" << endl;
         return 0;
    }  

    if( !image.empty() )//读取图片数据不能为空
    {
        detectAndDraw( image, cascade, nestedCascade, scale );
        waitKey(0);
    }  

    return 0;
}  

void detectAndDraw( Mat& img,
                   CascadeClassifier& cascade, CascadeClassifier& nestedCascade,
                   double scale)
{
    int i = 0;
    double t = 0;
    vector<Rect> faces;
    const static Scalar colors[] =  { CV_RGB(0,0,255),
        CV_RGB(0,128,255),
        CV_RGB(0,255,255),
        CV_RGB(0,255,0),
        CV_RGB(255,128,0),
        CV_RGB(255,255,0),
        CV_RGB(255,0,0),
        CV_RGB(255,0,255)} ;//用不同的颜色表示不同的人脸  

    Mat gray, smallImg( cvRound (img.rows/scale), cvRound(img.cols/scale), CV_8UC1 );//将图片缩小,加快检测速度  

    cvtColor( img, gray, CV_BGR2GRAY );//因为用的是类haar特征,所以都是基于灰度图像的,这里要转换成灰度图像
    resize( gray, smallImg, smallImg.size(), 0, 0, INTER_LINEAR );//将尺寸缩小到1/scale,用线性插值
    equalizeHist( smallImg, smallImg );//直方图均衡  

    t = (double)cvGetTickCount();//用来计算算法执行时间  

//检测人脸
 //detectMultiScale函数中smallImg表示的是要检测的输入图像为smallImg,faces表示检测到的人脸目标序列,1.1表示
 //每次图像尺寸减小的比例为1.1,2表示每一个目标至少要被检测到3次才算是真的目标(因为周围的像素和不同的窗口大
 //小都可以检测到人脸),CV_HAAR_SCALE_IMAGE表示不是缩放分类器来检测,而是缩放图像,Size(30, 30)为目标的
 //最小最大尺寸
    cascade.detectMultiScale( smallImg, faces,
        1.1, 2, 0
        //|CV_HAAR_FIND_BIGGEST_OBJECT
//|CV_HAAR_DO_ROUGH_SEARCH
        |CV_HAAR_SCALE_IMAGE
        ,
        Size(30, 30) );  

    t = (double)cvGetTickCount() - t;//相减为算法执行的时间
    printf( "detection time = %g ms\n", t/((double)cvGetTickFrequency()*1000.) );
    for( vector<Rect>::const_iterator r = faces.begin(); r != faces.end(); r++, i++ )
    {
        Mat smallImgROI;
        vector<Rect> nestedObjects;
        Point center;
        Scalar color = colors[i%8];
        int radius;
        center.x = cvRound((r->x + r->width*0.5)*scale);//还原成原来的大小
        center.y = cvRound((r->y + r->height*0.5)*scale);
        radius = cvRound((r->width + r->height)*0.25*scale);
        circle( img, center, radius, color, 3, 8, 0 );  

        //检测人眼,在每幅人脸图上画出人眼
        if( nestedCascade.empty() )
            continue;
        smallImgROI = smallImg(*r);  

        //和上面的函数功能一样
        nestedCascade.detectMultiScale( smallImgROI, nestedObjects,
            1.1, 2, 0
            //|CV_HAAR_FIND_BIGGEST_OBJECT
//|CV_HAAR_DO_ROUGH_SEARCH
//|CV_HAAR_DO_CANNY_PRUNING
            |CV_HAAR_SCALE_IMAGE
            ,
            Size(30, 30) );
        for( vector<Rect>::const_iterator nr = nestedObjects.begin(); nr != nestedObjects.end(); nr++ )
        {
            center.x = cvRound((r->x + nr->x + nr->width*0.5)*scale);
            center.y = cvRound((r->y + nr->y + nr->height*0.5)*scale);
            radius = cvRound((nr->width + nr->height)*0.25*scale);
            circle( img, center, radius, color, 3, 8, 0 );//将眼睛也画出来,和对应人脸的图形是一样的
        }
    }
    cv::imshow( "result", img );
}

人脸打马赛克

// cv2.cpp : Defines the entry point for the console application.
//
#include<opencv\\cv.h>
#include<opencv\\highgui.h>

#include <iostream>
#include <stdio.h>  

using namespace std;
using namespace cv;
static CvHaarClassifierCascade* cascade = 0;
static CvMemStorage* storage = 0;  

void detect_and_draw( IplImage* image );
const char* cascade_name ="F:\\opencv\\sources\\data\\haarcascades\\haarcascade_frontalface_alt.xml";  

  void detect_and_draw( IplImage* img )
{
  //static CvScalar colors[] =
  //{
  //	{{0,0,255}},
  //	{{0,128,255}},
  //	{{0,255,255}},
  //	{{0,255,0}},
  //	{{255,128,0}},
  //	{{255,255,0}},
  //	{{255,0,0}},
  //	{{255,0,255}}
  //};  //用不同颜色的圈圈区分不同的人

  double scale = 1.3;													//先缩小为small_img 后放大,为了便于处理也可以不用
  IplImage* gray = cvCreateImage( cvSize(img->width,img->height), 8, 1 );
  IplImage* small_img = cvCreateImage( cvSize( cvRound (img->width/scale),  cvRound (img->height/scale)),  8, 1 );
  int i;  

  cvCvtColor( img, gray, CV_BGR2GRAY );								//灰度图
  cvResize( gray, small_img, CV_INTER_LINEAR );						//缩小
  cvEqualizeHist( small_img, small_img );								//经过上面两步,gray指向的图像已经变为small_img
  cvClearMemStorage( storage );										//动态内存重置

  if( cascade )														//括号里是分类器的指针,就是用这个东西来判断是不是人脸的!!!
  {
    double t = (double)cvGetTickCount();							//开始计时
    CvSeq* faces = cvHaarDetectObjects( small_img, cascade, storage,
      1.1, 2, 0													/*CV_HAAR_DO_CANNY_PRUNING*/,
      cvSize(30, 30) );											//检测的核心语句,注意cascade参数
    t = (double)cvGetTickCount() - t;								//计算时间间隔
    //cout<<"detection time = %gms\n"<<t/((double)cvGetTickFrequency()*1000.)<<endl;//打印出所用的时间
    for( i = 0; i < (faces ? faces->total : 0); i++ )				//总共有faces->total 个脸,把他们一个一个圈出来
    {
      CvRect* r = (CvRect*)cvGetSeqElem( faces, i );				//每个脸对应的链表节点
      CvPoint center;
      int radius;
      center.x = cvRound((r->x + r->width*0.5)*scale);			//圆心横坐标,注意scale,这里放大
      center.y = cvRound((r->y + r->height*0.5)*scale);			//纵坐标
      radius = cvRound((r->width + r->height)*0.25*scale);		//半径
      //cvCircle( img, center, radius, colors[i%8], -1, 8, 0 );	//画圆圈出目标头像

      //马赛克
      cvSetImageROI(img,cvRect(center.x-radius,center.y-radius,radius*2,radius*2));
      int W=8;
      int H=8;
      for(int mi=W;mi<img->roi->width;mi+=W)
        for(int mj=H;mj<img->roi->height;mj+=H)
        {
          CvScalar tmp=cvGet2D(img,mj-H/2,mi-W/2);
          for(int mx=mi-W;mx<=mi;mx++)
            for(int my=mj-H;my<=mj;my++)
              cvSet2D(img,my,mx,tmp);
        }
      cvResetImageROI(img);
    }
  }
  cvShowImage( "result", img );
  cvShowImage( "gray", gray );
  cvShowImage( "face", small_img );
  cvReleaseImage( &gray );
  cvReleaseImage( &small_img );
}
  int main(int argc, char* argv[])
{
     cascade = (CvHaarClassifierCascade*)cvLoad( cascade_name, 0, 0, 0 );   //加载人脸检测所用的分类器
     if( !cascade )
     {
        fprintf( stderr, "ERROR: Could not load classifier cascade\n" );
        return -1;
     }  

     storage = cvCreateMemStorage(0);                                       //动态存储结构,用来存储人脸在图像中的位置
     cvNamedWindow( "result", 1 );
     cvNamedWindow( "gray", 1);
     cvNamedWindow("face",1);  

     const char* filename = "f:\\img\\lena.jpg";                                     //待检测图像(包含绝对路径)
     //const char* filename = "景甜.jpg";
     IplImage* image = cvLoadImage( filename, 1 );                          //加载图像
     detect_and_draw( image );                                              //对加载的图像进行检测
     cvWaitKey(0);
     cvReleaseImage( &image );
     cvDestroyWindow("result");
     cvDestroyWindow("gray");
     return 0;
}  

倾斜人脸检测

人脸识别

马赛克去除

Delaunay三角网与Voronoi图

(实线多边形就是Delaunay三角网;虚线多边形式Voronoi图)

  Voronoi图,又叫泰森多边形或Dirichlet图,它是由一组由连接两邻点直线的垂直平分线组成的连续多边形组成。N个在平面上有区别的点,按照最邻近原则划分平面;每个点与它的最近邻区域相关联。Delaunay三角形是由与相邻Voronoi多边形共享一条边的相关点连接而成的三角形。Delaunay三角形的外接圆圆心是与三角形相关的Voronoi多边形的一个顶点。Voronoi三角形是Delaunay图的偶图;

  对于给定的初始点集P,有多种三角网剖分方式,其中Delaunay三角网具有以下特征

  1、Delaunay三角网是唯一的;

  2、三角网的外边界构成了点集P的凸多边形“外壳”;

  3、没有任何点在三角形的外接圆内部,反之,如果一个三角网满足此条件,那么它就是Delaunay三角网。

  4、如果将三角网中的每个三角形的最小角进行升序排列,则Delaunay三角网的排列得到的数值最大,从这个意义上讲,Delaunay三角网是“最接近于规则化的“的三角网。

  Delaunay三角形网的特征又可以表达为以下特性

  1、在Delaunay三角形网中任一三角形的外接圆范围内不会有其它点存在并与其通视,即空圆特性;

  2、在构网时,总是选择最邻近的点形成三角形并且不与约束线段相交;

  3、形成的三角形网总是具有最优的形状特征,任意两个相邻三角形形成的凸四边形的对角线如果可以互换的话,那么两个三角形6个内角中最小的角度不会变大;

  4、不论从区域何处开始构网,最终都将得到一致的结果,即构网具有唯一性。

  Delaunay三角形产生的基本准则:任何一个Delaunay三角形的外接圆的内部不能包含其他任何点[Delaunay1934]。Lawson[1972]提出了最大化最小角原则,每两个相邻的三角形构成凸四边形的对角线,在相互交换后,六个内角的最小角不再增大。Lawson[1977提出了一个局部优化过程(LOP,local Optimization Procedure)方法。

#include "opencv\\cv.h"
#include "opencv\\highgui.h"
#include <opencv2/legacy/legacy.hpp>
#include <stdio.h>
/* the script demostrates iterative construction of
   delaunay triangulation and voronoi tesselation */
CvSubdiv2D* init_delaunay( CvMemStorage* storage,
                           CvRect rect )
{
    CvSubdiv2D* subdiv;
    subdiv = cvCreateSubdiv2D( CV_SEQ_KIND_SUBDIV2D, sizeof(*subdiv),
                               sizeof(CvSubdiv2DPoint),
                               sizeof(CvQuadEdge2D),
                               storage );
    cvInitSubdivDelaunay2D( subdiv, rect );
    return subdiv;
}

void draw_subdiv_point( IplImage* img, CvPoint2D32f fp, CvScalar color )
{
    cvCircle( img, cvPoint(cvRound(fp.x), cvRound(fp.y)), 3, color, CV_FILLED, 8, 0 );
}

void draw_subdiv_edge( IplImage* img, CvSubdiv2DEdge edge, CvScalar color )
{
    CvSubdiv2DPoint* org_pt;
    CvSubdiv2DPoint* dst_pt;
    CvPoint2D32f org;
    CvPoint2D32f dst;
    CvPoint iorg, idst;
    org_pt = cvSubdiv2DEdgeOrg(edge);
    dst_pt = cvSubdiv2DEdgeDst(edge);
    if( org_pt && dst_pt )
    {
        org = org_pt->pt;
        dst = dst_pt->pt;
        iorg = cvPoint( cvRound( org.x ), cvRound( org.y ));
        idst = cvPoint( cvRound( dst.x ), cvRound( dst.y ));
        cvLine( img, iorg, idst, color, 1, CV_AA, 0 );
    }
}

void draw_subdiv( IplImage* img, CvSubdiv2D* subdiv,
                  CvScalar delaunay_color, CvScalar voronoi_color )
{
    CvSeqReader reader;
    int i, total = subdiv->edges->total;
    int elem_size = subdiv->edges->elem_size;
    cvStartReadSeq( (CvSeq*)(subdiv->edges), &reader, 0 );
    for( i = 0; i < total; i++ )
    {
        CvQuadEdge2D* edge = (CvQuadEdge2D*)(reader.ptr);
        if( CV_IS_SET_ELEM( edge ))
        {
            draw_subdiv_edge( img, (CvSubdiv2DEdge)edge + 1, voronoi_color );
            draw_subdiv_edge( img, (CvSubdiv2DEdge)edge, delaunay_color );
        }
        CV_NEXT_SEQ_ELEM( elem_size, reader );
    }
}

void locate_point( CvSubdiv2D* subdiv, CvPoint2D32f fp, IplImage* img,
                   CvScalar active_color )
{
    CvSubdiv2DEdge e;
    CvSubdiv2DEdge e0 = 0;
    CvSubdiv2DPoint* p = 0;
    cvSubdiv2DLocate( subdiv, fp, &e0, &p );
    if( e0 )
    {
        e = e0;
        do
        {
            draw_subdiv_edge( img, e, active_color );
            e = cvSubdiv2DGetEdge(e,CV_NEXT_AROUND_LEFT);
        }
        while( e != e0 );
    }
    draw_subdiv_point( img, fp, active_color );
}

void draw_subdiv_facet( IplImage* img, CvSubdiv2DEdge edge )
{
    CvSubdiv2DEdge t = edge;
    int i, count = 0;
    CvPoint* buf = 0;
    // count number of edges in facet
    do
    {
        count++;
        t = cvSubdiv2DGetEdge( t, CV_NEXT_AROUND_LEFT );
    } while (t != edge );
    buf = (CvPoint*)malloc( count * sizeof(buf[0]));
    // gather points
    t = edge;
    for( i = 0; i < count; i++ )
    {
        CvSubdiv2DPoint* pt = cvSubdiv2DEdgeOrg( t );
        if( !pt ) break;
        buf[i] = cvPoint( cvRound(pt->pt.x), cvRound(pt->pt.y));
        t = cvSubdiv2DGetEdge( t, CV_NEXT_AROUND_LEFT );
    }
    if( i == count )
    {
        CvSubdiv2DPoint* pt = cvSubdiv2DEdgeDst( cvSubdiv2DRotateEdge( edge, 1 ));
        cvFillConvexPoly( img, buf, count, CV_RGB(rand()&255,rand()&255,rand()&255), CV_AA, 0 );
        cvPolyLine( img, &buf, &count, 1, 1, CV_RGB(0,0,0), 1, CV_AA, 0);
        draw_subdiv_point( img, pt->pt, CV_RGB(0,0,0));
    }
    free( buf );
}
void paint_voronoi( CvSubdiv2D* subdiv, IplImage* img )
{
    CvSeqReader reader;
    int i, total = subdiv->edges->total;
    int elem_size = subdiv->edges->elem_size;
    cvCalcSubdivVoronoi2D( subdiv );
    cvStartReadSeq( (CvSeq*)(subdiv->edges), &reader, 0 );
    for( i = 0; i < total; i++ )
    {
        CvQuadEdge2D* edge = (CvQuadEdge2D*)(reader.ptr);
        if( CV_IS_SET_ELEM( edge ))
        {
            CvSubdiv2DEdge e = (CvSubdiv2DEdge)edge;
            // left
            draw_subdiv_facet( img, cvSubdiv2DRotateEdge( e, 1 ));
            // right
            draw_subdiv_facet( img, cvSubdiv2DRotateEdge( e, 3 ));
        }
        CV_NEXT_SEQ_ELEM( elem_size, reader );
    }
}

void run(void)
{
    char win[] = "source";
    int i;
    CvRect rect = { 0, 0, 600, 600 };
    CvMemStorage* storage;
    CvSubdiv2D* subdiv;
    IplImage* img;
    CvScalar active_facet_color, delaunay_color, voronoi_color, bkgnd_color;
    active_facet_color = CV_RGB( 255, 0, 0 );
    delaunay_color = CV_RGB( 0,0,0);
    voronoi_color = CV_RGB(0, 180, 0);
    bkgnd_color = CV_RGB(255,255,255);
    img = cvCreateImage( cvSize(rect.width,rect.height), 8, 3 );
    cvSet( img, bkgnd_color, 0 );
    cvNamedWindow( win, 1 );
    storage = cvCreateMemStorage(0);
    subdiv = init_delaunay( storage, rect );
    printf("Delaunay triangulation will be build now interactively.\n"
           "To stop the process, press any key\n\n");
    for( i = 0; i < 200; i++ )
    {
        CvPoint2D32f fp = cvPoint2D32f( (float)(rand()%(rect.width-10)+5),
                                        (float)(rand()%(rect.height-10)+5));
        locate_point( subdiv, fp, img, active_facet_color );
        cvShowImage( win, img );
        if( cvWaitKey( 100 ) >= 0 )
            break;
        cvSubdivDelaunay2DInsert( subdiv, fp );
        cvCalcSubdivVoronoi2D( subdiv );
        cvSet( img, bkgnd_color, 0 );
        draw_subdiv( img, subdiv, delaunay_color, voronoi_color );
        cvShowImage( win, img );
        if( cvWaitKey( 100 ) >= 0 )
            break;
    }
    cvSet( img, bkgnd_color, 0 );
    paint_voronoi( subdiv, img );
    cvShowImage( win, img );
    cvWaitKey(0);
    cvReleaseMemStorage( &storage );
    cvReleaseImage(&img);
    cvDestroyWindow( win );
}
int main( int argc, char** argv )
{
    run();
    return 0;
}
时间: 2024-07-29 16:12:02

cv1.2的相关文章

Oculus Home安装的一些坑和如何使用Oculus Rict CV1在unity中做开发。

Oculus Home的安装和如何使用Oculus Rift CV1在unity中开发使用 By:zscjob 最近因工作需要适配了一下Oculus CV1,真是踩坑无数.了解一下步骤, 1. 到oculus官方网站下载Oculus Home的Setup文件,目前官方下载地址:https://www.oculus.com/en-us/setup/.安装oculus Home 必须卸载之前的Oculus RunTime;如果你之前有安装过就需要卸载掉它, 2. 如果你下载链接打不开的话,你需要一个

cv1.5

使用均值漂移算法查找物体 #include <opencv2/opencv.hpp> using namespace cv; using namespace std; #include "Histogram1D.h" #include <iostream> #include <vector> #include "ContentFinder.h" #include "colorhistogram.h" int m

cv1.1

分水岭算法实现分割 分水岭分割方法,是一种基于拓扑理论的数学形态学的分割方法,其基本思想是把图像看作是测地学上的拓扑地貌,图像中每一点像素的灰度值表示该点的海拔高度,每一个局部极小值及其影响区域称为集水盆,而集水盆的边界则形成分水岭.分水岭的概念和形成可以通过模拟浸入过程来说明.在每一个局部极小值表面,刺穿一个小孔,然后把整个模型慢慢浸入水中,随着浸入的加深,每一个局部极小值的影响域慢慢向外扩展,在两个集水盆汇合处构筑大坝,即形成分水岭. 分水岭算法一般和区域生长法或聚类分析法相结合. 分水岭算

cv1.0

环境 VS2010UltimTrial1.iso                    http://pan.baidu.com/s/1dEL85kl VS2010UltimTrialCHS版注册码    YCFHQ-9DWCY-DKV88-T2TMH-G7BHP opencv-2.4.9.exe                              http://pan.baidu.com/s/1kVaVwoR 图片地址:                                  

python作业:购物车(第二周)

一.作业需求: 1.启动程序后,输入用户名密码后,如果是第一次登录,让用户输入工资,然后打印商品列表 2.允许用户根据商品编号购买商品 3.用户选择商品后,检测余额是否够,够就直接扣款,不够就提醒 4.可随时退出,退出时,打印已购买商品和余额 5.在用户使用过程中, 关键输出,如余额,商品已加入购物车等消息,需高亮显示 6.用户下一次登录后,输入用户名密码,直接回到上次的状态,即上次消费的余额什么的还是那些,再次登录可继续购买 7.允许查询之前的消费记录 二.购物车用户信息: {'name':

036-多控制器管理(2)-iOS笔记

学习目标 1.[掌握]控制器的创建方式 2.[了解]导航控制器的介绍 3.[掌握]代码创建导航控制器 4.[掌握]storyboard中创建导航控制器 5.[理解]控制器的生命周期 一.控制器的创建方式 视图控制器就是用来控制或者说管理界面(视图)的,换句话说界面长得丑与美由视图控制器说的算.每个视图控制器 (UIViewController)都有一个View属性来描述界面长什么样,上一篇文章中提到的设置窗口的根控制器其实就是会把视图控制器的里 View会添加在窗口上进行显示. UIStoryb

《zw版&#183;Halcon-delphi系列原创教程》 酸奶自动分类脚本(机器学习、人工智能)

<zw版·Halcon-delphi系列原创教程> 酸奶自动分类脚本(机器学习.人工智能) Halcon强大的图像处理能力,令人往往会忽视其更加彪悍的机器学习.人工智能.      至少,目前国内.海外机器学习.人工智能方面的学者,没有几位重视这块.      国外,可能是版权问题,毕竟,Halcon是售价高达数万欧元(不是人民币)的商业软件,而且主要用于自控.机器视觉等工业领域,而不是大学.      国内,可能是对于Halcon的了解不够.      其实,图像处理的核心,图像识别.分类,

Android的SQLite基本操作

涉及SQLite的增删改查,结果用log显示 package com.example.sqlconnecttest; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteDatabase.CursorFactory; import android.database.sqlite.SQLiteOpenHelper; im

[强烈推荐]ORACLE PL/SQL编程详解之七:程序包的创建与应用(聪明在于学习,天才在于积累!)

原文:[强烈推荐]ORACLE PL/SQL编程详解之七:程序包的创建与应用(聪明在于学习,天才在于积累!) [强烈推荐]ORACLE PL/SQL编程详解之七: 程序包的创建与应用(聪明在于学习,天才在于积累!) ——通过知识共享树立个人品牌.   继上七篇:            [推荐]ORACLE PL/SQL编程详解之一:PL/SQL 程序设计简介(千里之行,始于足下)            [顶]ORACLE PL/SQL编程详解之二:PL/SQL块结构和组成元素(为山九仞,岂一日之