图片滤镜系列:波浪线叠加效果(手动抗锯齿)
2011-7-25 ~ 2023-2-5
(0)
程序简介
我念初中的时候买过一盘国外原版的磁带:贝多芬第九交响乐《合唱》。磁带很是精美,硬纸壳压出了立体的金色贝多芬头像,并且还有第二层封面,是叠加在金色波浪线上的贝多芬头像。这个波浪线叠加的效果很有趣,我一直想写个程序实现这种效果,无奈总是抽不出时间,今天可算把这件事情给做了。
只是由于屏幕分辨率太低,还是无法和印刷的效果相媲美。而且,由于磁带已经找不到了,我只是按照我想象中的样子做的。
没有抗锯齿的波浪线会看起来很粗糙,所以针对 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;
}
添加评论
取消回复