3基于像素点的反向投影
根据输入的图像计算色相饱和度(hue-saturation)直方图,以网格形式显示,利用肤色模板直方图进行基于像素点的反向投影,在测试图像中找出该肤色模板直方图对应的区域,对应具体代码如下,其中方法一中反向映射函数是自己设计的,方法二中是调用opencv接口:
方法一代码:
#include <cv.h>
#include <highgui.h>
#include <cxcore.h>
#define HIST_H_RANGE 14
#define HIST_V_RANGE 16
void cvCalcMyBackProject(IplImage* *planes, IplImage *dst, const CvHistogram *hist)
{
uchar *H_value=0 , *S_value=0,*dst_ptr=0;
float bin_val = 0, max_value=0;
int intensity = 0;
int hist_h=0,hist_s=0;
cvGetMinMaxHistValue(hist, 0, &max_value, 0, 0);
for (int y=0; y < planes[0]->height;y++) {
H_value = (uchar *)(planes[0]->imageData+y * planes[0]->widthStep);
S_value = (uchar *)(planes[1]->imageData+y * planes[1]->widthStep);
dst_ptr= (uchar *)(dst->imageData + y * dst->widthStep);
for (int x = 0; x < planes[0]->width;x++) {
hist_h = (int)(H_value[x]/ HIST_H_RANGE);
hist_s = (int)(S_value[x]/ HIST_V_RANGE);
bin_val = cvQueryHistValue_2D(hist, hist_h, hist_s);
intensity = cvRound(bin_val * 255 / max_value);
dst_ptr[x] = intensity;
}
}
}
int main(int argc, char** argv) {
IplImage * src ,* dst, *src1;
if ((src = cvLoadImage("D:\\openvc_project\\opencv_project7\\hand_model.jpg", 1)) != 0) {
// Compute the HSV image, and decompose it into separate planes.
//
IplImage* hsv = cvCreateImage(cvGetSize(src), 8, 3);
cvCvtColor(src, hsv, CV_BGR2HSV);
IplImage* h_plane = cvCreateImage(cvGetSize(src), 8, 1);
IplImage* s_plane = cvCreateImage(cvGetSize(src), 8, 1);
IplImage* v_plane = cvCreateImage(cvGetSize(src), 8, 1);
IplImage* planes[] = { h_plane, s_plane };
cvCvtPixToPlane(hsv, h_plane, s_plane, v_plane, 0);
// Build the histogram and compute its contents.
//
int h_bins = HIST_H_RANGE, s_bins = HIST_V_RANGE;
CvHistogram* hist;
{
int hist_size[] = { h_bins, s_bins };
float h_ranges[] = { 0, 180 }; // hue is [0,180]
float s_ranges[] = { 0, 255 };
float* ranges[] = { h_ranges, s_ranges };
hist = cvCreateHist(
2,
hist_size,
CV_HIST_ARRAY,
ranges,
1
);
}
cvCalcHist(planes, hist, 0, 0);
//cvNormalizeHist(hist, 255.0);
src1 = cvLoadImage("D:\\openvc_project\\opencv_project7\\hand_test1.jpg", 1);
dst = cvCreateImage(cvGetSize(src1), 8, 1);
cvZero(dst);
cvSmooth(src1, src1, CV_GAUSSIAN, 3, 3);
cvSmooth(src1, src1, CV_GAUSSIAN, 3, 3);//平滑处理
IplImage* hsv1 = cvCreateImage(cvGetSize(src1), 8, 3);
cvCvtColor(src1, hsv1, CV_BGR2HSV);
IplImage* h_plane1 = cvCreateImage(cvGetSize(src1), 8, 1);
IplImage* s_plane1 = cvCreateImage(cvGetSize(src1), 8, 1);
IplImage* v_plane1 = cvCreateImage(cvGetSize(src1), 8, 1);
IplImage* planes1[] = { h_plane1, s_plane1 };
cvCvtPixToPlane(hsv1, h_plane1, s_plane1, v_plane1, 0);
cvCalcMyBackProject(planes1, dst, hist);//目标图像,原图像,模板直方图
cvThreshold(dst, dst, 65, 255, CV_THRESH_BINARY);
cvNamedWindow("Source", 0);
cvShowImage("Source", src);
cvNamedWindow("result", 0);
cvSaveImage("D:\\openvc_project\\opencv_project7\\result.jpg", dst);
cvShowImage("result", dst);
cvWaitKey(0);
cvReleaseImage(&src);
cvReleaseImage(&dst);
cvReleaseImage(&hsv);
cvReleaseImage(&h_plane);
cvReleaseImage(&s_plane);
cvReleaseImage(&v_plane);
cvDestroyAllWindows();
}
}
方法二代码:
#include <cv.h>
#include <highgui.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
using namespace std;
int main(int argc, char* argv[])
{
IplImage* src1,*src2,*Imask,*hsv1,*hsv2; //源图像 HSV格式图像
if (!(src1 = cvLoadImage("D:\\Template\\OpenCV\\Template48_hue-saturation_BackProjection\\Debug\\hand1.jpg")))
return -1;
if (!(src2 = cvLoadImage("D:\\Template\\OpenCV\\Template48_hue-saturation_BackProjection\\Debug\\hand3.jpg")))
return -2;
//此处调入图像掩码应为单通道
if (!(Imask = cvLoadImage("D:\\Template\\OpenCV\\Template48_hue-saturation_BackProjection\\Debug\\Imask.jpg", CV_LOAD_IMAGE_GRAYSCALE)))
return -3;
cvXorS(Imask, cvScalar(255), Imask); //掩码图像按位异或,求反生成新的掩码处理模板
cvSet(src1, cvScalarAll(0), Imask);
hsv1 = cvCreateImage(cvGetSize(src1), src1->depth, src1->nChannels);
hsv2 = cvCreateImage(cvGetSize(src2), src2->depth, src2->nChannels);
cvCvtColor(src1, hsv1, CV_BGR2HSV); //源图像->HSV格式图像
cvCvtColor(src2, hsv2, CV_BGR2HSV); //源图像->HSV格式图像
//反向投影图像
IplImage *back_projection = cvCreateImage(cvGetSize(src2), IPL_DEPTH_8U, 1);
//色调(hue) 饱和度(saturation) 明度(value)
IplImage *h_plane_1 = cvCreateImage(cvSize(hsv1->width, hsv1->height), IPL_DEPTH_8U, 1);
IplImage *s_plane_1 = cvCreateImage(cvSize(hsv1->width, hsv1->height), IPL_DEPTH_8U, 1);
IplImage *v_plane_1 = cvCreateImage(cvSize(hsv1->width, hsv1->height), IPL_DEPTH_8U, 1);
IplImage *h_plane_2 = cvCreateImage(cvSize(hsv2->width, hsv2->height), IPL_DEPTH_8U, 1);
IplImage *s_plane_2 = cvCreateImage(cvSize(hsv2->width, hsv2->height), IPL_DEPTH_8U, 1);
IplImage *v_plane_2 = cvCreateImage(cvSize(hsv2->width, hsv2->height), IPL_DEPTH_8U, 1);
IplImage *planes1[] = { h_plane_1, s_plane_1 }; //色相饱和度数组
IplImage *planes2[] = { h_plane_2, s_plane_2 }; //色相饱和度数组
cvCvtPixToPlane(hsv1, h_plane_1, s_plane_1, v_plane_1, NULL); //图像分割
cvCvtPixToPlane(hsv2, h_plane_2, s_plane_2, v_plane_2, NULL); //图像分割
//cvSplit(hsv, h_plane, s_plane, v_plane, NULL);
int h_bins = 30, s_bins = 32;
//建立直方图
CvHistogram *hist_model,*hist_test;
int hist_size[] = { h_bins, s_bins }; //对应维数包含bins个数的数组
float h_ranges[] = { 0, 180 }; //H通道划分范围 饱和度0-180
float s_ranges[] = { 0, 255 }; //S通道划分范围
float* ranges[] = { h_ranges, s_ranges }; //划分范围数对, ****均匀bin,range只要最大最小边界
//创建直方图 (维数,对应维数bins个数,密集矩阵方式存储,划分范围数对,均匀直方图)
hist_model = cvCreateHist(2, hist_size, CV_HIST_ARRAY, ranges, 1);
hist_test = cvCreateHist(2, hist_size, CV_HIST_ARRAY, ranges, 1);
cvCalcHist(planes1, hist_model, 0, 0); //计算直方图(图像,直方图结构,不累加,掩码)
cvCalcHist(planes2, hist_test, 0, 0); //计算直方图(图像,直方图结构,不累加,掩码)
//cvNormalizeHist(hist_model, 1.0); //直方图归一化
//cvNormalizeHist(hist_test, 1.0); //直方图归一化
//绘制可视化直方图
int scale = 10;
IplImage* hist_img_model = cvCreateImage(cvSize(h_bins*scale, s_bins*scale), 8, 3); //300*320
IplImage* hist_img_test = cvCreateImage(cvSize(h_bins*scale, s_bins*scale), 8, 3); //300*320
cvZero(hist_img_model);
cvZero(hist_img_test);
//以小灰度块填充图像
float max_value_model = 0;
float max_value_test = 0;
cvGetMinMaxHistValue(hist_model, NULL, &max_value_model, NULL, NULL); //获取直方图最大值
cvGetMinMaxHistValue(hist_test, NULL, &max_value_test, NULL, NULL); //获取直方图最大值
for (int h = 0; h < h_bins; h++)
{
for (int s = 0; s < s_bins; s++)
{
float bin_val_model = cvQueryHistValue_2D(hist_model, h, s); //获取直方图相应bin中的浮点数
float bin_val_test = cvQueryHistValue_2D(hist_test, h, s); //获取直方图相应bin中的浮点数
int intensity1 = cvRound(bin_val_model * 255 / max_value_model);//映射到255空间
int intensity2 = cvRound(bin_val_test * 255 / max_value_test); //归一后太小
cvRectangle(hist_img_model, cvPoint(h*scale, s*scale),
cvPoint((h + 1)*scale - 1, (s + 1)*scale - 1),
CV_RGB(intensity1, intensity1, intensity1), CV_FILLED);
cvRectangle(hist_img_test, cvPoint(h*scale, s*scale),
cvPoint((h + 1)*scale - 1, (s + 1)*scale - 1),
CV_RGB(intensity2, intensity2, intensity2), CV_FILLED);
}
}
cvCalcBackProject(planes2, back_projection, hist_model); //像素点的反射投影
cvNamedWindow("Mask", 1);
cvNamedWindow("Model", 1);
cvNamedWindow("Test", 1);
cvNamedWindow("HIST_Model", 1);
cvNamedWindow("HIST_Test", 1);
cvNamedWindow("BACK_Projection", 1);
cvShowImage("Mask", Imask);
cvShowImage("Model", src1);
cvShowImage("Test", src2);
cvShowImage("HIST_Model", hist_img_model);
cvShowImage("HIST_Test", hist_img_test);
cvShowImage("BACK_Projection", back_projection);
cvWaitKey(0);
//system("pause");
cvReleaseHist(&hist_model);
cvReleaseHist(&hist_test);
cvReleaseImage(&Imask);
cvReleaseImage(&src1);
cvReleaseImage(&src2);
cvReleaseImage(&hist_img_model);
cvReleaseImage(&hist_img_test);
cvReleaseImage(&h_plane_1);
cvReleaseImage(&s_plane_1);
cvReleaseImage(&v_plane_1);
cvReleaseImage(&h_plane_2);
cvReleaseImage(&s_plane_2);
cvReleaseImage(&v_plane_2);
cvReleaseImage(&back_projection);
cvDestroyAllWindows();
}