17模板匹配寻找手掌区域

17模板匹配寻找手掌区域

寻找手掌区域,利用模板匹配策略,通过cvMatchTemplate()函数找出手掌区域,本例中,结果一在main()函数中调用了Find_Hand_Region()函数去除了不相关区域,结果二未调用,具体代码如下:


#include <cv.h>
#include <highgui.h>  
#include <stdlib.h>  
#include <stdio.h> 
#include <math.h>

using namespace std;

CvPoint Current_Point;              //全局变量才可通过普通成员引用变更其值

bool find_point(IplImage *img, char val);
void Create_Imask(IplImage *src, IplImage *dst);
void Create_RIO(IplImage *dst, IplImage *match_temp);
void Find_Hand_Region(IplImage *model, IplImage *test, IplImage *mask, IplImage *dst);

int main(int argc, char* argv[])
{
    IplImage *src1, *src2, *Imask;      //肤色模板 视频流 手掌掩码
    IplImage *dst, *match_temp;         //肤色区域图像 模板匹配图像                 
    CvCapture* capture;

    if (!(src1 = cvLoadImage("D:\\Template\\OpenCV\\Template60_Hand_Track _Match_Template\\Debug\\hand.jpg")))
        return -1;      //肤色模板
    if (!(match_temp = cvLoadImage("D:\\Template\\OpenCV\\Template60_Hand_Track _Match_Template\\Debug\\match_temp.jpg")))
        return -2;      //匹配模板图像

    if (argc == 1)   //此处代码是做一个判断,有摄像头设备则读入摄像头设备的图像信息,没有则播放本地视频文件
        capture = cvCreateCameraCapture(0);
    else
        return -3;  //没有摄像头

    src2 = cvQueryFrame(capture);                                           //获取摄像头图像帧
    Imask = cvCreateImage(cvGetSize(src1), src1->depth, 1);                 //手掌掩码图像
    dst = cvCreateImage(cvGetSize(src2), IPL_DEPTH_8U, 1);                  //处理后的反射投影      

    int result_width = src2->width - match_temp->width + 1;
    int result_height = src2->height - match_temp->height + 1;
    CvSize result_size = cvSize(result_width, result_height);
    IplImage *result = cvCreateImage(result_size, IPL_DEPTH_32F, 1);

    Create_Imask(src1, Imask);                              //创建肤色掩码图像

    cvNamedWindow("Match_Template", 1);
    cvNamedWindow("BACK_Projection", 1);
    cvNamedWindow("Destination", 1);
    cvNamedWindow("Hand", 1);
    cvNamedWindow("SQDIFF_NORMED", 1); 

    cvShowImage("Match_Template", match_temp);

    while (1)
    {
        src2 = cvQueryFrame(capture);

        //Find_Hand_Region(src1, src2, Imask, dst);         //寻找肤色区域

        cvMatchTemplate(src2, match_temp, result, 1);       //模板匹配
        //cvNormalize(result, result, 1, 0, CV_MINMAX);     //元素规范化 平移缩放返回值[0,1]

        if (!src2)
            break;
        cvShowImage("SQDIFF_NORMED", result);
        char c = cvWaitKey(32);
        if (c == 27) 
            break;
    }

    cvWaitKey();

    cvReleaseCapture(&capture);

    cvReleaseImage(&src1);
    cvReleaseImage(&Imask);
    cvReleaseImage(&dst);
    cvReleaseImage(&match_temp);
    cvReleaseImage(&result);

    cvDestroyAllWindows();
}

/******************遍历图像-指针算法********************/
bool find_point(IplImage *img, char val)
{
    char* ptr = NULL;

    if (img->nChannels == 1)
    {
        ptr = img->imageData;
        if (ptr != NULL)
        {
            for (int i = 0; i < img->height; i++)       //矩阵指针行寻址
            {
                ptr = (img->imageData + i*(img->widthStep));   //i 行 j 列

                for (int j = 0; j < img->width; j++)    //矩阵指针列寻址
                {
                    if (ptr[j] == val)                  //判断某点像素是否为255
                    {
                        Current_Point.x = j;            
                        Current_Point.y = i;
                        return true;
                    }
                }
            }
        }
    }
    return false;
}

void Create_Imask(IplImage *src, IplImage *dst)
{
    int Last_Area = 0;                          //上一个区域面积       
    int Current_Area = 0;                       //当前区域面积
    int threshold_type = CV_THRESH_BINARY;      //阈值类型
    CvPoint Last_Point;                         //值为255点的上一点
    CvConnectedComp comp;                       //被填充区域统计属性
    IplImage *gray, *threshold, *temp,*open;    //灰度图像

    Last_Point = cvPoint(0, 0);         //初始化上一点
    Current_Point = cvPoint(0, 0);      //初始化当前点

    gray = cvCreateImage(cvGetSize(src), src->depth, 1);
    threshold = cvCreateImage(cvGetSize(src), src->depth, 1);
    temp = cvCreateImage(cvGetSize(src), src->depth, 1);
    open = cvCreateImage(cvGetSize(src), src->depth, 1);

    cvCvtColor(src, gray, CV_BGR2GRAY); //源图像->灰度图像
    //二值阈值化
    cvThreshold(gray, threshold, 100, 255, threshold_type);     
    //开运算,去除小亮区域,其他联结 NULL:3*3参考点为中心的核
    cvMorphologyEx(threshold, open, temp, NULL, CV_MOP_OPEN, 1);

    cvNamedWindow("肤色模板", 1);
    cvNamedWindow("肤色掩码", 1);
    cvShowImage("肤色模板", src);
    cvShowImage("肤色掩码", dst);

    //漫水填充 获得手掌掩码
    cvCopy(open, dst);               //复制生成手掌掩码
    do
    {
        if (find_point(dst, 255))    //找像素值为255的像素点
        {

            cout << " X: " << Current_Point.x << " Y: " << Current_Point.y << endl;

            cvFloodFill(dst, Current_Point, cvScalar(100), cvScalar(0), cvScalar(0),
                &comp, 8 | CV_FLOODFILL_FIXED_RANGE);       //对值为255的点进行漫水填充,值100
            Current_Area = comp.area;                       //当前区域面积

            if (Last_Area<Current_Area)                     //当前区域大于上一区域,上一区域清0
            {
                if (Last_Area>0)
                    cvFloodFill(dst, Last_Point, cvScalar(0), cvScalar(0), cvScalar(0),
                    &comp, 8 | CV_FLOODFILL_FIXED_RANGE);   //上一区域赋值0
                cvShowImage("肤色掩码", dst);
                cvWaitKey(500);

                Last_Area = Current_Area;                               //当前区域赋值给上一区域
                Last_Point = Current_Point;                             //当前点赋值给上一点
            }
            else                                            //当前区域小于等于上一区域,当前区域清0
            {
                if (Current_Area>0)
                    cvFloodFill(dst, Current_Point, cvScalar(0), cvScalar(0), cvScalar(0),
                    &comp, 8 | CV_FLOODFILL_FIXED_RANGE);   //当前区域赋值0
                cvShowImage("肤色掩码", dst);
                cvWaitKey(500);
            }
        }
        else                                                //最后剩余的最大区域赋值255
        {
            cvFloodFill(dst, Last_Point, cvScalar(255), cvScalar(0), cvScalar(0), &comp, 8 | CV_FLOODFILL_FIXED_RANGE);
            cvShowImage("肤色掩码", dst);
            cvWaitKey(500);
            //上一区域赋值0
            break;
        }
    } while (true);

    //cvSaveImage("Imask.jpg", dst);

    cvReleaseImage(&gray);
    cvReleaseImage(&threshold);
    cvReleaseImage(&temp);
    cvReleaseImage(&open);
}

void Find_Hand_Region(IplImage *model, IplImage *test, IplImage *mask, IplImage *dst)
{

    int threshold_type = CV_THRESH_BINARY;      //阈值类型

    //临时图像  反向投影图像
    IplImage *temp = cvCreateImage(cvSize(model->width, model->height), IPL_DEPTH_8U, 1);
    IplImage *back_projection = cvCreateImage(cvSize(test->width, test->height), IPL_DEPTH_8U, 1);
    //RGB
    IplImage *r_plane_1 = cvCreateImage(cvSize(model->width, model->height), IPL_DEPTH_8U, 1);
    IplImage *g_plane_1 = cvCreateImage(cvSize(model->width, model->height), IPL_DEPTH_8U, 1);
    IplImage *b_plane_1 = cvCreateImage(cvSize(model->width, model->height), IPL_DEPTH_8U, 1);

    IplImage *r_plane_2 = cvCreateImage(cvSize(test->width, test->height), IPL_DEPTH_8U, 1);
    IplImage *g_plane_2 = cvCreateImage(cvSize(test->width, test->height), IPL_DEPTH_8U, 1);
    IplImage *b_plane_2 = cvCreateImage(cvSize(test->width, test->height), IPL_DEPTH_8U, 1);

    IplImage *planes1[] = { r_plane_1, g_plane_1, b_plane_1 };          //色相饱和度数组
    IplImage *planes2[] = { r_plane_2, g_plane_2, b_plane_2 };          //色相饱和度数组

    cvCvtPixToPlane(model, b_plane_1, g_plane_1, r_plane_1, NULL);      //图像分割
    cvCvtPixToPlane(test, b_plane_2, g_plane_2, r_plane_2, NULL);       //图像分割

    int r_bins = 32, g_bins = 32, b_bins = 32;

    //建立直方图
    CvHistogram *hist_model, *hist_test;

    int hist_size[] = { r_bins, g_bins, b_bins };       //对应维数包含bins个数的数组
    float r_ranges[] = { 0, 255 };                      //R通道划分范围 
    float g_ranges[] = { 0, 255 };                      //G通道划分范围
    float b_ranges[] = { 0, 255 };                      //R通道划分范围 
    float* ranges[] = { r_ranges, g_ranges, b_ranges }; //划分范围数对, ****均匀bin,range只要最大最小边界

    //创建直方图 (维数,对应维数bins个数,密集矩阵方式存储,划分范围数对,均匀直方图)
    hist_model = cvCreateHist(3, hist_size, CV_HIST_ARRAY, ranges, 1);
    hist_test = cvCreateHist(3, hist_size, CV_HIST_ARRAY, ranges, 1);

    cvCalcHist(planes1, hist_model, 0, mask);   //计算直方图(图像,直方图结构,不累加,掩码)
    cvCalcHist(planes2, hist_test, 0, 0);       //计算直方图(图像,直方图结构,不累加,掩码)

    //cvNormalizeHist(hist_model, 1.0);         //直方图归一化
    //cvNormalizeHist(hist_test, 1.0);          //直方图归一化

    //像素点的反射投影 创建测试hist的图像数组 结果图像 模板hist
    cvCalcBackProject(planes2, back_projection, hist_model);

    cvSmooth(back_projection, dst, CV_MEDIAN, 11);  //中值滤波 去除椒盐噪声

    //开运算,去除小亮区域,其他联结 NULL:3*3参考点为中心的核
    cvMorphologyEx(dst, dst, temp, NULL, CV_MOP_OPEN, 1);

    cvThreshold(dst, dst, 0, 255, threshold_type);  //二值阈值化

    //边缘检测   src dst 边缘连接 边缘初始分割 核
    //cvCanny(dst, dst,90,180,3);
    //得到手掌轮廓 绘制轮廓线
    //getContoursByC(dst, dst);             

    cvShowImage("BACK_Projection", back_projection);
    cvShowImage("Destination", dst);

    cvXorS(dst, cvScalar(255), dst);        //掩码图像按位异或,求反生成新的掩码处理模板
    cvSet(test, cvScalarAll(0), dst);
    cvShowImage("Hand", test);
    //cvSaveImage("DST.jpg", dst);

    cvReleaseHist(&hist_model);
    cvReleaseHist(&hist_test);

    cvReleaseImage(&back_projection);
    cvReleaseImage(&temp);
    cvReleaseImage(&r_plane_1);
    cvReleaseImage(&g_plane_1);
    cvReleaseImage(&b_plane_1);
    cvReleaseImage(&r_plane_2);
    cvReleaseImage(&g_plane_2);
    cvReleaseImage(&b_plane_2);
}

结果如下:
这里写图片描述
这里写图片描述

猜你喜欢

转载自blog.csdn.net/z827997640/article/details/79841431