OpenCV-证件照蓝底换成白底(或其他颜色如红色)

来源:互联网 发布:excel纸上数据录入技巧 编辑:程序博客网 时间:2024/05/16 19:16

今天刚好老师要办点事情,老师唯一的一张证件照是蓝色的,但是需要的底色是白色的,于是乎,好久不折腾的PS也忘记了,还好旁边的刚来的小学弟懂一点,

在那里慢慢的帮老师一点点的处理,PS在边缘的地方效果还真不咋地,确实是一门技术活。

于是我就想OpenCV能不能实现呢?一搜百度第一篇就是,但是人家转成红色,然后我又对HSV颜色空间不是很懂,最后在一个学习群里

博主的链接如下:http://blog.csdn.net/jiang111_111shan/article/details/462

但是文中未对HSV那一块做出解释,可能是我太菜了奋斗

贴出去问了下,一位优秀的本科生帮我清晰解答了,汗颜大哭

主要步骤为:

1.把RGB图像转换到HSV空间

2.取背景的一小块20*20,计算蓝色背景的平均色调和饱和度

3.设置阈值,取出蓝色背景替换为红色背景

4.把HSV图像转换会RGB空间

5.滤波器去除边缘效应

具体代码为:

// change_color.cpp : 定义控制台应用程序的入口点。//证件照从蓝色底换成红色底//#include "stdafx.h"#include <iostream>#include <opencv2\core\core.hpp>#include <opencv2\highgui\highgui.hpp>#include <opencv2\imgproc\imgproc.hpp>using namespace cv;using namespace std;int main(){char *origin="Original";char *window="Image";char *str="C:\\Users\\ltc\\Desktop\\nihao.jpg";namedWindow(origin,1);namedWindow(window,1);Mat image=imread(str);if(!image.data){cout<<"图像载入出现问题"<<endl;return 0;}Mat roi=image(Rect(20,20,20,20));Mat hsvImg;cvtColor(image, hsvImg, CV_BGR2HSV); //将图像转换到HSV颜色空间//分离HSV空间,v[0]为H色调,v[1]为S饱和度,v[2]为v灰度 vector<Mat> v;split(hsvImg,v);Mat roiH=v[0](Rect(20,20,20,20));Mat roiS=v[1](Rect(20,20,20,20));int SumH=0;int SumS=0;int avgH, avgS;//蓝底的平均色调和平均饱和度//取一块蓝色背景,计算出它的平均色调和平均饱和度for(int i=0; i<20; i++){for(int j=0; j<20; j++){/*SumH=SumH+roiH(i,j);*/SumH=int(roiH.at<uchar>(j,i))+SumH;SumS=int(roiS.at<uchar>(j,i))+SumS;}}avgH=SumH/400;avgS=SumS/400;//遍历整个图像int nl=hsvImg.rows;int nc=hsvImg.cols;int step=10;for(int j=0; j<nl; j++){for(int i=0; i<nc; i++){//以H.S两个通道做阈值分割,把蓝色替换成红色if((v[0].at<uchar>(j,i))<=(avgH+5) && v[0].at<uchar>(j,i)>=(avgH-5)&&(v[1].at<uchar>(j,i))<=(avgS+40) && v[1].at<uchar>(j,i)>=(avgS-40)){//cout<<int(v[0].at<uchar>(j,i))<<endl;//红色底//v[0].at<uchar>(j,i)=0;//白色底v[0].at<uchar>(j,i)=0;v[1].at<uchar>(j,i)=0;  //V[0]和V[1]全调成0就是变成白色//绿色底//v[0].at<uchar>(j,i)=60;//蓝色底//v[0].at<uchar>(j,i)=120;/*cout<<int(v[0].at<uchar>(j,i))<<endl;*/}}}Mat finImg;merge(v,finImg);Mat rgbImg;cvtColor(finImg,rgbImg, CV_HSV2BGR); //将图像转换回RGB空间imshow(origin,image);imshow(window,rgbImg);//加个滤波把边缘部分的值滤掉(此处应该用低通滤波器,但感觉不太好,还是不用了。)Mat result;GaussianBlur(rgbImg,result,Size(3,3),0.5);imshow(window,result);imwrite("nihaoWhite.jpg",result);waitKey(0);//system("pause");return 0;}////遍历整个图像//int nl=hsvImg.rows;//int nc=hsvImg.cols * hsvImg.channels();//for(int j=0; j<nl; j++)//{//uchar *data=hsvImg.ptr<uchar>(j);//for(int i=0; i<nc; i++)//{//cout<<int(data[i])<<" ";//}//}

这里面主要说明一下:

 HSV模型

倒锥形模型:

                          

这个模型就是按色彩、深浅、明暗来描述的。

H是色彩

S是深浅, S = 0时,只有灰度

V是明暗,表示色彩的明亮程度,但与光强无直接联系,(意思是有一点点联系吧)。


在这个程序里

色调主要是由V[0]来控制的

hsv是一个360度的模型 每个角度代表一种颜色

0度是红色

120度是绿色

240度是蓝色


但是OpenCV里最大值是255 所以它会对色调除以2,就是最大值是180

绿色对应的让它等于60    蓝色对应的就是120

换不同的背景只需要改动:

//红色底v[0].at<uchar>(j,i)=0;//白色底v[0].at<uchar>(j,i)=0;v[1].at<uchar>(j,i)=0;  //V[0]和V[1]全调成0就是变成白色//绿色底v[0].at<uchar>(j,i)=60;//蓝色底v[0].at<uchar>(j,i)=120;
改动的位置就不需要说明了吧!这个方法的效果确实不错,大赞!

毕竟是老师的图片,不能轻易放出来,网上的也不能随便用吧!哈哈

那就放张我最爱的崩坏3吧!