个人填充图形算法之直线扫描[含透明化背景以输出人物]

简介

使用库:easyx
语言:C++
作用:对某个IMAGE对象的存储的图形进行分别从上下左右开始直线扫描的像素点识别,如果是要被替换的颜色,
或者在与替换颜色相似,则都会被替换成目标颜色HIDE_COLOR(一个常量)

使用该算法前应该具有的前置代码:

#define HIDE_COLOR 0xFF555555//设置目标颜色
struct color_group{//先建立一个用来存储颜色的结构体
	BYTE r;//这三个是要换成HIDE_COLOR的颜色的RGB
	BYTE g;
	BYTE b;
	BYTE rl;//这六项是要被替换的颜色所允许的误差范围,即用来判断是否是相似色
	BYTE gl;
	BYTE bl;
	BYTE rr;
	BYTE gr;
	BYTE br;
	BYTE rs;//这三项是扫描到的点本身的RGB三色
	BYTE gs;
	BYTE bs;
};

在具备了上述前置代码后,则开始使用以下代码开始计算:

/计算准备
	IMAGE img;
	static int i, j, w, h;//因为可能图片处理时候比较常用,所以就设置为static
	DWORD *src;
	COLORREF color = 0xffffff;//要被替换的颜色 这里是白色
	int color_go = 20;//偏差20范围的颜色视作为相似
	color_group p;//生成实例
	p.r = GetRValue(color);//获得要被替换的颜色的RGB三色
	p.g = GetGValue(color);
	p.b = GetBValue(color);
	p.rl = p.r < color_go ? 0 : p.r - color_go ;//COLOR_GO是误差值,这里用来获取误差区间
	p.gl = p.g < color_go ? 0 : p.g - color_go ;
	p.bl = p.b < color_go ? 0 : p.b - color_go ;
	p.rr = p.r > 255 - color_go ? 255 : 255 - color_go ;
	p.gr = p.g > 255 - color_go  ? 255 : 255 - color_go ;
	p.br = p.b > 255 - color_go ? 255 : 255 - color_go ;
	loadimage(&img, TEXT("a.jpg"));//装载目标图像:TEXT("路径+文件名")这种写法是为了自适应当前编码
	w = img.getwidth(), h = img.getheight();//获取图像宽高
	bool *x = (bool*)malloc(sizeof(bool)*w);//设置标志数组,记得用完释放掉
	bool *y = (bool*)malloc(sizeof(bool)*h);
	src = GetImageBuffer(&img);//得到图像缓冲区
	/算法实现
for (i = 0; i < w; ++i) {//建立上方横向扫描线
		p.rs = GetRValue(src[i]);
		p.gs = GetGValue(src[i]);
		p.bs = GetBValue(src[i]);
		if (p.rs >= p.rl && p.rs <= p.rr && p.gs >= p.gl && p.gs <= p.gr && p.bs >= p.bl && p.bs <= p.br || src[i] == HIDE_COLOR) {
			x[i] = true;
			src[i] = HIDE_COLOR;
		}
		else
			x[i] = false;
	}
	for (j = 1; j < h; ++j) {
		for (i = 0; i < w; ++i) {//上方横向扫描线向下扫描开始
			p.rs = GetRValue(src[i + j * w]);
			p.gs = GetGValue(src[i + j * w]);
			p.bs = GetBValue(src[i + j * w]);
			if (x[i] == true) {
				if (p.rs >= p.rl && p.rs <= p.rr && p.gs >= p.gl && p.gs <= p.gr && p.bs >= p.bl && p.bs <= p.br || src[i + j * w] == HIDE_COLOR) {
					x[i] = true;
					src[i + j * w] = HIDE_COLOR;
				}
				else
					x[i] = false;
			}
		}
	}
	for (i = 0; i < w; ++i) {//建立下方横向扫描线
		p.rs = GetRValue(src[i + (h - 1)*w]);
		p.gs = GetGValue(src[i + (h - 1)*w]);
		p.bs = GetBValue(src[i + (h - 1)*w]);
		if (p.rs >= p.rl && p.rs <= p.rr && p.gs >= p.gl && p.gs <= p.gr && p.bs >= p.bl && p.bs <= p.br || src[i + (h - 1)*w] == HIDE_COLOR) {
			x[i] = true;
			src[i + (h - 1)*w] = HIDE_COLOR;
		}
		else
			x[i] = false;
	}
	for (j = h - 2; j >= 0; --j) {
		for (i = 0; i < w; ++i) {//下方横向扫描线向上扫描开始
			p.rs = GetRValue(src[i + j * w]);
			p.gs = GetGValue(src[i + j * w]);
			p.bs = GetBValue(src[i + j * w]);
			if (x[i] == true) {
				if (p.rs >= p.rl && p.rs <= p.rr && p.gs >= p.gl && p.gs <= p.gr && p.bs >= p.bl && p.bs <= p.br || src[i + j * w] == HIDE_COLOR) {
					x[i] = true;
					src[i + j * w] = HIDE_COLOR;
				}
				else
					x[i] = false;
			}
		}
	}
	for (j = 0; j < h; ++j) {//建立左方竖向扫描线
		p.rs = GetRValue(src[j*w]);
		p.gs = GetGValue(src[j*w]);
		p.bs = GetBValue(src[j*w]);
		if (p.rs >= p.rl && p.rs <= p.rr && p.gs >= p.gl && p.gs <= p.gr && p.bs >= p.bl && p.bs <= p.br || src[j*w] == HIDE_COLOR) {
			y[j] = true;
			src[j*w] = HIDE_COLOR;
		}
		else
			y[j] = false;
	}
	for (i = 1; i < w; ++i) {
		for (j = 0; j < h; ++j) {//左方竖向扫描线向右扫描开始
			p.rs = GetRValue(src[i + j * w]);
			p.gs = GetGValue(src[i + j * w]);
			p.bs = GetBValue(src[i + j * w]);
			if (y[j] == true) {
				if (p.rs >= p.rl && p.rs <= p.rr && p.gs >= p.gl && p.gs <= p.gr && p.bs >= p.bl && p.bs <= p.br || src[i + j * w] == HIDE_COLOR) {
					y[j] = true;
					src[i + j * w] = HIDE_COLOR;
				}
				else
					y[j] = false;
			}
		}
	}
	for (j = 0; j < h; ++j) {//建立右方竖向扫描线
		p.rs = GetRValue(src[w - 1 + j * w]);
		p.gs = GetGValue(src[w - 1 + j * w]);
		p.bs = GetBValue(src[w - 1 + j * w]);
		if (p.rs >= p.rl && p.rs <= p.rr && p.gs >= p.gl && p.gs <= p.gr && p.bs >= p.bl && p.bs <= p.br || src[w - 1 + j * w] == HIDE_COLOR) {
			y[j] = true;
			src[w - 1 + j * w] = HIDE_COLOR;
		}
		else
			y[j] = false;
	}
	for (i = w - 1; i >= 0; --i) {
		for (j = 0; j < h; ++j) {//右方竖向扫描线向左扫描开始
			p.rs = GetRValue(src[i + j * w]);
			p.gs = GetGValue(src[i + j * w]);
			p.bs = GetBValue(src[i + j * w]);
			if (y[j] == true) {
				if (p.rs >= p.rl && p.rs <= p.rr && p.gs >= p.gl && p.gs <= p.gr && p.bs >= p.bl && p.bs <= p.br || src[i + j * w] == HIDE_COLOR) {
					y[j] = true;
					src[i + j * w] = HIDE_COLOR;
				}
				else
					y[j] = false;
			}
		}
	}

完整实例:

#include <graphics.h>
#include <conio.h>
#define HIDE_COLOR 0xFF555555//设置目标颜色
struct color_group {//先建立一个用来存储颜色的类
	BYTE r;//这三个是要换成HIDE_COLOR的颜色的RGB
	BYTE g;
	BYTE b;
	BYTE rl;//这六项是要被替换的颜色所允许的误差范围
	BYTE gl;
	BYTE bl;
	BYTE rr;
	BYTE gr;
	BYTE br;
	BYTE rs;//这三项是扫描到的点本身的RGB三色
	BYTE gs;
	BYTE bs;
};
void ChangImg(IMAGE &img, const COLORREF &color, const int &color_go,color_group &p) {
	static int i, j, w, h;//因为可能图片处理时候比较常用,所以就设置为static
	static DWORD *src;
	w = img.getwidth(), h = img.getheight();//获取图像宽高
	bool *x = (bool*)malloc(sizeof(bool)*w);//设置标志数组,记得用完释放掉
	bool *y = (bool*)malloc(sizeof(bool)*h);
	src = GetImageBuffer(&img);//得到图像缓冲区
	for (i = 0; i < w; ++i) {//建立上方横向扫描线
		p.rs = GetRValue(src[i]);
		p.gs = GetGValue(src[i]);
		p.bs = GetBValue(src[i]);
		if (p.rs >= p.rl && p.rs <= p.rr && p.gs >= p.gl && p.gs <= p.gr && p.bs >= p.bl && p.bs <= p.br || src[i] == HIDE_COLOR) {
			x[i] = true;
			src[i] = HIDE_COLOR;
		}
		else
			x[i] = false;
	}
	for (j = 1; j < h; ++j) {
		for (i = 0; i < w; ++i) {//上方横向扫描线向下扫描开始
			p.rs = GetRValue(src[i + j * w]);
			p.gs = GetGValue(src[i + j * w]);
			p.bs = GetBValue(src[i + j * w]);
			if (x[i] == true) {
				if (p.rs >= p.rl && p.rs <= p.rr && p.gs >= p.gl && p.gs <= p.gr && p.bs >= p.bl && p.bs <= p.br || src[i + j * w] == HIDE_COLOR) {
					x[i] = true;
					src[i + j * w] = HIDE_COLOR;
				}
				else
					x[i] = false;
			}
		}
	}
	for (i = 0; i < w; ++i) {//建立下方横向扫描线
		p.rs = GetRValue(src[i + (h - 1)*w]);
		p.gs = GetGValue(src[i + (h - 1)*w]);
		p.bs = GetBValue(src[i + (h - 1)*w]);
		if (p.rs >= p.rl && p.rs <= p.rr && p.gs >= p.gl && p.gs <= p.gr && p.bs >= p.bl && p.bs <= p.br || src[i + (h - 1)*w] == HIDE_COLOR) {
			x[i] = true;
			src[i + (h - 1)*w] = HIDE_COLOR;
		}
		else
			x[i] = false;
	}
	for (j = h - 2; j >= 0; --j) {
		for (i = 0; i < w; ++i) {//下方横向扫描线向上扫描开始
			p.rs = GetRValue(src[i + j * w]);
			p.gs = GetGValue(src[i + j * w]);
			p.bs = GetBValue(src[i + j * w]);
			if (x[i] == true) {
				if (p.rs >= p.rl && p.rs <= p.rr && p.gs >= p.gl && p.gs <= p.gr && p.bs >= p.bl && p.bs <= p.br || src[i + j * w] == HIDE_COLOR) {
					x[i] = true;
					src[i + j * w] = HIDE_COLOR;
				}
				else
					x[i] = false;
			}
		}
	}
	for (j = 0; j < h; ++j) {//建立左方竖向扫描线
		p.rs = GetRValue(src[j*w]);
		p.gs = GetGValue(src[j*w]);
		p.bs = GetBValue(src[j*w]);
		if (p.rs >= p.rl && p.rs <= p.rr && p.gs >= p.gl && p.gs <= p.gr && p.bs >= p.bl && p.bs <= p.br || src[j*w] == HIDE_COLOR) {
			y[j] = true;
			src[j*w] = HIDE_COLOR;
		}
		else
			y[j] = false;
	}
	for (i = 1; i < w; ++i) {
		for (j = 0; j < h; ++j) {//左方竖向扫描线向右扫描开始
			p.rs = GetRValue(src[i + j * w]);
			p.gs = GetGValue(src[i + j * w]);
			p.bs = GetBValue(src[i + j * w]);
			if (y[j] == true) {
				if (p.rs >= p.rl && p.rs <= p.rr && p.gs >= p.gl && p.gs <= p.gr && p.bs >= p.bl && p.bs <= p.br || src[i + j * w] == HIDE_COLOR) {
					y[j] = true;
					src[i + j * w] = HIDE_COLOR;
				}
				else
					y[j] = false;
			}
		}
	}
	for (j = 0; j < h; ++j) {//建立右方竖向扫描线
		p.rs = GetRValue(src[w - 1 + j * w]);
		p.gs = GetGValue(src[w - 1 + j * w]);
		p.bs = GetBValue(src[w - 1 + j * w]);
		if (p.rs >= p.rl && p.rs <= p.rr && p.gs >= p.gl && p.gs <= p.gr && p.bs >= p.bl && p.bs <= p.br || src[w - 1 + j * w] == HIDE_COLOR) {
			y[j] = true;
			src[w - 1 + j * w] = HIDE_COLOR;
		}
		else
			y[j] = false;
	}
	for (i = w - 1; i >= 0; --i) {
		for (j = 0; j < h; ++j) {//右方竖向扫描线向左扫描开始
			p.rs = GetRValue(src[i + j * w]);
			p.gs = GetGValue(src[i + j * w]);
			p.bs = GetBValue(src[i + j * w]);
			if (y[j] == true) {
				if (p.rs >= p.rl && p.rs <= p.rr && p.gs >= p.gl && p.gs <= p.gr && p.bs >= p.bl && p.bs <= p.br || src[i + j * w] == HIDE_COLOR) {
					y[j] = true;
					src[i + j * w] = HIDE_COLOR;
				}
				else
					y[j] = false;
			}
		}
	}
	free(x);
	free(y);
}
int main()
{
	IMAGE img;
	COLORREF color = 0xffffff;//要被替换的颜色 这里是白色
	int color_go = 20;//偏差20范围的颜色视作为相似
	color_group p;//生成实例
	p.r = GetRValue(color);//获得要被替换的颜色的RGB三色
	p.g = GetGValue(color);
	p.b = GetBValue(color);
	p.rl = p.r < color_go ? 0 : p.r - color_go;//color_go是误差值,这里用来获取误差区间,为了判断相似色
	p.gl = p.g < color_go ? 0 : p.g - color_go;
	p.bl = p.b < color_go ? 0 : p.b - color_go;
	p.rr = p.r > 255 - color_go ? 255 : 255 - color_go;
	p.gr = p.g > 255 - color_go ? 255 : 255 - color_go;
	p.br = p.b > 255 - color_go ? 255 : 255 - color_go;
	loadimage(&img, TEXT("a.jpg"));//装载目标图像:TEXT("路径+文件名")这种写法是为了自适应当前编码
	initgraph(img.getwidth()*2, img.getheight());//准备演示
	setbkcolor(HIDE_COLOR);//设置设备背景色
	cleardevice();//清洗背景
	putimage(0, 0, &img);//输出原图像
	ChangImg(img, color, color_go, p);//开始除去除该颜色
	putimage(img.getwidth(), 0, &img);//输出对比图像
	_getch();//如果这里出错就换成getch();
	closegraph();
	return 0;
}

效果图:
左边原图,右边替换后的图
对比图

可以看到,我们成功地将人物的背景色替换成了我们指定的目标颜色(HIDE_COLOR)
当指定窗口HIDE_COLOR颜色透明时就可以获得下图效果

透明对比图
得到这样一个人物指定颜色透明输出的效果
以下是更改后的实例代码:

#include <graphics.h>
#include <conio.h>
#define HIDE_COLOR 0xFF555555//设置目标颜色
struct color_group {//先建立一个用来存储颜色的类
	BYTE r;//这三个是要换成HIDE_COLOR的颜色的RGB
	BYTE g;
	BYTE b;
	BYTE rl;//这六项是要被替换的颜色所允许的误差范围
	BYTE gl;
	BYTE bl;
	BYTE rr;
	BYTE gr;
	BYTE br;
	BYTE rs;//这三项是扫描到的点本身的RGB三色
	BYTE gs;
	BYTE bs;
};
void ChangImg(IMAGE &img, const COLORREF &color, const int &color_go,color_group &p) {
	static int i, j, w, h;//因为可能图片处理时候比较常用,所以就设置为static
	static DWORD *src;
	w = img.getwidth(), h = img.getheight();//获取图像宽高
	bool *x = (bool*)malloc(sizeof(bool)*w);//设置标志数组,记得用完释放掉
	bool *y = (bool*)malloc(sizeof(bool)*h);
	src = GetImageBuffer(&img);//得到图像缓冲区
	for (i = 0; i < w; ++i) {//建立上方横向扫描线
		p.rs = GetRValue(src[i]);
		p.gs = GetGValue(src[i]);
		p.bs = GetBValue(src[i]);
		if (p.rs >= p.rl && p.rs <= p.rr && p.gs >= p.gl && p.gs <= p.gr && p.bs >= p.bl && p.bs <= p.br || src[i] == HIDE_COLOR) {
			x[i] = true;
			src[i] = HIDE_COLOR;
		}
		else
			x[i] = false;
	}
	for (j = 1; j < h; ++j) {
		for (i = 0; i < w; ++i) {//上方横向扫描线向下扫描开始
			p.rs = GetRValue(src[i + j * w]);
			p.gs = GetGValue(src[i + j * w]);
			p.bs = GetBValue(src[i + j * w]);
			if (x[i] == true) {
				if (p.rs >= p.rl && p.rs <= p.rr && p.gs >= p.gl && p.gs <= p.gr && p.bs >= p.bl && p.bs <= p.br || src[i + j * w] == HIDE_COLOR) {
					x[i] = true;
					src[i + j * w] = HIDE_COLOR;
				}
				else
					x[i] = false;
			}
		}
	}
	for (i = 0; i < w; ++i) {//建立下方横向扫描线
		p.rs = GetRValue(src[i + (h - 1)*w]);
		p.gs = GetGValue(src[i + (h - 1)*w]);
		p.bs = GetBValue(src[i + (h - 1)*w]);
		if (p.rs >= p.rl && p.rs <= p.rr && p.gs >= p.gl && p.gs <= p.gr && p.bs >= p.bl && p.bs <= p.br || src[i + (h - 1)*w] == HIDE_COLOR) {
			x[i] = true;
			src[i + (h - 1)*w] = HIDE_COLOR;
		}
		else
			x[i] = false;
	}
	for (j = h - 2; j >= 0; --j) {
		for (i = 0; i < w; ++i) {//下方横向扫描线向上扫描开始
			p.rs = GetRValue(src[i + j * w]);
			p.gs = GetGValue(src[i + j * w]);
			p.bs = GetBValue(src[i + j * w]);
			if (x[i] == true) {
				if (p.rs >= p.rl && p.rs <= p.rr && p.gs >= p.gl && p.gs <= p.gr && p.bs >= p.bl && p.bs <= p.br || src[i + j * w] == HIDE_COLOR) {
					x[i] = true;
					src[i + j * w] = HIDE_COLOR;
				}
				else
					x[i] = false;
			}
		}
	}
	for (j = 0; j < h; ++j) {//建立左方竖向扫描线
		p.rs = GetRValue(src[j*w]);
		p.gs = GetGValue(src[j*w]);
		p.bs = GetBValue(src[j*w]);
		if (p.rs >= p.rl && p.rs <= p.rr && p.gs >= p.gl && p.gs <= p.gr && p.bs >= p.bl && p.bs <= p.br || src[j*w] == HIDE_COLOR) {
			y[j] = true;
			src[j*w] = HIDE_COLOR;
		}
		else
			y[j] = false;
	}
	for (i = 1; i < w; ++i) {
		for (j = 0; j < h; ++j) {//左方竖向扫描线向右扫描开始
			p.rs = GetRValue(src[i + j * w]);
			p.gs = GetGValue(src[i + j * w]);
			p.bs = GetBValue(src[i + j * w]);
			if (y[j] == true) {
				if (p.rs >= p.rl && p.rs <= p.rr && p.gs >= p.gl && p.gs <= p.gr && p.bs >= p.bl && p.bs <= p.br || src[i + j * w] == HIDE_COLOR) {
					y[j] = true;
					src[i + j * w] = HIDE_COLOR;
				}
				else
					y[j] = false;
			}
		}
	}
	for (j = 0; j < h; ++j) {//建立右方竖向扫描线
		p.rs = GetRValue(src[w - 1 + j * w]);
		p.gs = GetGValue(src[w - 1 + j * w]);
		p.bs = GetBValue(src[w - 1 + j * w]);
		if (p.rs >= p.rl && p.rs <= p.rr && p.gs >= p.gl && p.gs <= p.gr && p.bs >= p.bl && p.bs <= p.br || src[w - 1 + j * w] == HIDE_COLOR) {
			y[j] = true;
			src[w - 1 + j * w] = HIDE_COLOR;
		}
		else
			y[j] = false;
	}
	for (i = w - 1; i >= 0; --i) {
		for (j = 0; j < h; ++j) {//右方竖向扫描线向左扫描开始
			p.rs = GetRValue(src[i + j * w]);
			p.gs = GetGValue(src[i + j * w]);
			p.bs = GetBValue(src[i + j * w]);
			if (y[j] == true) {
				if (p.rs >= p.rl && p.rs <= p.rr && p.gs >= p.gl && p.gs <= p.gr && p.bs >= p.bl && p.bs <= p.br || src[i + j * w] == HIDE_COLOR) {
					y[j] = true;
					src[i + j * w] = HIDE_COLOR;
				}
				else
					y[j] = false;
			}
		}
	}
	free(x);
	free(y);
}
int main()
{
	IMAGE img;
	COLORREF color = 0xffffff;//要被替换的颜色 这里是白色
	int color_go = 20;//偏差20范围的颜色视作为相似
	color_group p;//生成实例
	p.r = GetRValue(color);//获得要被替换的颜色的RGB三色
	p.g = GetGValue(color);
	p.b = GetBValue(color);
	p.rl = p.r < color_go ? 0 : p.r - color_go;//color_go是误差值,这里用来获取误差区间,为了判断相似色
	p.gl = p.g < color_go ? 0 : p.g - color_go;
	p.bl = p.b < color_go ? 0 : p.b - color_go;
	p.rr = p.r > 255 - color_go ? 255 : 255 - color_go;
	p.gr = p.g > 255 - color_go ? 255 : 255 - color_go;
	p.br = p.b > 255 - color_go ? 255 : 255 - color_go;
	loadimage(&img, TEXT("a.jpg"));//装载目标图像:TEXT("路径+文件名")这种写法是为了自适应当前编码
	initgraph(img.getwidth()*2, img.getheight());//准备演示
	HWND hWnd = GetHWnd();//获得窗口句柄
	int ExdStyle = (int)GetWindowLong(hWnd, GWL_EXSTYLE);
	SetWindowLong(hWnd, GWL_EXSTYLE, ExdStyle | WS_EX_LAYERED);
	SetLayeredWindowAttributes(hWnd, HIDE_COLOR, 255, LWA_COLORKEY);//指定为颜色HIDE_COLOR透明
	setbkcolor(HIDE_COLOR);//设置设备背景色
	cleardevice();//清洗背景
	putimage(0, 0, &img);//输出原图像
	ChangImg(img, color, color_go, p);//开始除去除该颜色
	putimage(img.getwidth(), 0, &img);//输出对比图像
	_getch();//如果这里出错就换成getch();
	closegraph();
	return 0;
}

思考:这样是不会误杀人物内部颜色了,但是有些缝隙的颜色却没有清除掉,这该怎么去除?

答:仍然有办法,下一篇博客将会展示一种更好的算法,可以完美去除人物凹边内的残余颜色

这是也一种简单的算法,个人自己写的,当时在写桌宠,一心想着怎么透明,如今初入DSDN,将解决的算法一步步的分享出来,请各位多多包涵,有文章逻辑或排版问题还请指出。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值