基于python win32setpixel api 实现计算机图形学相关操作

本文介绍了使用Python的win32api进行计算机图形学操作,包括画线、中心圆算法、扫描线填充和裁剪算法。通过win32setpixel API直接在显示器上绘制图像,探讨了为何选择Python而非C++,并分享了实现的各种图形算法及代码示例,展示了裁剪多边形的实时效果。
摘要由CSDN通过智能技术生成

最近读研期间上了计算机可视化的课,老师也对计算机图形学的实现布置了相关的作业。虽然我没有系统地学过图形可视化的课,但是我之前逆向过一些游戏引擎,除了保护驱动之外, 因为要做透视 ,接触过一些计算机图形学的基础常识。这次的作业主要分为2个主要模块,一个是实现画线,画圆的算法,还有填充的算法,以及裁剪的算法。

之前工作的时候虽然参与过一些数据可视化大屏的设计,但是当时主要的工作使用Echarts或者G2做业务组件开发,并没有对画线,填充,裁剪等基础算法做过实现。这次就着这个机会我就想了解一些。实现的效果如下(动图加载可能有些慢):

扫描线填充过程

裁剪过程(根据鼠标位置,实时裁剪多边形,右边的蓝色是裁剪后的图形)

为什么选择win32 api画图

选择win32的原因是我想做一些与众不同的实现方法,比起用D3或者Echarts这种webGL的实现方式,我更想直接在显示器上画出图像,看起来更极客一些。这也导致了录屏软件没办法捕捉,只能用手机来录制:joy:

为什么不选C++而选择python

主要是python能对内存做个管理,C++直接调这种底层的接口会把内存搞坏掉,导致电脑变得特别卡。。不信大家可以在电脑上编译运行这段代码2分钟试一试,如果你电脑没炸,算你有钱。。

#include <windows.h>
// g++ a.cpp -o a.exe -lgdi32 && a.exe
void bresenham(int x0,int y0,int x1,int y1){
    int dx = abs(x1-x0);
    int dy = abs(y1-y0);
    int sx = x0<x1 ? 1 : -1;
    int sy = y0<y1 ? 1 : -1;
    int err = dx-dy;
    int e2;
    while(1){
        SetPixel(GetDC(0),x0,y0,RGB(255,0,0));
        if(x0==x1 && y0==y1) break;
        e2 = 2*err;
        if(e2>-dy){
            err = err-dy;
            x0 = x0+sx;
        }
        if(e2<dx){
            err = err+dx;
            y0 = y0+sy;
        }
    }
}


void draw_polygon(int x[], int y[], int n)
{
    int i;
    for (i = 0; i < n - 1; i++)
        bresenham(x[i], y[i], x[i + 1], y[i + 1]);
    bresenham(x[n - 1], y[n - 1], x[0], y[0]);
}


int main()
{
    HDC hdc = GetDC(0);
    int x[4] = {100,200,300,100};
    int y[4] = {100,100,200,200};
    while (1)
    {
        draw_polygon(x,y,4);
        ReleaseDC(0, hdc);
    }
    return 0;
}

画线

对于画线部分,我这里使用了一个叫bresenham算法。。虽然我念不出名字,但是这个算法能够帮助我们实现画线运算,还有后面的中心圆填充,多边形绘画等方法。而且不通过浮点数的运算,直接变成整数运算,算法实现的函数如下所示,看起来比较简单,运行速度也很快。

def bresenham(x0, y0, x1, y1 , color):
    dx = abs(x1 - x0)
    dy = abs(y1 - y0)
    sx = 1 if x0 < x1 else -1
    sy = 1 if y0 < y1 else -1
    err = dx - dy
    while True:
        win32gui.SetPixel(dc, x0, y0, color)
        if x0 == x1 and y0 == y1:
            break
        e2 = 2 * err
        if e2 > -dy:
            err -= dy
            x0 += sx
        if e2 < dx:
            err += dx
            y0 += sy

我的屏幕分辨率是1920x1080的,只要在电脑里调用这个函数,把两个点的坐标填进去,就可以在显示器屏幕上画一条线。

中心圆算法

这个中心圆算法相对来说就比画线的算法在理解上面难很多,但是实现起来更简单一些,分成8个关于直线的和坐标轴对称的区域画圆,因此知道一个就可以画出其他几个,下面是实现过程。

def draw_circle(x, y, r):
    x0 = 0
    y0 = r
    d = 3 - 2 * r
    while x0 <= y0:
        win32gui.SetPixel(dc, x + x0, y + y0, 0xffffff)
        win32gui.SetPixel(dc, x + y0, y + x0, 0xffffff)
        win32gui.SetPixel(dc, x - y0, y + x0, 0xffffff)
        win32gui.SetPixel(dc, x - x0, y + y0, 0xffffff)
        win32gui.SetPixel(dc, x - x0, y - y0, 0xffffff)
        win32gui.SetPixel(dc, x - y0, y - x0, 0xffffff)
        win32gui.SetPixel(dc, x + y0, y - x0, 0xffffff)
        win32gui.SetPixel(dc, x + x0, y - y0, 0xffffff)
        if d < 0:
            d += 4 * x0 + 6
        else:
            d += 4 * (x0 - y0) + 10
            y0 -= 1
        x0 += 1

在中心圆填充这里,可以取个巧,把几个顶点直接用画线的算法一行一行填充上去。就可以实现下面的效果。代码如下

# 画实心圆
def draw_circle_fill(x0, y0, r):
    x = 0
    y = r
    d = 3 - 2 * r
    while x <= y:
        time.sleep(0.01)
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值