温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

C++中如何使用OpenCV实现证件照蓝底换成白底功能

发布时间:2021-09-23 14:33:55 来源:亿速云 阅读:139 作者:小新 栏目:编程语言

这篇文章主要介绍了C++中如何使用OpenCV实现证件照蓝底换成白底功能,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。

主要步骤为:

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吧!

附录

提取图像中指定颜色的像素区域

#include<iostream>#include<opencv2/core/core.hpp>#include<opencv2/imgproc/imgproc.hpp>#include<opencv2/highgui/highgui.hpp>using namespace cv;class ColorDetector{private:    //最小可接受距离    int minDist;    //目标色    cv::Vec3b target;    //结果图像    cv::Mat result;//计算与目标颜色的距离int getDistance(cv::Vec3b color){    return abs(color[0] - target[0]) + abs(color[1] - target[1]) + abs(color[2] - target[2]);}public:    //空构造函数    ColorDetector() :minDist(100)    {    //初始化默认参数    target[0] = target[1] = target[2] = 0;    }    void setColorDistanceThreshold(int distance);    int getColorDistanceThreshold() const;    void setTargetColor(unsigned char red, unsigned char green, unsigned char blue);    void setTargetColor(cv::Vec3b color);    cv::Vec3b getTargetColor() const;    cv::Mat ColorDetector::process(const cv::Mat &image);    };//设置色彩距离阈值,阈值必须是正的,否则设为0void ColorDetector::setColorDistanceThreshold(int distance){    if (distance < 0)    distance = 0;    minDist = distance;}//获取色彩距离阈值int ColorDetector::getColorDistanceThreshold() const{    return minDist;}//设置需检测的颜色void ColorDetector::setTargetColor(unsigned char red, unsigned char green, unsigned char blue){    //BGR顺序    target[2] = red;    target[1] = green;    target[0] = blue;}//设置需检测的颜色void ColorDetector::setTargetColor(cv::Vec3b color){    target = color;}//获取需检测的颜色cv::Vec3b ColorDetector::getTargetColor() const{    return target;}cv::Mat ColorDetector::process(const cv::Mat &image)//核心的处理方法{    //按需重新分配二值图像    //与输入图像的尺寸相同,但是只有一个通道    result.create(image.rows, image.cols, CV_8U);    //得到迭代器    cv::Mat_<cv::Vec3b>::const_iterator it = image.begin<cv::Vec3b>();    cv::Mat_<cv::Vec3b>::const_iterator itend = image.end<cv::Vec3b>();    cv::Mat_<uchar>::iterator itout = result.begin<uchar>();    for (; it != itend; ++it, ++itout)//处理每个像素    {        //计算离目标颜色的距离        if (getDistance(*it) < minDist)        {            *itout = 255;        }        else        {            *itout = 0;        }    }        return result;}int _tmain(int argc, _TCHAR* argv[]){    //1.创建图像处理的对象    ColorDetector cdetect;    //2.读取输入图像    cv::Mat image = cv::imread("boldt.jpg");    if (!image.data)    {        return 0;    }    //3.设置输入参数    cdetect.setTargetColor(130, 190, 230);//蓝天的颜色    cv::namedWindow("result");    //4.处理并显示结果    cv::imshow("result", cdetect.process(image));    cv::waitKey();    return 0;}

感谢你能够认真阅读完这篇文章,希望小编分享的“C++中如何使用OpenCV实现证件照蓝底换成白底功能”这篇文章对大家有帮助,同时也希望大家多多支持亿速云,关注亿速云行业资讯频道,更多相关知识等着你来学习!

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI