为什么美颜摄像这么简单的功能,OpenCV这个开源项目网上很少有代码呢?对于在windows平台下,生成h264视频流也比价麻烦,没有现成的api可以使用,需要借助MinGw编译libx264,或者ffmpeg才能使用。

最近有个小需求,要推送直播视频流,我在网上查了一下有live555或者用librtmp来推送,但是前者还需要修改源代码,也挺麻烦的,现在先做到了下面几个步骤:

1.OpenCV捕捉摄像头的图像

2.进行识别需要美颜的部分(人脸识别,肤色识别)

3.进行美颜(提升亮度,直方图均衡,滤波)

4.生成YUV视频

5.生成h264

现在用librtmp时候,出现了

ERROR:RTMP_Connect0,failed to connect socket,10061(unknow error)

不知道是咋回事了,怀疑是1935端口被禁,但是一时半会儿不知道咋弄。

主要功能代码:

/** Global variables */
//-- Note, either copy these two files from opencv/data/haarscascades to your current folder, or change these locations
string face_cascade_name = "haarcascade_frontalface_alt.xml"; CascadeClassifier face_cascade;
CascadeClassifier eyes_cascade;
string window_name_onlyface = "Capture - only Face";
string window_name_face = "Capture - Face "; /**
* @function detectAndDisplay
*/
void detectAndenhance( Mat &frame )
{
std::vector<Rect> faces;
Mat frame_gray;
Mat hatAlpha; //hatAlpha = imread("2.png",-1);//圣诞帽的图片 cvtColor( frame, frame_gray, COLOR_BGR2GRAY );
//equalizeHist( frame_gray, frame_gray );
//-- Detect faces
face_cascade.detectMultiScale( frame_gray, faces, 1.1, 2, 0|CV_HAAR_SCALE_IMAGE, Size(30, 30) ); for( size_t i = 0; i < faces.size(); i++ )
{
Rect face(faces[i].x,faces[i].y,faces[i].x + faces[i].width,faces[i].y + faces[i].height);
cvSetImageROI(&IplImage(frame),face); // Do the porcess
blur(frame,frame,Size(7,7),Point(-1,-1));
//////////////////////////////////////////////
cvResetImageROI( &IplImage(frame) );
Point center( faces[i].x + faces[i].width/2, faces[i].y + faces[i].height/2 );
ellipse( frame, center, Size( faces[i].width/2, faces[i].height/2), 0, 0, 360, Scalar( 255, 0, 255 ), 2, 8, 0 ); // line(frame,Point(faces[i].x,faces[i].y),center,Scalar(255,0,0),5); Mat faceROI = frame_gray( faces[i] );
std::vector<Rect> eyes; imshow( window_name_onlyface, faceROI ); }
//-- Show what you got
imshow( window_name_face, frame );
//imwrite("merry christmas.jpg",frame);
} /** @函数 detectAndDisplay */
void detectAndDisplay( Mat frame )
{
std::vector<Rect> faces;
Mat frame_gray; cvtColor( frame, frame_gray, CV_BGR2GRAY );
equalizeHist( frame_gray, frame_gray ); //-- 多尺寸检测人脸
face_cascade.detectMultiScale( frame_gray, faces, 1.1, 2, 0|CV_HAAR_SCALE_IMAGE, Size(30, 30) ); for( int i = 0; i < faces.size(); i++ )
{
Point center( faces[i].x + faces[i].width*0.5, faces[i].y + faces[i].height*0.5 );
ellipse( frame, center, Size( faces[i].width*0.5, faces[i].height*0.5), 0, 0, 360, Scalar( 255, 0, 255 ), 4, 8, 0 ); Mat faceROI = frame_gray( faces[i] );
std::vector<Rect> eyes; //-- 在每张人脸上检测双眼
eyes_cascade.detectMultiScale( faceROI, eyes, 1.1, 2, 0 |CV_HAAR_SCALE_IMAGE, Size(30, 30) ); for( int j = 0; j < eyes.size(); j++ )
{
Point center( faces[i].x + eyes[j].x + eyes[j].width*0.5, faces[i].y + eyes[j].y + eyes[j].height*0.5 );
int radius = cvRound( (eyes[j].width + eyes[i].height)*0.25 );
circle( frame, center, radius, Scalar( 255, 0, 0 ), 4, 8, 0 );
}
}
//-- 显示结果图像
imshow( window_name_face, frame );
} // add by shiter 2016/3/3 Mat equalizeChannelHist(const Mat & inputImage)
{
if( inputImage.channels() >= 3 )
{
vector<Mat> channels;
split(inputImage, channels); Mat B,G,R; equalizeHist( channels[0], B );
equalizeHist( channels[1], G );
equalizeHist( channels[2], R ); vector<Mat> combined;
combined.push_back(B);
combined.push_back(G);
combined.push_back(R); Mat result;
merge(combined, result); return result;
}
else{return inputImage;} return inputImage;
} Mat equalizeIntensityHist(const Mat & inputImage)
{
if(inputImage.channels() >= 3)
{
Mat ycrcb; cvtColor(inputImage, ycrcb, COLOR_BGR2YCrCb); vector<Mat> channels;
split(ycrcb, channels); equalizeHist(channels[0], channels[0]); Mat result;
merge(channels,ycrcb); cvtColor(ycrcb, result, COLOR_YCrCb2BGR); return result;
} return Mat();
} //皮肤检测,并针对皮肤进行增强,模糊
void MySkinEnhance(Mat &frame)
{
Mat input_image =frame;
Mat output_mask;
Mat output_image;
Mat mask;
//肤色椭圆
/*椭圆皮肤模型*/
Mat skinCrCbHist = Mat::zeros(Size(256, 256), CV_8UC1);
ellipse(skinCrCbHist, Point(113, 155.6), Size(23.4, 15.2), 43.0, 0.0, 360.0, Scalar(255, 255, 255), -1); Mat element = getStructuringElement(MORPH_RECT, Size(3, 3), Point(-1, -1) ); if(input_image.empty())
return ; Mat ycrcb_image;
output_mask = Mat::zeros(input_image.size(), CV_8UC1);
cvtColor(input_image, ycrcb_image, CV_BGR2YCrCb); //首先转换成到YCrCb空间 for(int i = 0; i < input_image.rows; i++) //利用椭圆皮肤模型进行皮肤检测
{
uchar* p = (uchar*)output_mask.ptr<uchar>(i);
Vec3b* ycrcb = (Vec3b*)ycrcb_image.ptr<Vec3b>(i);
for(int j = 0; j < input_image.cols; j++)
{
if(skinCrCbHist.at<uchar>(ycrcb[j][1], ycrcb[j][2]) > 0)
p[j] = 255;
}
} //morphologyEx(output_mask,output_mask,MORPH_CLOSE,element); //output_mask.setTo(0); dilate(output_mask,output_mask,Mat(32,32,CV_8U),Point(-1,-1),2);
//imwrite("dilate.jpg",dst);
// output_image.setTo(0);
input_image.copyTo(output_image, output_mask); Mat enhance = output_image;
medianBlur(output_image,enhance,11);
//blur(enhance,enhance,Size(4,4),Point(-1,-1),4);
imshow("blur face",enhance);
for(int i = 0; i < output_image.rows; i++) //
{
uchar* p = (uchar*)output_mask.ptr<uchar>(i); for(int j = 0; j < output_image.cols; j++)
{
if((enhance.at<Vec3b>(i,j)[0] < 50) && (enhance.at<Vec3b>(i,j)[1] < 50)&& (enhance.at<Vec3b>(i,j)[2] < 50) )
{
//不是纯黑的 }
else
{ frame.at<Vec3b>(i,j)[0] = enhance.at<Vec3b>(i,j)[0]; frame.at<Vec3b>(i,j)[1] = enhance.at<Vec3b>(i,j)[1];
frame.at<Vec3b>(i,j)[2] = enhance.at<Vec3b>(i,j)[2];
}
}
}
// 图像融合
//addWeighted(input_image, 0.95, enhance, 0.05, 0.0, input_image);
imshow("ouput image",frame); } //提高亮度对比度
void highlight(Mat &frame)
{
Mat src,dst;
double alpha =1.5;
double beta = 20; src = frame;
if(!src.data)
{
cout<<"Failed to load image!"<<endl;
return ;
} //dst = Mat::zeros(src.size(),src.type());
for (int i = 0;i<src.rows;++i)
{
//uchar* inData=src.ptr<uchar>(i); for(int j= 0;j<src.cols;++j)
{ /*src.at<Vec3b>(i,j)[0] = saturate_cast<uchar>(src.at<Vec3b>(i,j)[0]*alpha+beta);
src.at<Vec3b>(i,j)[1] = saturate_cast<uchar>(src.at<Vec3b>(i,j)[1]*alpha+beta);
src.at<Vec3b>(i,j)[2] = saturate_cast<uchar>(src.at<Vec3b>(i,j)[2]*alpha+beta); */
//上面的效率低,下面的有越界
src.at<Vec3b>(i,j)[0] = (src.at<Vec3b>(i,j)[0]*alpha+beta);
src.at<Vec3b>(i,j)[1] = (src.at<Vec3b>(i,j)[1]*alpha+beta);
src.at<Vec3b>(i,j)[2] = (src.at<Vec3b>(i,j)[2]*alpha+beta); }
} namedWindow("Handled Image");
imshow("Handled Image",src);
//waitKey();
}

实现效果:实时实现的话我只加了肤色检测和简单的滤波,具体美化还需要进一步调试

参数和算法 的组合可以在代码中调整参数实现,可以把膨胀的参数调大一点这个整个人脸就差不多可以经过肤色检测全部搞出来。

完整工程代码:http://download.csdn.net/detail/wangyaninglm/9453146

参考文献:

肤色检测:http://blog.csdn.net/yangtrees/article/details/8269984

人像优化:http://blog.csdn.net/u011630458/article/details/46275469

肤色检测:http://blog.csdn.net/wj080211140/article/details/23384927

改变对比读:http://blog.csdn.net/ubunfans/article/details/24373811

直接推送直播流:http://blog.csdn.net/wangyaninglm/article/details/51056101

OpenCV实时美颜摄像并生成H264视频流的更多相关文章

  1. 基于GPUImage的实时美颜滤镜

    1.背景 前段时间由于项目需求,做了一个基于GPUImage的实时美颜滤镜.现在各种各样的直播.视频App层出不穷,美颜滤镜的需求也越来越多.为了回馈开源,现在我把它放到了GitHub https:/ ...

  2. IOS-实战分享:实时美颜滤镜是怎样炼成的

    作者:琨君 原文链接:http://www.jianshu.com/p/945fc806a9b4 本文获作者授权转载 背景 前段时间由于项目需求,做了一个基于GPUImage的实时美颜滤镜.现在各种各 ...

  3. 从wireshark数据中分析rtmp协议,并提取出H264视频流

    我写的小工具 rtmp_parse.exe 使用用法如先介绍下: -sps  [文件路径] 解析 sps 数据 文件当中的内容就是纯方本的hexstring: 如 42 E0 33 8D 68 05 ...

  4. 在iOS平台使用ffmpeg解码h264视频流(转)

    在iOS平台使用ffmpeg解码h264视频流,有需要的朋友可以参考下. 对于视频文件和rtsp之类的主流视频传输协议,ffmpeg提供avformat_open_input接口,直接将文件路径或UR ...

  5. Android平台Camera实时滤镜实现方法探讨(十一)--实时美颜滤镜

    上一章完毕了对图片的磨皮处理.经过简单算法流程优化,能够达到非常快的速度.可是不能用于实时美颜.经实验,若採用仅仅处理Y信号的方案.半径极限大约是5-10,超过10则明显感受到卡顿.但对于1920X1 ...

  6. 在iOS平台使用ffmpeg解码h264视频流

    来源:http://www.aichengxu.com/view/37145 在iOS平台使用ffmpeg解码h264视频流,有需要的朋友可以参考下. 对于视频文件和rtsp之类的主流视频传输协议,f ...

  7. 利用flask将opencv实时视频流输出到浏览器

    opencv通过webcam可以获取本地实时视频流,但是如果需要将视频流共享给其他机器调用,就可以将利用flask框架构建一个实时视频流服务器,然后其他机器可以通过向这个服务器发送请求来获取这台机器上 ...

  8. 基于OpenCV 的美颜相机推送直播流

    程序流程: 1.图像采集 先从opencv(2.4.10版本)采集回来摄像头的图像,是一帧一帧的 每一帧图像是一个矩阵,opencv中的mat 数据结构. 2.人脸的美化 人脸美化,我们用的皮肤检测, ...

  9. 利用FFmpge进行视频压缩(从图像到H264视频流)

    对于FFmpeg相信做视频或图像处理这一块的都不会陌生,在网上也能找到非常多相关的代码.但因为版本号不同等原因.往往找到的代码都是须要自行改动才干够用,为此本人希望能尽绵薄之力,将开发包和自行编写的代 ...

随机推荐

  1. PKUWC 2018 滚粗记

    day0 上午居然考了一场考试,大爆炸,攒了一波RP,下午也没有心思去落实题目,而是一心去搞颓废,到了晚上看时间还早,于是就看了一波上午考试的Solution,懵逼.jpg day1 上午考数学,前一 ...

  2. [暑假的bzoj刷水记录]

    (这篇我就不信有网站来扣) 这个暑假打算刷刷题啥的 但是写博客好累啊  堆一起算了 隔一段更新一下.  7月27号之前刷的的就不写了 , 写的累 代码不贴了,可以找我要啊.. 2017.8.27upd ...

  3. bzoj 3631: [JLOI2014]松鼠的新家

    Description 松鼠的新家是一棵树,前几天刚刚装修了新家,新家有n个房间,并且有n-1根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的.天哪,他居然真的住在"树&q ...

  4. [bzoj4883][Lydsy2017年5月月赛]棋盘上的守卫

    来自FallDream的博客,未经允许,请勿转载, 谢谢. 在一个n*m的棋盘上要放置若干个守卫.对于n行来说,每行必须恰好放置一个横向守卫:同理对于m列来说,每列 必须恰好放置一个纵向守卫.每个位置 ...

  5. spine - unity3D(摘自博主softimagewht)

    摘自:(博主 http://www.cnblogs.com/softimagewht/p/4149118.html) //skeletonDataSkeletonAnimation skeletonA ...

  6. PostgreSQL 查看单表大小

    1. 在数据库中查单个表 select pg_size_pretty(pg_relation_size('table_name')); 2. 查出并按大小排序 SELECT table_schema ...

  7. Linux学习之CentOS(五)--CentOS下VMware-Tools安装

    已经进入到了Linux学习之CentOS的第六篇随笔了,所以这里就介绍一下VMware-Tools的安装. VMware-Tools的安装 VMware-Tools 主要的功能就是让用户在虚拟机和真实 ...

  8. js时间比较,获取n天后(前)的日期

    <html> <head> <meta http-equiv="Content-Type" content="textml; charset ...

  9. return、break和continue

    return.break和continue 这三个关键字有一个共同点,那就是读能让后面的语句不执行,不同的地方就是挑的距离不一样. return很强大,如果一个函数中有一个return,并且执行了,那 ...

  10. day0203 XML 学习笔记

    day02, 03 1. xml语言和作用 2. xml语法详解 2.1 xml 语法声明 2.1.1 encoding 属性 2.1.2 standalone 属性 2.2 xml 元素(Eleme ...