朋友找我帮忙更换证件照背景,因为mac上没装合适的软件,就想用OpenCV搞一下。

源文件我上传了一份:http://download.csdn.net/detail/cy_tec/9526134 使用OpenCV修改证件照背景。里面的代码可以直接用,头文件和库的路径要根据自己的机器进行配置。我的机器是mabbook air 13。OpenCV版本是3.1.0.

首先分析一下图片的情况:

这次的目标是把肩、头上面的灰色背景除去(当然也可以换成其它颜色)。

分析: 从肉眼可以看出背景和衣服、头发之间的色差还是挺明显的。转化成图像处理的语言就是,衣服和头发的像素值(RGB或者灰度值)都要比与它们相邻的背景区域大。

思路:

1. 从肉眼看来,从上往下像素点的值应该是在变大的过程,直到遇见头发或者衣服。所以方法一就是竖着扫描像素点,依次将扫描过的点置成你想要的颜色(比如全白:255, 255, 255),终止条件是找到第一个(我用的灰度)像素点的值小于前一个点的值。然后扫描下一竖行。

结果:这种方法的结果在这幅图像上并不适用。因为有些竖行的灰度值并不是完全递增的。

2. 我设置一个灰度值作为阈值。

结果:这种方式的阈值不够灵活,会出现过界或者没到边界的情况。

3. 取前n行(不能把目标包含进去)的最小值作阈值。

结果:这个方法就灵活很多。处理完之后洗二寸的照片上已经可以了。

用mac air自带的图片工具稍微处理一下就可以得到不错的效果了。

代码如下:

//
//  changeContext.cpp
//  changeContext
//
//  Created by cslzy on 16/5/12.
//  Copyright © 2016年 CY. All rights reserved.
//#include "changeContext.hpp"bool not_all_full(uchar pixel)
{
//    if (pixel[0] > uchar(0)) {
//        return true;
//    }
//    if (pixel[1] > uchar(0)) {
//        return true;
//    }
//    if (pixel[2] > uchar(0)) {
//        return true;
//    }
//    cout<<"work?"<<endl;if (pixel > uchar(0)) {return true;}return false;
}void changeFull(string photo)
{Mat img = imread(photo);int width = img.size().width;int height = img.size().height;// show depth
//    cout<<"depth:"<<img.at<Vec3b>(0,0).depth()<<endl;Mat tem_mat;tem_mat = img.clone();Mat gray;cvtColor(img, gray, CV_BGR2GRAY);cout<<img.at<Vec3b>(0,0)[0]<<endl;// 取前j行的最小值作为阈值,从上往下for (int i = 0; i<width; i++) {//        for (int j = 0; j<height; j++) {int j = 0;int min = 256;while (j<height-1){if (j<300) { // 从前j行中找像灰度素点值最小的点,意思if (gray.at<uchar>(j,i) < min) {min = gray.at<uchar>(j,i);}img.at<Vec3b>(j,i)[0] = uchar(255);//R G B 三个通道,每一个都是8bits.img.at<Vec3b>(j,i)[1] = uchar(255);img.at<Vec3b>(j,i)[2] = uchar(255);j++;continue;}//            if (not_all_full(gray.at<uchar>(j,i))) {if (gray.at<uchar>(j,i)>min) {// 整数通道,应该是有多个通道。//                img.at<Vec3i>(j,i)[0] = 255;//                img.at<Vec3i>(j,i)[1] = 255;//                img.at<Vec3i>(j,i)[2] = 255;img.at<Vec3b>(j,i)[0] = uchar(255);//R G B 三个通道,每一个都是8bits.img.at<Vec3b>(j,i)[1] = uchar(255);img.at<Vec3b>(j,i)[2] = uchar(255);//                cout<<"("<<i<<", "<<j<<"):"<<img.at<Vec3f>(j,i)<<endl;//                imshow("tao", img);//                waitKey(1);}else{break;}j++;}}//    // 从上往下,人工设置阈值。
//    for (int i = 0; i<width; i++) {for (int j = 0; j<height; j++) {
//        int j = 0;
//        while (j<height-1)
//        {
//            float flag = gray.at<uchar>(j,i) - gray.at<uchar>(j+1,i);if (not_all_full(gray.at<uchar>(j,i))) {
//            if (flag < 10) {
//            // 整数通道,应该是有多个通道。img.at<Vec3i>(j,i)[0] = 255;img.at<Vec3i>(j,i)[1] = 255;img.at<Vec3i>(j,i)[2] = 255;
//            img.at<Vec3b>(j,i)[0] = uchar(255);//R G B 三个通道,每一个都是8bits.
//            img.at<Vec3b>(j,i)[1] = uchar(255);
//            img.at<Vec3b>(j,i)[2] = uchar(255);cout<<"("<<i<<", "<<j<<"):"<<img.at<Vec3f>(j,i)<<endl;imshow("tao", img);waitKey(1);
//            }
//            else
//            {
//                break;
//            }
//
//            j++;
//        }
//    }// 从左往右
//    for (int j = 0; j<height; j++) {
//        int i = 0;
//        while (i < width-1) {
//            float flag = gray.at<uchar>(j,i) - gray.at<uchar>(j, i+1);
//            if (flag < 10) {
//                img.at<Vec3b>(j,i)[0] = uchar(255);//R G B 三个通道,每一个都是8bits.
//                img.at<Vec3b>(j,i)[1] = uchar(255);
//                img.at<Vec3b>(j,i)[2] = uchar(255);
//            }
//            else
//            {
//                break;
//            }
//            i++;
//        }
//    }cout<<width<<" "<<height<<endl;imshow("fixed", img);imwrite("/Users/cslzy/Desktop/fuluhou_fixed.jpg", img);imshow("test", tem_mat);moveWindow("test", width, 0);waitKey(0);
}

思路1 和 2 都可以参考下图:

当然也可以横着扫描,但是,要从两边开始往中间扫描。

思路3的效果如下图:

PS:感谢TT大美女让我使用她的证件照练手。。。

C++OpenCV实现抠除(也可用于更换)证件照背景相关推荐

  1. Opencv中Kmeans使用学习,更换证件照背景,QT界面,函数实现,C++实现

    kmeans简介 kmeans是机器学习中的一种聚类算法,简单来说就是把在一个区域中的点进行分类,分类的类别由自己定.具体的数学原理大家可以在很多的blog中学习,在这里主要介绍opencv中pyth ...

  2. 利用OpenCV的Grabcut()函数实现图像的前景与背景的分割-并对Grabcut()作详细介绍

    图像处理开发需求.图像处理接私活挣零花钱,请加微信/QQ 2487872782 图像处理开发资料.图像处理技术交流请加QQ群,群号 271891601 Graphcut是一种基于图论的分割方法,在计算 ...

  3. OpenCV C++案例实战六《绿幕视频背景替换》

    OpenCV C++案例实战六<绿幕视频背景替换> 前言 一.图像预处理 二.HSV色彩空间转换 1. cvtColor色彩空间转换 2. inRange抠图 三.背景替换 四.源码 总结 ...

  4. OpenCV这么简单为啥不学——1.11、蓝背景证件照替换白色或红色

    OpenCV这么简单为啥不学--1.11.蓝背景证件照替换白色或红色 目录 OpenCV这么简单为啥不学--1.11.蓝背景证件照替换白色或红色 前言 蓝背景证件照替换白色 蓝背景证件照替换红色 总结 ...

  5. opencv证件照背景替换

    #include <QCoreApplication> #include "opencv2/opencv.hpp"using namespace cv; using n ...

  6. opencv的VideoWriter类及参数用于保存视频

    VideoWriter 说明 参数 例子 例一:修改视频的分辨率 例二:在视频的指定区域画圆 例三:对彩色图像的每个通道单独进行处理 错误的情况 1.图片的分辨率大小 2.路径 说明 要使用OpenC ...

  7. opencv imencode和imdecode使用,用于网络传输图片

    这是C++版本的.程序首先读入一个图片.然后encode,之后把encode后的内容写入文件(实际应用可以发送到网络). 第二步,从文件读取encode的内容.然后解码decode.转换为mat格式, ...

  8. python+opencv 只抠出车牌部分

    一.实现效果(效果不好 能用 ): 二.py流程图 三.方法2. py代码 import cv2 #cv2库 import os import tkinter.filedialog #tk 是ugi库 ...

  9. 【OpenCV】图像代数运算:平均值去噪,减去背景

    代数运算,就是对两幅图像的点之间进行加.减.乘.除的运算.四种运算相应的公式为: 代数运算中比较常用的是图像相加和相减.图像相加常用来求平均值去除addtive噪声或者实现二次曝光(double-ex ...

最新文章

  1. SpringMVC的form:form表单的使用
  2. efficientransac_【泡泡图灵智库】基于图割优化的RANSAC算法(CVPR)
  3. 第一次写,python爬虫图片,操作excel。
  4. 有趣又有用的皮托定理!
  5. java io 机器名_java IO最让初学者误解的取名方式
  6. 递归走迷宫java,java递归实现的迷宫游戏
  7. 重磅 | 京东云区块链数据服务(BDS)正式开源!
  8. 朴素贝叶斯-垃圾邮件(英文的)处理
  9. 交友 它能让霍金有一口伦敦腔,也在帮聋哑人重新开口说话
  10. 计算机睡眠之后无法唤醒,电脑进入睡眠状态后无法唤醒一直黑屏,该如何处理...
  11. 包含下载,数据安全,数据备份16条军规
  12. 不愿意和别人打交道_一个人不愿意和同事打交道,大多是这3个原因,你了解吗...
  13. 最简单的机器学习入门:线性回归
  14. python(Django之组合搜索、JSONP、XSS过滤 )
  15. kali Linux 2020.1B 最详细安装教程
  16. 中北大学算法分析与设计实验报告一(BF算法)
  17. Pbootcms自定义分页样式,适用于多种环境
  18. 设计一套简单的计算机系统及其指令系统,【精品】计算机组成综合设计指导书...
  19. linux centos7 镜像下载
  20. 路由器无线桥接的方法

热门文章

  1. 031永久储存:腌制一缸美味的泡菜
  2. Failed to compile编译失败
  3. Word——图表如何交叉引用-插入题注-交叉引用
  4. NLM-P (使用积分图像进行算法的优化)
  5. [HDU-6578]
  6. mysql 建表最佳实践
  7. Win11系统默认用户名怎么进行修改教学
  8. 联网常见通信协议与通讯协议梳理- 通讯协议
  9. 【干货】1.5W+字的全链路前端性能优化送给你
  10. 人大金仓windows 10 安装闪退,改绿色安装方法,