OpenCV——证件照自动抠图

今天去交社保,要白底的电子版照片,我目前手头就是一个蓝底的,又不想手动抠图,于是想做一个自动换背景的程序。

先上效果:

具体分三步,第一步是大体的背景转换,把蓝色变为白色:

void colortransfer(cv::Mat image) //蓝背景转白背景,有边缘残留
{
    int Diff;
    int num_row = image.rows;
    int num_col = image.cols;
    for (int r = 0; r < num_row; r++)
    {
        cv::Vec3b *data = image.ptr<cv::Vec3b>(r);
        for (int c = 0; c < num_col; c++)
        {
            Diff = data[c][0] - (data[c][1] + data[c][2]) / 2; //蓝色检测
            if (Diff > 60 && data[c][0]>150)//蓝色分量比GR分量的平均值高60且蓝色分量大于150
            {
                data[c][0] = 255;
                data[c][1] = 255;
                data[c][2] = 255;
            }
        }
    }
}

但是这步出来之后效果不太好,可以看出来有很明显的边缘,很多蓝底照片因为照的时候和背景过近,导致边缘颜色变化

接下来就是对这些深色的蓝边进行一个处理,这里采用了检测蓝边->中值滤波器的方法:

void Optimization(cv::Mat image)   //去边缘残留
{
    int num_row = image.rows;
    int num_col = image.cols;
    for (int i = 1; i < num_row-1; i++)
    {
        cv::Vec3b *last_r = image.ptr<cv::Vec3b>(i-1);
        cv::Vec3b *data = image.ptr<cv::Vec3b>(i);
        cv::Vec3b *next_r = image.ptr<cv::Vec3b>(i+1);
        for (int j = 1; j < num_col-1; j++)
        {
            if (data[j][0]>90 && data[j][0] - data[j][1]>9 && data[j][0] - data[j][2]>9)
            {
                int stat;
                cv::Vec3b Temp;
                cv::Vec3b array[9] = { last_r[j - 1], last_r[j], last_r[j + 1], data[j - 1], data[j], data[j + 1], next_r[j - 1], next_r[j], next_r[j + 1] };
                do
                {
                    stat = 0;
                    for (int m = 0; m < 8; m++)
                    {
                        if (array[m][0] + array[m][1] + array[m][2]> array[m + 1][0] + array[m + 1][1] + array[m + 1][2])
                        {
                            Temp=array[m + 1];
                            array[m + 1] = array[m];
                            array[m] = Temp;
                            stat = 1;
                        }

                    }
                } while (stat == 1);
                data[j][0] = array[7][0];
                data[j][1] = array[7][1];
                data[j][2] = array[7][2];
            }
        }
    }
}

中间用了冒泡算法进行排序,结果如下:

边缘基本去除了,但是头发这边显得非常不真实,没有边缘的毛躁感。这里我们检测到头发边缘后,对边缘区域进行一个低通滤波和颜色的加白处理,让边缘有层次感:

void hairilization(cv::Mat image) //毛躁化
{
    int num_row = image.rows / 3;
    int num_col = image.cols;
    for (int i = 2; i < num_row - 2; i=i+5)
    {
        cv::Vec3b *last_sec_r = image.ptr<cv::Vec3b>(i - 2);
        cv::Vec3b *last_r = image.ptr<cv::Vec3b>(i - 1);
        cv::Vec3b *data = image.ptr<cv::Vec3b>(i);
        cv::Vec3b *next_r = image.ptr<cv::Vec3b>(i + 1);
        cv::Vec3b *next_sec_r = image.ptr<cv::Vec3b>(i + 2);
        for (int j = 2; j < num_col; j = j + 5)
        {
            int count = 0;// check how many 255point in this area(boundary)
            cv::Vec3b array[5][5] = { last_sec_r[j - 2], last_sec_r[j - 1], last_sec_r[j], last_sec_r[j + 1], last_sec_r[j + 2],                             last_r[j - 2], last_r[j - 1], last_r[j], last_r[j + 1], last_r[j + 2],                            data[j - 2], data[j - 1], data[j], data[j + 1], data[j + 2],                            next_r[j - 2], next_r[j - 1], next_r[j], next_r[j + 1], next_r[j + 2],                         next_sec_r[j - 2], next_sec_r[j - 1], next_sec_r[j], next_sec_r[j + 1], next_sec_r[j + 2]};
            for (int r = 0; r < 5; r++)
            {
                for (int c = 0; c < 5; c++)
                {
                    if (array[r][c][1] >= 251)
                        count++;
                }
            }
            if (count >= 7 &&count<=18) //说明是头发边缘,开始处理
            {

                last_r[j - 1] = 1 / 9 * (array[0][0] + array[0][1] + array[0][2] + array[1][0] + array[1][1] + array[1][2] + array[2][0] + array[2][1] + array[2][2]) + cv::Vec3b(100, 100, 100);
                last_r[j] = 1 / 9 * (array[0][1] + array[0][2] + array[0][3] + array[1][1] + array[1][2] + array[1][3] + array[2][1] + array[2][2] + array[2][3]) + cv::Vec3b(80, 80, 80);
                last_r[j + 1] = 1 / 9 * (array[0][2] + array[0][3] + array[0][4] + array[1][2] + array[1][3] + array[1][4] + array[2][2] + array[2][3] + array[2][4]) + cv::Vec3b(100, 100, 100);

                data[j - 1] = (1 / 9 * array[1][0] + 1 / 9 * array[1][1] + 1 / 9 * array[1][2] + 1 / 9 * array[2][0] + 1 / 9 * array[2][1] + 1 / 9 * array[2][2] + 1 / 9 * array[3][0] + 1 / 9 * array[3][1] + 1 / 9 * array[3][2]) + cv::Vec3b(80, 80, 80);
                data[j] = (1 / 9 * array[1][1] + 1 / 9 * array[1][2] + 1 / 9 * array[1][3] + 1 / 9 * array[2][1] + 1 / 9 * array[2][2] + 1 / 9 * array[2][3] + 1 / 9 * array[3][1] + 1 / 9 * array[3][2] + 1 / 9 * array[3][3]) + cv::Vec3b(80, 80, 80);
                data[j + 1] =  (1 / 9 * array[1][2] + 1 / 9 * array[1][3] + 1 / 9 * array[1][4] + 1 / 9 * array[2][2] + 1 / 9 * array[2][3] + 1 / 9 * array[2][4] + 1 / 9 * array[3][2] + 1 / 9 * array[3][3] + 1 / 9 * array[3][4]) + cv::Vec3b(80, 80, 80);

                data[j - 1] =  (1 / 9 * array[2][0] + 1 / 9 * array[2][1] + 1 / 9 * array[2][2] + 1 / 9 * array[3][0] + 1 / 9 * array[3][1] + 1 / 9 * array[3][2] + 1 / 9 * array[4][0] + 1 / 9 * array[4][1] + 1 / 9 * array[4][2]) + cv::Vec3b(100, 100, 100);
                data[j] =  (1 / 9 * array[2][1] + 1 / 9 * array[2][2] + 1 / 9 * array[2][3] + 1 / 9 * array[3][1] + 1 / 9 * array[3][2] + 1 / 9 * array[3][3] + 1 / 9 * array[4][1] + 1 / 9 * array[4][2] + 1 / 9 * array[4][3]) + cv::Vec3b(80, 80, 80);
                data[j + 1] =  (1 / 9 * array[2][2] + 1 / 9 * array[2][3] + 1 / 9 * array[2][4] + 1 / 9 * array[3][2] + 1 / 9 * array[3][3] + 1 / 9 * array[3][4] + 1 / 9 * array[4][2] + 1 / 9 * array[4][3] + 1 / 9 * array[4][4]) + cv::Vec3b(100, 100, 100);

            }
        }
    }
}

结果如下:

相比于:

有很大提升

时间: 2024-10-07 04:36:40

OpenCV——证件照自动抠图的相关文章

Python - AI自动抠图

一.简介 抠图是用PS? 用魔棒和快速选择工具? 遇到复杂背景怎么办? 最近发现一个神奇的工具——Remove Image Background https://www.remove.bg/zh 它是基于Python.Ruby和深度学习技术开发,通过强大的AI人工智能算法实现自动识别出前景主体与背景图,秒秒种完成抠图. 这款抠图工具有两种简单方式: 1.在线抠图 2.API代码抠图 二.在线抠图 1.打开remove.bg网站首页,可以上传本地图片,也可以选择网络图片的URL链接. 2.上传几秒

OpenCV 2.4.9 学习笔记(2)—— OpenCV内存自动管理

OpenCV自动内存管理 目前版本的OpenCV是自动处理所有自己的内存的,虽然这么说也不是很严谨.OpenCV在2.0版本中引入了一个新的C++接口,利用自动内存管理给出了解决问题的新方法.使用这个方法,开发者不需要纠结在管理内存上,而且你的代码会变得简洁. 以 Mat为例 ,首先现在没必要再手动地(1)为其开辟空间(2)在不需要时立即将空间释放.但手动地做还是可以的:大多数OpenCV函数仍会手动地为输出数据开辟空间.当传递一个已经存在的 Mat 对象时,开辟好的矩阵空间会被重用.也就是说,

opencv::证件照背景替换

证件照背景替换 K-Means 背景融合 – 高斯模糊 遮罩层生成 #include <opencv2/opencv.hpp> #include <iostream> using namespace cv; using namespace std; Mat mat_to_samples(Mat &image); int main(int argc, char** argv) { Mat src = imread("D:/images/toux.jpg")

利用openCV实现自动抓拍,人脸识别,清晰度的验证等

1.本文主要涉及到opencv的视频帧抓拍和验证的相关问题,不包含如何集成opencv 2.主要讲解涉及到opencv中的关键类及一些常用的方法 3.着重讲解代理方法: - (void)processImage:(cv::Mat &)image 4.集成过程中的注意事项 5.附上抓拍的小demo的下载地址 6.扩展,验证抓拍的图片中是否包含人脸 =====================================分割线====================================

Anaconda安装OpenCV没有自动代码补全

(1)错误描述 出现这种错误OpenCV3.0 和 4.0 都是一样的,不是版本导致的问题,不要在版本中挣扎啦! 最省心最安全最简洁的方式就是下载Anaconda+OpenCV再安装,别用单独的Python了...Python的Python和Anaconda的Python还是有一点点不一样...况且你都用OpenCV做项目了,那不得更加换成Anaconda了吗... (2)Anaconda4.5.11安装OpenCV4.0.0 查看当前Anaconda的版本和包含的Python解释器的版本: D

OpenCV 2.4.9 学习笔记(3)—— OpenCV自动为输出数组(矩阵)分配内存

OpenCV大部分时候会为OpenCV方法中的输出数据(方法的参数)自动分配内存,所以如果一个方法的参数有一个或者多个输入数组(cv::Mat 实例)和一些输出数组时,OpenCV会自动为输出数组分配内存空间或者重新分配内存空间,内存的大小和数据类型由输入数组决定.如果需要的话,这个方法会通过其他的参数来决定输出数组的其他属性. 下面用一段代码来说明一下: 1 #include "cv.h" 2 #include "highgui.h" 3 4 using name

[OpenCV]1 体验OpenCV

<span style="font-size:18px;">#include "highgui.h" int main(int argc,char** argv) { IplImage* img=cvLoadImage(argv[1]); cvNamedWindow("Test1",CV_WINDOW_AUTOSIZE); cvShowImage("Test1",img); cvWaitKey(0); cvRele

openCV学习笔记(2)--cvCreateTrackbar

int cvCreateTrackbar( const char* trackbar_name, //滑动条的名称 const char* window_name, //窗口的名称,滑动条不会遮挡图像 int* value, //当滑动条被拖到时,OpenCV会自动将当前位置所代表的值传给指针指向的整数 int count, //滑动条所能达到的最大值 CvTrackbarCallback on_change //可选的回调函数,回调函数可参见http://wapedia.mobi/zhtrad

【OpenCV归纳】1 体验OpenCV

#include "highgui.h" int main(int argc,char** argv) { IplImage* img=cvLoadImage(argv[1]); cvNamedWindow("Test1",CV_WINDOW_AUTOSIZE); cvShowImage("Test1",img); cvWaitKey(0); cvReleaseImage(&img); cvDestoryWindow("Test