慢羊羊的空间

无为,无我,无欲,居下,清虚,自然

图片滤镜系列:波浪线叠加效果(手动抗锯齿) 银牌收录

程序简介

我念初中的时候买过一盘国外原版的磁带:贝多芬第九交响乐《合唱》。磁带很是精美,硬纸壳压出了立体的金色贝多芬头像,并且还有第二层封面,是叠加在金色波浪线上的贝多芬头像。这个波浪线叠加的效果很有趣,我一直想写个程序实现这种效果,无奈总是抽不出时间,今天可算把这件事情给做了。

只是由于屏幕分辨率太低,还是无法和印刷的效果相媲美。而且,由于磁带已经找不到了,我只是按照我想象中的样子做的。

没有抗锯齿的波浪线会看起来很粗糙,所以针对 y 轴加了手动抗锯齿的算法。算法不复杂,就是根据 y 坐标的浮点值,分别计算出上下两个相邻像素上的值,绘制即可。

执行效果

我就不弄贝多芬的头像了,换了星爷的靓照。原图:

将原图改名为 src.jpg,保存到项目路径下。执行后可以看到效果:

还可以拿好朋友的照片来生成这个有趣的效果(注意,必须将图片调整为 640 x 480。如果需要别的尺寸,请自行修改代码):

全部源代码如下:

注:src.jpg 就是源图片的名字,该图片的大小必须是 640 x 480,另外建议用简单的背景,大一点的头像,效果会更理想。

///////////////////////////////////////////////////
// 程序名称:图片滤镜系列:波浪线叠加效果
// 编译环境:Visual C++ 6.0 / 2010,EasyX_20220901
// 作  者:慢羊羊 <yw80@qq.com>
// 最后修改:2011-7-25
//
#include <graphics.h>
#include <conio.h>
#include <math.h>

#define PI		3.14159265359
#define PEN		0x4d8399		// 绘图颜色(金色)
#define RATIO	GetBValue		// 获取 PEN 的主要颜色分量

IMAGE g_img;					// 保存有图片的全局 IMAGE 对象


// 画点(叠加法) (透明 0 <= alpha <= 1 不透明)
void mixpixel(int x, int y, double alpha)
{
	double f1 = (0xff - RATIO(getpixel(x, y))) / (float)(0xff - RATIO(PEN));
	double f = f1 + alpha;
	if (f > 1)	f = 1;

	COLORREF c = RGB(	GetRValue(PEN) + (0xff - GetRValue(PEN)) * (1 - f),
						GetGValue(PEN) + (0xff - GetGValue(PEN)) * (1 - f),
						GetBValue(PEN) + (0xff - GetBValue(PEN)) * (1 - f)	);

	putpixel(x, y, c);
}


// 画点(支持浮点 y 坐标)
void mypixel(int x, double y)
{
	int y1 = (int)floor(y);
	int y2 = y1 + 1;

	mixpixel(x, y1, y2 - y);
	mixpixel(x, y2, y - y1);
}


// 画纵向线
void myline(int x, double y)
{
	// 获取灰度图片指定位置的颜色平均值
	SetWorkingImage(&g_img);
	int sum = 0;
	int count = 0;
	for(int i = (int)(y - 2 + 0.5); i <= (int)(y + 2 + 0.5); i++)
		if (i >= 0)
		{
			count++;
			sum += (0xff & getpixel(x, i));
		}
	if (count > 0)
		sum = (int)(sum / (float)count + 0.5);
	SetWorkingImage(NULL);

	// 根据获取到的颜色值,画等效线
	if (sum >= 192)
		mypixel(x, y);
	else
	{
		int y1 = (int)y;
		sum += (int)(64 * (1 - (y - y1)));
		mixpixel(x, y1, (1 - (y - y1)));
		while(sum < 192)
		{
			sum += 64;
			mixpixel(x, ++y1, 1);
		}
		mixpixel(x, ++y1, 1 - (sum - 191) / 64.0);
	}
}


// 主函数
int main()
{
	// 初始化
	initgraph(640, 480);				// 创建绘图窗口
	loadimage(&g_img, _T("src.jpg"));	// 加载图片(必须为 640 x 480)
	setbkcolor(0xffffff);
	cleardevice();

	// 将图片转换为灰度图片
	DWORD* buf = GetImageBuffer(&g_img);
	for(int i = 0; i < 640 * 480; i++)
	{
		buf[i] = BGR(RGBtoGRAY(BGR(buf[i])));
	}

	// 画背景正弦曲线,并在此基础上叠加图像
	for(int x = 0; x < 640; x++)
	{
		double y1 = sin(x / 30.0 / PI) * 20.8;
		for(double y = y1 - 20; y < 480; y+=5)
			myline(x, y);
	}

	// 按任意键退出
	_getch();
	closegraph();
	return 0;
}

添加评论