一、向量和矩阵的基本运算
【计算机视觉】二、图像形成:1、向量和矩阵的基本运算:线性变换与齐次坐标
二、几何基元和变换
1、几何基元(Geometric Primitives)
几何基元是计算机图形学中最基本的图形对象,它们是构建更复杂图形的基础单元。常见的几何基元包括:
- 点(Point): 由一对或一组坐标值表示的零维对象。
- 线段(Line Segment): 由两个端点确定的一维对象。
- 多边形(Polygon): 由一系列顶点连接而成的闭合平面图形,是二维对象。
- 曲线(Curve): 由一系列控制点和方程确定的平滑曲线,如贝塞尔曲线、样条曲线等。
- 圆(Circle): 由一个圆心和半径确定的二维闭合曲线。
- 球体(Sphere): 由一个球心和半径确定的三维闭合曲面。
这些基本的几何基元可以通过组合、变换等操作构建出更加复杂的图形对象,如三维模型、场景等。
2、几何变换(Geometric Transformations)
【计算机视觉】二、图像形成:2、几何基元和几何变换:2D变换
2D变换编辑器
0. 程序简介
本人使用 Pygame 库实现了一个图像变换程序,提供六种不同的变换操作,分别是平移、旋转、等比缩放、缩放、镜像和剪切。可以通过点击相应的按钮选择要执行的变换操作,然后使用鼠标拖动来调整变换的参数,实时查看变换后的图像效果。
环境说明
安装Pygame库
代码语言:javascript
复制
pip install pygame
程序流程
- 确保图像
"image.jpg"
文件与Python文件在同一目录下。 - 运行Python文件,将会弹出一个888x888的窗口,显示原始图像和一排按钮。
- 点击任意一个按钮,选择相应的变换操作。按钮及对应的变换操作如下:
代码语言:txt
复制
- “Translate”: 平移变换
- “Rotate”: 旋转变换
- “Isotropic Scale”: 等比缩放变换
- “Scale”: 缩放变换
- “Mirror”: 镜像变换
- “Shear”: 剪切变换按住鼠标左键,并拖拽鼠标,可以实时调整变换效果:
代码语言:txt
复制
- 平移变换: 拖拽方向和距离决定平移的偏移量。
- 旋转变换: 拖拽的水平距离决定旋转角度。
- 等比缩放变换: 拖拽的水平距离决定缩放比例。
- 缩放变换: 拖拽的水平距离决定x方向缩放比例,垂直距离决定y方向缩放比例。
- 镜像变换: 向右拖拽进行水平镜像,向左拖拽进行垂直镜像。
- 剪切变换: 拖拽的水平距离决定x方向剪切系数,垂直距离决定y方向剪切系数。变换后的图像将显示在原始图像的右侧。
- 窗口上方会显示当前选择的变换类型。
- 要退出程序,请关闭窗口或按下键盘上的"Esc"键。
1. 各种变换
平移变换
代码语言:javascript
复制
def translate(img, x, y):
width, height = img.get_size()
translated_img = pygame.Surface((window_width, window_height), pygame.SRCALPHA)
translated_img.blit(img, (x, y))
return translated_img
旋转变换
代码语言:javascript
复制
def rotate(img, angle):
rotated_img = pygame.transform.rotate(img, angle)
return rotated_img
等比缩放变换
代码语言:javascript
复制
def isotropic_scale(img, scale_factor):
width, height = img.get_size()
new_size = (int(width * scale_factor), int(height * scale_factor))
scaled_img = pygame.transform.scale(img, new_size)
return scaled_img
缩放变换
代码语言:javascript
复制
def scale(img, scale_x, scale_y):
width, height = img.get_size()
new_width = int(width * scale_x)
new_height = int(height * scale_y)
scaled_img = pygame.transform.scale(img, (new_width, new_height))
return scaled_img
镜像变换
代码语言:javascript
复制
def mirror(img, mirror_type):
if mirror_type == 'horizontal':
mirrored_img = pygame.transform.flip(img, True, False)
elif mirror_type == 'vertical':
mirrored_img = pygame.transform.flip(img, False, True)
else:
return img
return mirrored_img
剪切变换
代码语言:javascript
复制
def shear(img, shear_x, shear_y):
width, height = img.get_size()
sheared_img = pygame.Surface((width + abs(shear_x * height), height + abs(shear_y * width)))
sheared_img.set_colorkey((0, 0, 0))
for x in range(width):
for y in range(height):
sheared_img.blit(img, (x + shear_x * y, y + shear_y * x), (x, y, 1, 1))
return sheared_img
2. 按钮
按钮类
代码语言:javascript
复制
class Button: def __init__(self, x, y, width, height, text, color): self.rect = pygame.Rect(x, y, width, height) self.text = text self.color = color
def draw(self, surface): pygame.draw.rect(surface, self.color, self.rect) font = pygame.font.Font(None, 24) text = font.render(self.text, True, (255, 255, 255)) text_rect = text.get_rect(center=self.rect.center) surface.blit(text, text_rect) def is_clicked(self, pos): return self.rect.collidepoint(pos)</code></pre></div></div><h6 id="954616" name="%E5%88%9B%E5%BB%BA%E6%8C%89%E9%92%AE">创建按钮</h6><div class="rno-markdown-code"><div class="rno-markdown-code-toolbar"><div class="rno-markdown-code-toolbar-info"><div class="rno-markdown-code-toolbar-item is-type"><span class="is-m-hidden">代码语言:</span>javascript</div></div><div class="rno-markdown-code-toolbar-opt"><div class="rno-markdown-code-toolbar-copy"><i class="icon-copy"></i><span class="is-m-hidden">复制</span></div></div></div><div class="developer-code-block"><pre class="prism-token token line-numbers language-javascript"><code class="language-javascript" style="margin-left:0">buttons = [ Button(50, 50, 150, 50, "Translate", (255, 0, 0)), Button(250, 50, 150, 50, "Rotate", (255, 165, 0)), Button(450, 50, 150, 50, "Isotropic Scale", (0, 255, 0)), Button(650, 50, 150, 50, "Scale", (0, 255, 255)), Button(50, 150, 150, 50, "Mirror", (0, 0, 255)), Button(250, 150, 150, 50, "Shear", (128, 0, 128))
]
- "Translate"按钮颜色为红色
(255, 0, 0)
- "Rotate"按钮颜色为橙色
(255, 165, 0)
- "Isotropic Scale"按钮颜色为绿色
(0, 255, 0)
- "Scale"按钮颜色为青色
(0, 255, 255)
- "Mirror"按钮颜色为蓝色
(0, 0, 255)
- "Shear"按钮颜色为紫色
(128, 0, 128)
问:为什么没有黄色
答:黄色太耀眼了………
3. Pygame
初始化变量
代码语言:javascript
复制
selected_transform = None
transformed_img = original_img.copy()
mouse_dragging = False
drag_start_pos = (0, 0)
drag_offset = (0, 0)
translation_offset = (0, 0) # 平移偏移量变量
初始化Pygame
代码语言:javascript
复制
pygame.init()
设置窗口大小
window_width, window_height = 888, 888
window = pygame.display.set_mode((window_width, window_height))
pygame.display.set_caption("Image Transformations")加载并调整原始图像大小为256x256
original_img = pygame.image.load("image.jpg")
original_img = pygame.transform.scale(original_img, (256, 256))
主循环
代码语言:javascript
复制
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.MOUSEBUTTONDOWN:
mouse_pos = pygame.mouse.get_pos()
for button in buttons:
if button.is_clicked(mouse_pos):
selected_transform = button.text
transformed_img = original_img.copy()
if event.button == 1: # 鼠标左键
mouse_dragging = True
drag_start_pos = mouse_pos
elif event.type == pygame.MOUSEBUTTONUP:
if event.button == 1: # 鼠标左键
mouse_dragging = False
elif event.type == pygame.MOUSEMOTION:
if mouse_dragging:
mouse_pos = pygame.mouse.get_pos()
drag_offset = (mouse_pos[0] - drag_start_pos[0], mouse_pos[1] - drag_start_pos[1])
if selected_transform == "Translate":
translation_offset = drag_offset # 更新平移偏移量
transformed_img = translate(original_img, translation_offset[0], translation_offset[1])
elif selected_transform == "Rotate":
angle = drag_offset[0]
transformed_img = rotate(original_img, angle)
elif selected_transform == "Isotropic Scale":
scale_factor = max(0.1, 1 + drag_offset[0] / 100) # 限制缩放比例在0.1到无穷大之间
transformed_img = isotropic_scale(original_img, scale_factor)
elif selected_transform == "Scale":
scale_x = max(0.1, 1 + drag_offset[0] / 100) # 限制x方向缩放比例在0.1到无穷大之间
scale_y = max(0.1, 1 + drag_offset[1] / 100) # 限制y方向缩放比例在0.1到无穷大之间
transformed_img = scale(original_img, scale_x, scale_y)
elif selected_transform == "Mirror":
if drag_offset[0] > 0:
mirror_type = 'horizontal'
else:
mirror_type = 'vertical'
transformed_img = mirror(original_img, mirror_type)
elif selected_transform == "Shear":
shear_x = drag_offset[0] / 100
shear_y = drag_offset[1] / 100
transformed_img = shear(original_img, shear_x, shear_y)
# 清空窗口
window.fill((222, 222, 222))
# 显示原始图像
window.blit(original_img, (50, 250))
# 显示变换后的图像
if transformed_img is not None:
window.blit(transformed_img, (350, 250))
# 显示选择的变换
if selected_transform is not None:
font = pygame.font.Font(None, 36)
text = font.render(f"Selected Transform: {selected_transform}", True, (255, 255, 255))
text_rect = text.get_rect(center=(window_width // 2, 222))
window.blit(text, text_rect)
# 绘制按钮
for button in buttons:
button.draw(window)
# 更新显示
pygame.display.flip()</code></pre></div></div><h6 id="954631" name="%E9%80%80%E5%87%BAPygame">退出Pygame</h6><div class="rno-markdown-code"><div class="rno-markdown-code-toolbar"><div class="rno-markdown-code-toolbar-info"><div class="rno-markdown-code-toolbar-item is-type"><span class="is-m-hidden">代码语言:</span>javascript</div></div><div class="rno-markdown-code-toolbar-opt"><div class="rno-markdown-code-toolbar-copy"><i class="icon-copy"></i><span class="is-m-hidden">复制</span></div></div></div><div class="developer-code-block"><pre class="prism-token token line-numbers language-javascript"><code class="language-javascript" style="margin-left:0">pygame.quit()</code></pre></div></div><h5 id="954633" name="4.-%E6%95%88%E6%9E%9C%E5%B1%95%E7%A4%BA">4. 效果展示</h5><p></p><figure class=""><div class="rno-markdown-img-url" style="text-align:center"><div class="rno-markdown-img-url-inner" style="width:100%"><div style="width:100%"><img src="https://cdn.static.attains.cn/app/developer-bbs/upload/1723331262524956166.png" /></div></div></div></figure><figure class=""><div class="rno-markdown-img-url" style="text-align:center"><div class="rno-markdown-img-url-inner" style="width:100%"><div style="width:100%"><img src="https://cdn.static.attains.cn/app/developer-bbs/upload/1723331263158289413.png" /></div></div></div></figure><p></p><figure class=""><div class="rno-markdown-img-url" style="text-align:center"><div class="rno-markdown-img-url-inner" style="width:100%"><div style="width:100%"><img src="https://cdn.static.attains.cn/app/developer-bbs/upload/1723331263578373004.png" /></div></div></div></figure><p></p><figure class=""><div class="rno-markdown-img-url" style="text-align:center"><div class="rno-markdown-img-url-inner" style="width:100%"><div style="width:100%"><img src="https://cdn.static.attains.cn/app/developer-bbs/upload/1723331264163594081.png" /></div></div></div></figure><figure class=""><div class="rno-markdown-img-url" style="text-align:center"><div class="rno-markdown-img-url-inner" style="width:100%"><div style="width:100%"><img src="https://cdn.static.attains.cn/app/developer-bbs/upload/1723331264774273205.png" /></div></div></div></figure><p></p><figure class=""><div class="rno-markdown-img-url" style="text-align:center"><div class="rno-markdown-img-url-inner" style="width:100%"><div style="width:100%"><img src="https://cdn.static.attains.cn/app/developer-bbs/upload/1723331265204302137.png" /></div></div></div></figure>