千家信息网

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

发表于:2025-11-08 作者:千家信息网编辑
千家信息网最后更新 2025年11月08日,本篇内容介绍了"基于python win32setpixel api怎么实现计算机图形学相关操作"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这
千家信息网最后更新 2025年11月08日基于python win32setpixel api怎么实现计算机图形学相关操作

本篇内容介绍了"基于python win32setpixel api怎么实现计算机图形学相关操作"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

扫描线填充过程

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

为什么选择win32 api画图

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

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

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

#include // g++ a.cpp -o a.exe -lgdi32 && a.exevoid bresenham(int x0,int y0,int x1,int y1){    int dx = abs(x1-x0);    int dy = abs(y1-y0);    int sx = x0-dy){            err = err-dy;            x0 = x0+sx;        }        if(e2

画线

对于画线部分,我这里使用了一个叫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)        bresenham(x0 + x, y0 + y, x0 - x, y0 + y)        time.sleep(0.01)        bresenham(x0 + x, y0 - y, x0 - x, y0 - y)        time.sleep(0.01)        bresenham(x0 + y, y0 + x, x0 - y, y0 + x)        time.sleep(0.01)        bresenham(x0 + y, y0 - x, x0 - y, y0 - x)        if d < 0:            d += 4 * x + 6        else:            d += 4 * (x - y) + 10            y -= 1        x += 1

扫描线填充

扫描线填充的算法就比较难实现了,需要找到起始的种子,还有每行的种子,因为我这里仅仅用顶点实现起来过于复杂,就索性偷懒用了数组。下面的算法实现部分仅供参考,具体的实现包括种子的选择等等,可以更好一些。

maps = [[0 for x in range(0,400)] for x in range(0,400)]for i in range(200,300):    maps[i][200] = 1    maps[200][i] = 1    maps[i][300] = 1    maps[300][i] = 1for i in range(230,270):    maps[i][230] = 1    maps[i][270] = 1    maps[230][i] = 1    maps[270][i] = 1# 扫描填充mapsdef scan_fill():    seed = (271,296)    stack = []    stack.append(seed)    while len(stack) > 0:        (x,y) = stack.pop()        # 如果已经被填充过,则跳过        if(maps[x][y] == 1):            continue        # 横向填充并记录lx rx        i=0        time.sleep(0.01)        while(maps[x+i][y] == 0):            maps[x+i][y] = 1            win32gui.SetPixel(dc, x+i, y, 0xffffff)            i += 1        rx = x+i-1        i=1        while(maps[x-i][y] == 0):            maps[x-i][y] = 1            win32gui.SetPixel(dc, x-i, y, 0xffffff)            i+=1        lx = x-i+1        # 下一个种子        if y+1>=300:            continue        i=0        while(maps[lx+i][y+1] == 0):            if(maps[lx+i+1][y+1]==1):                stack.append((lx+i,y+1))                break            i+=1        i=0        while(maps[rx-i][y+1] == 0):            if(maps[rx-i-1][y+1]==1):                stack.append((rx-i,y+1))                break            i+=1        if y-1<=0:            continue        i=0        while(maps[lx+i][y-1] == 0):            if(maps[lx+i+1][y-1]==1):                stack.append((lx+i,y-1))                break            i+=1        i=0        while(maps[rx-i][y-1] == 0):            if(maps[rx-i-1][y-1]==1):                stack.append((rx-i,y-1))                break            i+=1scan_fill()

这里是所有代码

上面的代码都是剪切过的,完整的代码如下所示,运行后大家就可以在显示器上看到运行过程:

import timeimport win32guidc = win32gui.GetDC(0)maps = [[0 for x in range(0,400)] for x in range(0,400)]for i in range(200,300):    maps[i][200] = 1    maps[200][i] = 1    maps[i][300] = 1    maps[300][i] = 1for i in range(230,270):    maps[i][230] = 1    maps[i][270] = 1    maps[230][i] = 1    maps[270][i] = 1# 中点算法画圆def draw_circle(x, y, r):    x0 = 0    y0 = r    d = 3 - 2 * r    while x0 <= y0:        time.sleep(0.01)        win32gui.SetPixel(dc, x + x0, y + y0, 0xffffff)        time.sleep(0.01)        win32gui.SetPixel(dc, x + y0, y + x0, 0xffffff)        time.sleep(0.01)        win32gui.SetPixel(dc, x - y0, y + x0, 0xffffff)        time.sleep(0.01)        win32gui.SetPixel(dc, x - x0, y + y0, 0xffffff)        time.sleep(0.01)        win32gui.SetPixel(dc, x - x0, y - y0, 0xffffff)        time.sleep(0.01)        win32gui.SetPixel(dc, x - y0, y - x0, 0xffffff)        time.sleep(0.01)        win32gui.SetPixel(dc, x + y0, y - x0, 0xffffff)        time.sleep(0.01)        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 bresenham(x0, y0, x1, y1):    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:        #time.sleep(0.01)        win32gui.SetPixel(dc, x0, y0, 0xffffff)        if x0 == x1 and y0 == y1:            break        e2 = 2 * err        if e2 > -dy:            err -= dy            x0 += sx        if e2 < dx:            err += dx            y0 += sy# 画实心圆def draw_circle_fill(x0, y0, r):    x = 0    y = r    d = 3 - 2 * r    while x <= y:        time.sleep(0.01)        bresenham(x0 + x, y0 + y, x0 - x, y0 + y)        time.sleep(0.01)        bresenham(x0 + x, y0 - y, x0 - x, y0 - y)        time.sleep(0.01)        bresenham(x0 + y, y0 + x, x0 - y, y0 + x)        time.sleep(0.01)        bresenham(x0 + y, y0 - x, x0 - y, y0 - x)        if d < 0:            d += 4 * x + 6        else:            d += 4 * (x - y) + 10            y -= 1        x += 1# 画多边形def draw_polygon(points):    for i in range(len(points)):        x0 = points[i][0]        y0 = points[i][1]        x1 = points[(i + 1) % len(points)][0]        y1 = points[(i + 1) % len(points)][1]        bresenham(x0, y0, x1, y1)# 画椭圆def draw_ellipse(x0, y0, a, b):    x = 0    y = b    a2 = a * a    b2 = b * b    d = b2 - a2 * b + a2 / 4    while b2 * x <= a2 * y:        win32gui.SetPixel(dc, x0 + x, y0 + y, 0xffffff)        win32gui.SetPixel(dc, x0 - x, y0 + y, 0xffffff)        win32gui.SetPixel(dc, x0 + x, y0 - y, 0xffffff)        win32gui.SetPixel(dc, x0 - x, y0 - y, 0xffffff)        if d < 0:            d += b2 * (2 * x + 3)        else:            d += b2 * (2 * x - 2 * y + 5)            y -= 1        x += 1    d1 = b2 * (x + 0.5) * (x + 0.5) + a2 * (y - 1) * (y - 1) - a2 * b2    while y >= 0:        win32gui.SetPixel(dc, x0 + x, y0 + y, 0xffffff)        win32gui.SetPixel(dc, x0 - x, y0 + y, 0xffffff)        win32gui.SetPixel(dc, x0 + x, y0 - y, 0xffffff)        win32gui.SetPixel(dc, x0 - x, y0 - y, 0xffffff)        if d1 > 0:            d1 -= a2 * (2 * y - 1)        d1 += b2 * (2 * x + 3)        x += 1        y -= 1# 画矩形def draw_rectangle(x0, y0, x1, y1):    bresenham(x0, y0, x1, y0)    bresenham(x1, y0, x1, y1)    bresenham(x1, y1, x0, y1)    bresenham(x0, y1, x0, y0)# 扫描填充mapsdef scan_fill():    seed = (271,296)    stack = []    stack.append(seed)    while len(stack) > 0:        (x,y) = stack.pop()        # 如果已经被填充过,则跳过        if(maps[x][y] == 1):            continue        # 横向填充并记录lx rx        i=0        time.sleep(0.01)        while(maps[x+i][y] == 0):            maps[x+i][y] = 1            win32gui.SetPixel(dc, x+i, y, 0xffffff)            i += 1        rx = x+i-1        i=1        while(maps[x-i][y] == 0):            maps[x-i][y] = 1                        win32gui.SetPixel(dc, x-i, y, 0xffffff)            i+=1        lx = x-i+1        # 下一个种子        if y+1>=300:            continue        i=0        while(maps[lx+i][y+1] == 0):            if(maps[lx+i+1][y+1]==1):                stack.append((lx+i,y+1))                break            i+=1        i=0        while(maps[rx-i][y+1] == 0):            if(maps[rx-i-1][y+1]==1):                stack.append((rx-i,y+1))                break            i+=1        if y-1<=0:            continue        i=0        while(maps[lx+i][y-1] == 0):            if(maps[lx+i+1][y-1]==1):                stack.append((lx+i,y-1))                break            i+=1        i=0        while(maps[rx-i][y-1] == 0):            if(maps[rx-i-1][y-1]==1):                stack.append((rx-i,y-1))                break            i+=1scan_fill()while True:    # 画线        bresenham(400, 900, 1000, 700)    # 填充圆    draw_circle_fill(900, 500, 100)    # 中心圆    draw_circle(1000, 200, 100)    # 椭圆    draw_ellipse(1500, 200, 100, 100)    # 矩形    draw_rectangle(1100, 400, 1200, 500)    # 多边形    draw_polygon([(900, 1000), (800, 800), (1000, 900), (1100, 1000)])    #三角形    draw_polygon([(400, 200), (500, 300), (600, 200)])

裁剪

裁剪这里简直就是我的噩梦,因为我之前为了极客选择了仅仅知道顶点就画出裁剪过的多边形,导致我没有数组,只能设计更极客的算法。
最后我找到了一种裁剪凸多边形的办法,大致就是找到每个线段的交点,然后顺时针方向对交点和在主多边形,副多边形的顶点排序,最后就可以实现裁剪。代码超级复杂,

import win32guiimport mathimport pygamedc = win32gui.GetDC(0)# 获取鼠标的位置mouse_x=win32gui.GetCursorPos()[0]mouse_y=win32gui.GetCursorPos()[1]temp = win32gui.GetCursorPos()def get_mouse_pos():    global mouse_x, mouse_y    mouse_x = win32gui.GetCursorPos()[0]    mouse_y = win32gui.GetCursorPos()[1]clock = pygame.time.Clock()temp2 = []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 += sydef draw_rectangle(x0, y0, x1, y1):    bresenham(x0, y0, x1, y0,0xffffff)    bresenham(x1, y0, x1, y1,0xffffff)    bresenham(x1, y1, x0, y1,0xffffff)    bresenham(x0, y1, x0, y0,0xffffff)def draw_polygon(points):    for i in range(len(points)):        x0 = points[i][0]        y0 = points[i][1]        x1 = points[(i + 1) % len(points)][0]        y1 = points[(i + 1) % len(points)][1]        bresenham(x0, y0, x1, y1,0x00ff00)def draw_polygon_black(points):    for i in range(len(points)):        x0 = points[i][0]        y0 = points[i][1]        x1 = points[(i + 1) % len(points)][0]        y1 = points[(i + 1) % len(points)][1]        bresenham(x0, y0, x1, y1,0x000000)# 线段是否相交def IsRectCross(p1x, p1y, p2x, p2y, q1x, q1y, q2x, q2y):    return min(p1x,p2x) <= max(q1x,q2x) and min(q1x,q2x) <= max(p1x,p2x) and min(p1y,p2y) <= max(q1y,q2y) and min(q1y,q2y) <= max(p1y,p2y)def IsLineSegmentCross(pFirst1x,pFirst1y,pFirst2x,pFirst2y,pSecond1x,pSecond1y,pSecond2x,pSecond2y):    line1 = pFirst1x * (pSecond1y - pFirst2y) + pFirst2x * (pFirst1y - pSecond1y) + pSecond1x * (pFirst2y - pFirst1y)    line2 = pFirst1x * (pSecond2y - pFirst2y) + pFirst2x * (pFirst1y - pSecond2y) + pSecond2x * (pFirst2y - pFirst1y)    if (((line1 ^ line2) >= 0) and not (line1 == 0 and line2 == 0)):        return False    line1 = pSecond1x * (pFirst1y - pSecond2y) + pSecond2x * (pSecond1y - pFirst1y) + pFirst1x * (pSecond2y - pSecond1y)    line2 = pSecond1x * (pFirst2y - pSecond2y) + pSecond2x * (pSecond1y - pFirst2y) + pFirst2x * (pSecond2y - pSecond1y)    if (((line1 ^ line2) >= 0) and not (line1 == 0 and line2 == 0)):        return False    return Truedef GetCrossPoint(p1x, p1y, p2x, p2y, q1x, q1y, q2x, q2y):    if(IsRectCross(p1x, p1y, p2x, p2y, q1x, q1y, q2x, q2y)):        if (IsLineSegmentCross(p1x, p1y, p2x, p2y, q1x, q1y, q2x, q2y)):            tmpLeft = (q2x - q1x) * (p1y - p2y) - (p2x - p1x) * (q1y - q2y)            tmpRight = (p1y - q1y) * (p2x - p1x) * (q2x - q1x) + q1x * (q2y - q1y) * (p2x - p1x) - p1x * (p2y - p1y) * (q2x - q1x)            if (tmpLeft == 0):                return None            x = (int)(tmpRight/tmpLeft)            tmpLeft = (p1x - p2x) * (q2y - q1y) - (p2y - p1y) * (q1x - q2x)            tmpRight = p2y * (p1x - p2x) * (q2y - q1y) + (q2x- p2x) * (q2y - q1y) * (p1y - p2y) - q2y * (q1x - q2x) * (p2y - p1y)            if (tmpLeft == 0):                return None            y = (int)(tmpRight/tmpLeft)            return (x,y)        else:            return None    else:        return Nonedef draw_rectangle_black(x0, y0, x1, y1):    bresenham(x0, y0, x1, y0,0x000000)    bresenham(x1, y0, x1, y1,0x000000)    bresenham(x1, y1, x0, y1,0x000000)    bresenham(x0, y1, x0, y0,0x000000)# 判断点是否在多边形内def IsPointInPolygon(points, x, y):    nCross = 0    for i in range(len(points)):        p1x = points[i][0]        p1y = points[i][1]        p2x = points[(i + 1) % len(points)][0]        p2y = points[(i + 1) % len(points)][1]        if (y > min(p1y, p2y)):            if (y <= max(p1y, p2y)):                if (x <= max(p1x, p2x)):                    if (p1y != p2y):                        xinters = (y - p1y) * (p2x - p1x) / (p2y - p1y) + p1x                    if (p1x == p2x or x <= xinters):                        nCross += 1    if (nCross % 2 == 0):        return False    else:        return Truedef getNonRepeatList(data):    new_data = []    for i in range(len(data)):        if data[i] not in new_data:            new_data.append(data[i])    return new_data# 判断两多边形重叠部分 返回一个多边形def IsPolygonCross(points1, points2):    result = []    for i in range(len(points1)):        p1x = points1[i][0]        p1y = points1[i][1]        p2x = points1[(i + 1) % len(points1)][0]        p2y = points1[(i + 1) % len(points1)][1]        for j in range(len(points2)):            q1x = points2[j][0]            q1y = points2[j][1]            q2x = points2[(j + 1) % len(points2)][0]            q2y = points2[(j + 1) % len(points2)][1]            if (IsPointInPolygon(points1, q1x, q1y) and (q1x, q1y) not in result):                result.append((q1x, q1y))            if (IsPointInPolygon(points1, q2x, q2y) and (q2x, q2y) not in result):                result.append((q2x, q2y))            if (IsPointInPolygon(points2, p1x, p1y) and (p1x, p1y) not in result):                result.append((p1x, p1y))            if (IsPointInPolygon(points2, p2x, p2y) and (p2x, p2y) not in result):                result.append((p2x, p2y))            if (IsRectCross(p1x, p1y, p2x, p2y, q1x, q1y, q2x, q2y)):                if  GetCrossPoint(p1x, p1y, p2x, p2y, q1x, q1y, q2x, q2y) != None:                    (x, y) = GetCrossPoint(p1x, p1y, p2x, p2y, q1x, q1y, q2x, q2y)                    result.append((x, y))    if (result == []):        return result    return (sort_points_in_clockwise_order(result))w = 60h = 100def draw_polygon_red(points):    for i in range(len(points)):        x0 = points[i][0]        y0 = points[i][1]        x1 = points[(i + 1) % len(points)][0]        y1 = points[(i + 1) % len(points)][1]        bresenham(x0, y0, x1, y1,0xff0000)def sort_points_in_clockwise_order(points):    center = (0, 0)    for point in points:        center = (center[0] + point[0], center[1] + point[1])    center = (center[0] / len(points), center[1] / len(points))    points_copy = list(points)    points_copy.sort(key=lambda point: math.atan2(point[0] - center[0], point[1] - center[1]))    res = []    for i in points_copy:       res.append((i[0]+500,i[1]))    return respolygon_Points = [(600,500), (800,500), (900, 600), (900, 400),(600,300)]while True:    draw_rectangle_black(temp[0],temp[1],temp[0]+w,temp[1]+h)    draw_rectangle(mouse_x,mouse_y,mouse_x+w,mouse_y+h)    temp = (mouse_x,mouse_y)    get_mouse_pos()    draw_polygon(polygon_Points)    res =  IsPolygonCross(polygon_Points,[(mouse_x,mouse_y),(mouse_x+w,mouse_y),(mouse_x+w,mouse_y+h),(mouse_x,mouse_y+h)])     print(res)    if temp2 != []:        draw_polygon_black(temp2)    if res != [] and res != None:        draw_polygon_red(res)        temp2 = res    clock.tick(120)# 60帧

"基于python win32setpixel api怎么实现计算机图形学相关操作"的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注网站,小编将为大家输出更多高质量的实用文章!

算法 多边形 代码 种子 过程 选择 电脑 顶点 运行 图形 扫描线 显示器 部分 面的 运算 计算机 复杂 一行 交点 位置 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 工业网络安全配置 济南专业软件开发服务 网络技术服务费用什么单位名称 本数据库并发控制真题 服务器bmc口集中管理 让网络安全为国泰民保驾护航 民勤软件开发项目管理 网络安全师得学多长时间 天意网络安全绘画 梅州自主可控软件开发代理价格 web服务器cpu 网络安全法 拘留 厦门软件开发有限公司郑文健 我的世界服务器麦块 聊天软件后台数据库设计 黑龙江农青网络技术合伙企业 苏州服务器pdu电源定制 哈尔滨海上飞互联网科技有限公司 江苏北斗时间服务器设置云主机 服务器5块硬盘安全吗 剑网3最新服务器列表 第六次网络安全与信息化会议 简历数据库尽快回复通知 静海区企业网络技术创造辉煌 梅州自主可控软件开发代理价格 web服务器cpu 华为数据库要在平遥修建 期货交易系统软件开发公司 数字货币下的网络安全 软件开发人工外包毛利
0