朋友找我帮忙更换证件照背景,因为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?"< 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:"<(0,0).depth()<(0,0)[0]<(j,i) < min) {
min = gray.at(j,i);
}
img.at(j,i)[0] = uchar(255);//R G B 三个通道,每一个都是8bits.
img.at(j,i)[1] = uchar(255);
img.at(j,i)[2] = uchar(255);
j++;
continue;
}
// if (not_all_full(gray.at(j,i))) {
if (gray.at(j,i)>min) {
// 整数通道,应该是有多个通道。
// img.at(j,i)[0] = 255;
// img.at(j,i)[1] = 255;
// img.at(j,i)[2] = 255;
img.at(j,i)[0] = uchar(255);//R G B 三个通道,每一个都是8bits.
img.at(j,i)[1] = uchar(255);
img.at(j,i)[2] = uchar(255);
// cout<<"("<(j,i)<(j,i) - gray.at(j+1,i);
//// if (not_all_full(gray.at(j,i))) {
// if (flag < 10) {
// // 整数通道,应该是有多个通道。
//// img.at(j,i)[0] = 255;
//// img.at(j,i)[1] = 255;
//// img.at(j,i)[2] = 255;
// img.at(j,i)[0] = uchar(255);//R G B 三个通道,每一个都是8bits.
// img.at(j,i)[1] = uchar(255);
// img.at(j,i)[2] = uchar(255);
//// cout<<"("<(j,i)<(j,i) - gray.at(j, i+1);
// if (flag < 10) {
// img.at(j,i)[0] = uchar(255);//R G B 三个通道,每一个都是8bits.
// img.at(j,i)[1] = uchar(255);
// img.at(j,i)[2] = uchar(255);
// }
// else
// {
// break;
// }
// i++;
// }
// }
cout<
思路1 和 2 都可以参考下图:
当然也可以横着扫描,但是,要从两边开始往中间扫描。
思路3的效果如下图:
PS:感谢TT大美女让我使用她的证件照练手。。。