Python 语言学习——应用1.2 数字图像处理(第二节,变换)

news2024/10/6 8:10:24

目录

1.基础知识

        1.图像几何变换概念

        2.图像几何变换方式 

        3.插值运算

        4.几何变换步骤 

2.各类变换 

        1.位置变换

         2.形状变换

        3.代数运算 

3.实战演练 


1.基础知识

        1.图像几何变换概念

  • 在图像处理过程中,为了观测需要,常常需要对 图像进行几何变换,如几何失真图像的校正、图 像配准、电影、电视和媒体广告等的影像特技处 理等,是图像变形以及校正变形的基础。
  • 图像几何变换将图像中任一像素映射到一个新位置,是一种空间变换,关键在于确定图像中点与点之间的映射关系

        2.图像几何变换方式 

  • 首先有齐次坐标:用n+1维向量表示n维向量的方法称为齐次坐标 表示法。原图像用点集[x,y,1]^{T}(转置的意思)表示。好处:齐次坐标中,对原图像进行平移、缩放、旋转等 几何变换,可用一个变换矩阵表示。
  • 然后是变换矩阵:a,b,c,d用于图形的比例、对称、 错切、旋转等基本变换;k,m用于 图形的平移变换;p,q用于投影变 换;s用于全比例变换。
  • 实现2D图像几何变换的基本变换的一般过程是:变换矩阵T×变换前的点集矩阵=变换后的点集矩阵。 

        3.插值运算

  • 为什么会有这玩意:当你调整图像的大小,特别是缩小图像时,由于目标大小的像素数量少于原图像的像素数量,就需要通过插值算法来估算新像素的值。在进行旋转、平移、拉伸等几何变换时,图像的像素位置可能会发生变化(比如原x,y的像素点变成0.8x,0.9y算出来是个小数,则相应位置像素值不知道是多少)应用一些滤波器或处理器时,如模糊、锐化等操作,会导致像素值的变化,需要通过插值来重新计算像素值。

  • 概念:指利用已知邻近像素点的灰度值来产生未知像素点的灰度值(各通道)

  • 常用插值运算方法:

  1. 最近邻插值:非整数像素灰度值就等于距离最近 的坐标都为整数的像素的灰度值。 
  2. 双线性插值:利用非整数像素点周围的四个像素 点的相关性,通过双线性算法计算得出。图1算法或图2算法(利用周边四个点)。

  3. 双三次插值:利用非整数像素点周围的16个像素 点进行计算。

        4.几何变换步骤 

  1. 根据不同的几何变换公式计算新图像的尺寸
  2. 根据几何变换的逆变换,对新图像中的每一点确 定其在原图像中的对应点
  3. 按对应关系给新图像中各个像素赋值
  • 若新图像中像素点在原图像中的对应点坐标存 在,直接赋值
  • 若新图像中像素点在原图像中的对应点坐标超 出图像宽高范围,直接赋背景色
  • 若新图像中像素点在原图像中的对应点坐标在 图像宽高范围内,采用插值的方法计算 

2.各类变换 

        1.位置变换

  • 图像的位置变换是指图像的大小和形状不发生变化,只是图像像素点的位置发生变化,含平 移、镜像、旋转
  • 平移:若不想丢失信息,可能需要扩大画布

  • 镜像:M为总行数,N为总列数 

  • 旋转: θ为正,代表逆时针旋转,若要确定变换后的尺寸大小:计算原图像四个角在 旋转后的坐标;确定新图像的分辨率,M'=max x'-min x'+1;N'=max y'-min y'+1(结果向上取整).对于不在原点旋转的,先要将坐标系平移到原点,再按绕原点旋转进行变换,然后平移回原坐标原点。得到新图像的M',N'后,需依次确定[0,M'-1]+minx',[0,N'-1]+miny'各个像素点的值。也就是再逆变换回去,根据步骤第三点的三条进行赋值。

         2.形状变换

  • 缩放

  • 错切:平面景物在投影平面上的非垂直投 影,使图像中的图形产生扭变

     

        3.代数运算 

  • 加法运算如下图,应用主要有:多幅图像相加求平均去除叠加性噪声,将一幅图像的内容经配准后叠加到另一幅图像 上去,以改善图像的视觉效果,在多光谱图像中,通过加法运算加宽波段,如 绿色波段和红色波段图像相加可以得到近似全色图像,用于图像合成和图像拼接。

  • 减法运算如下图,应用主要有:显示两幅图像的差异,检测同一场景两幅图像 之间的变化;去除不需要的叠加性图案,加性图案可能是缓 慢变化的背景阴影或周期性的噪声,或在图像 上每一个像素处均已知的附加污染等;图像分割:如分割运动的车辆,减法去掉静止 部分,剩余的是运动元素和噪声;生成合成图像。 

  • 乘法运算主要是部分图框出来,也就是图像的局部显示和提取:用二值模板图像与 原图像做乘法来实现 。

  • 逻辑运算:原理如图。


3.实战演练 

P1. 试编写程序,对图像逆时针旋转60°,采用双线性插值的方法

from PIL import Image  # 导入PIL库,用于图像处理
import math #用于旋转时计算三角函数

def bilinear_interpolation(image, x, y):
    # 将坐标转换为整数
    x1, y1 = int(x), int(y)
    x2, y2 = x1 + 1, y1 + 1

    # 处理边界情况
    if x2 >= image.width:
        x2 = x1
    if y2 >= image.height:
        y2 = y1

    # 获取四个相邻像素的RGB值
    q11 = image.getpixel((x1, y1))
    q21 = image.getpixel((x2, y1))
    q12 = image.getpixel((x1, y2))
    q22 = image.getpixel((x2, y2))

    r = []#空列表的创建

    # 处理 RGB 值的每个通道
    for i in range(3):  # 0: 红色通道, 1: 绿色通道, 2: 蓝色通道
        r.append(q11[i] * (x2 - x) * (y2 - y) + q21[i] * (x - x1) * (y2 - y) + q12[i] * (x2 - x) * (y - y1) + q22[i] * (x - x1) * (y - y1))

    return tuple(map(int, r))  # 返回处理后的 RGB 值

def rotate_image(image, angle):
    # 旋转图像函数
    angle = angle % 360
    if angle == 0:
        return image

    rotated_image = Image.new("RGB", image.size)  # 创建旋转后的图像对象

    for x in range(rotated_image.width):
        for y in range(rotated_image.height):
            # 计算旋转后的坐标,即逆变换找到原坐标位置
            x_original = ((x - rotated_image.width / 2) * math.cos(math.radians(angle)) -
                          (y - rotated_image.height / 2) * math.sin(math.radians(angle)) + image.width / 2)
            y_original = ((x - rotated_image.width / 2) * math.sin(math.radians(angle)) +
                          (y - rotated_image.height / 2) * math.cos(math.radians(angle)) + image.height / 2)

            if 0 <= x_original < image.width - 1 and 0 <= y_original < image.height - 1:
                # 应用双线性插值
                rotated_image.putpixel((x, y), bilinear_interpolation(image, x_original, y_original))#注意写法,这个函数第二个参数是元组表示的一组rgb的值

    return rotated_image

# 打开图像文件
image = Image.open("rainbow.jpg")

# 逆时针旋转60°
rotated_image = rotate_image(image, 60)

# 保存旋转后的图像
rotated_image.save("rotated_image.jpg")  # 保存旋转后的图像

说明:map(int, r): 这部分使用了Python内置的 map 函数,它接受一个函数和一个可迭代对象作为参数。在这里,int 函数被应用于可迭代对象 r 中的每个元素,将每个元素转换为整数。tuple(...): tuple() 函数用于将一个可迭代对象转换为元组(tuple)。在这里,map(int, r) 返回一个迭代器,然后 tuple() 将这个迭代器转换为一个由整数组成的元组。

P2. 打开一幅图像,依次完成下列要求:顺时针旋转20°,做水平镜像,做错切变换,缩小图像。若需要插值运算,采用双线性插值方法;要求输出显示原图、中间结果和最后结果。(作为模板题)

import math #用于旋转时计算三角函数
from PIL import Image


def resize_image(image, width_scale, height_scale):
    # 获取图像的宽度和高度
    width, height = image.size

    # 计算放大或缩小后的宽度和高度
    new_width = int(width * width_scale)
    new_height = int(height * height_scale)

    # 创建一个新图像对象,用于存储放大或缩小后的图像
    resized_image = image.resize((new_width, new_height))

    return resized_image


def shear_image(image, shear_factor):
    # 获取图像的宽度和高度
    width, height = image.size

    # 计算错切后的宽度,只需计算宽度即可
    new_width = width + int(abs(shear_factor) * height)

    # 创建一个新图像对象,用于存储错切后的图像
    sheared_image = Image.new("RGB", (new_width, height))

    # 错切处理
    for x in range(new_width):
        for y in range(height):
            # 计算错切后的坐标,逆旋转
            new_x = x - int(shear_factor * y)

            if 0 <= new_x < width:
                # 获取原始图像中的像素值
                pixel = image.getpixel((new_x, y))
                # 将像素值复制到错切图像中
                sheared_image.putpixel((x, y), pixel)

    return sheared_image


def mirror_image(image):
    # 获取图像的宽度和高度
    width, height = image.size

    # 创建一个新图像对象,用于存储镜像后的图像
    mirrored_image = Image.new("RGB", (width, height))

    # 镜像处理
    for x in range(width):
        for y in range(height):
            # 获取原始图像中的像素值
            pixel = image.getpixel((x, y))
            # 将像素值复制到镜像图像中,但是在水平方向上镜像
            mirrored_image.putpixel((width - x - 1, y), pixel)

    return mirrored_image


def bilinear_interpolation(image, x, y):
    # 将坐标转换为整数
    x1, y1 = int(x), int(y)
    x2, y2 = x1 + 1, y1 + 1

    # 处理边界情况
    if x2 >= image.width:
        x2 = x1
    if y2 >= image.height:
        y2 = y1

    # 获取四个相邻像素的RGB值
    q11 = image.getpixel((x1, y1))
    q21 = image.getpixel((x2, y1))
    q12 = image.getpixel((x1, y2))
    q22 = image.getpixel((x2, y2))

    r = []#空列表的创建

    # 处理 RGB 值的每个通道
    for i in range(3):  # 0: 红色通道, 1: 绿色通道, 2: 蓝色通道
        r.append(q11[i] * (x2 - x) * (y2 - y) + q21[i] * (x - x1) * (y2 - y) + q12[i] * (x2 - x) * (y - y1) + q22[i] * (x - x1) * (y - y1))

    return tuple(map(int, r))  # 返回处理后的 RGB 值

def rotate_image(image, angle):
    # 旋转图像函数
    angle = angle % 360
    if angle == 0:
        return image

    rotated_image = Image.new("RGB", image.size)  # 创建旋转后的图像对象

    for x in range(rotated_image.width):
        for y in range(rotated_image.height):
            # 计算旋转后的坐标,即逆变换找到原坐标位置
            x_original = ((x - rotated_image.width / 2) * math.cos(math.radians(angle)) -
                          (y - rotated_image.height / 2) * math.sin(math.radians(angle)) + image.width / 2)
            y_original = ((x - rotated_image.width / 2) * math.sin(math.radians(angle)) +
                          (y - rotated_image.height / 2) * math.cos(math.radians(angle)) + image.height / 2)

            if 0 <= x_original < image.width - 1 and 0 <= y_original < image.height - 1:
                # 应用双线性插值
                rotated_image.putpixel((x, y), bilinear_interpolation(image, x_original, y_original))#注意写法,这个函数第二个参数是元组表示的一组rgb的值

    return rotated_image

# 打开图像文件
image = Image.open("rainbow.jpg")
image.show()

# 逆时针旋转-20°
rotated_image = rotate_image(image, -20)
rotated_image.show()

mirror=mirror_image(rotated_image)
mirror.show()

share=shear_image(mirror,2)
share.show()

resize=resize_image(share,0.2,0.2)
resize.show()

P3. 打开两幅图像,利用几何变换、图像代数运算,生成一幅精美的合成图像

from PIL import Image

def resize_image(image, width_scale, height_scale):
    # 获取图像的宽度和高度
    width, height = image.size

    # 计算放大或缩小后的宽度和高度
    new_width = int(width * width_scale)
    new_height = int(height * height_scale)

    # 创建一个新图像对象,用于存储放大或缩小后的图像
    resized_image = image.resize((new_width, new_height))

    return resized_image

def add_images(sun_image, sky_image, output_path):

    # 获取太阳图像和天空图像的宽度和高度
    sun_width, sun_height = sun_image.size
    sky_width, sky_height = sky_image.size

    # 确保太阳图像完全在天空图像内
    if sun_width <= sky_width and sun_height <= sky_height:
        # 创建一个新的图像对象,用于存储混合后的图像
        result_image = Image.new("RGB", (sky_width, sky_height))

        # 将天空图像复制到结果图像中
        result_image.paste(sky_image, (0, 0))

        # 将太阳图像叠加到左上角
        result_image.paste(sun_image, (0, 0), sun_image)

        # 保存混合后的图像
        result_image.show()
    else:
        print("Sun image is too large to fit entirely on the sky image.")

# 图像文件路径

sun_path = "sun.png"
sun_image = Image.open(sun_path)
sun_image.show()
sun=resize_image(sun_image,0.2,0.2)
sky_path = "sky.jpg"
output_path = "result_image.jpg"
sky_image = Image.open(sky_path)
sky_image.show()
# 执行图像混合操作
add_images(sun, sky_image, output_path)

 说明,paste函数的使用:语法为image.paste(image_to_paste, box, mask)image_to_paste: 要粘贴的图像对象。box: 表示将图像粘贴到另一个图像的位置,通常是一个元组 (x, y),表示左上角的坐标。mask: 用于指定一个掩码图像,一般而言为数值,从0不透明到255透明,也可以是一个二值图像,如果提供了掩码图像,它将根据掩码的像素值来控制被粘贴图像的透明度,使得被粘贴图像可以部分透明地展现在目标图像上。

题外话:不要吐槽图像的精美程度。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2191474.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

EXCEL_光标百分比

Public Sub InitCells()Dim iSheet As LongFor iSheet Sheets.Count To 1 Step -1Sheets(iSheet).ActivateActiveWindow.Zoom 85ActiveWindow.ScrollRow 1ActiveWindow.ScrollColumn 1Sheets(iSheet).Range("A1").ActivateNext iSheetEnd Sub对日项目中的文档满天…

Python | Leetcode Python题解之第459题重复的子字符串

题目&#xff1a; 题解&#xff1a; class Solution:def repeatedSubstringPattern(self, s: str) -> bool:def kmp(query: str, pattern: str) -> bool:n, m len(query), len(pattern)fail [-1] * mfor i in range(1, m):j fail[i - 1]while j ! -1 and pattern[j …

深度学习中的结构化概率模型 - 结构化概率模型的深度学习方法篇

序言 在深度学习的广阔领域中&#xff0c;结构化概率模型&#xff08; Structured Probabilistic Model \text{Structured Probabilistic Model} Structured Probabilistic Model&#xff09;扮演着至关重要的角色。这类模型利用图论中的图结构来表示概率分布中随机变量之间的…

普渡PUDU MT1:AI赋能,破解大面积场景清洁新挑战

普渡AI智能扫地机器人PUDU MT1:破解大面积场景清洁难题的新利器 在仓储物流、工业车间、交通枢纽、大型商场等大面积场景中,清洁难题一直是管理者们头疼的问题。这些区域面积广阔,清洁任务繁重,传统清洁方式难以胜任。然而,普渡机器人最新推出的AI智能扫地机器人PUDU MT1…

【目标检测】工程机械车辆数据集2690张4类VOC+YOLO格式

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;2694 标注数量(xml文件个数)&#xff1a;2694 标注数量(txt文件个数)&#xff1a;2694 标注…

付费计量系统数据元素(Data elements)

See also Clause 4 for a discussion on general concepts.Data elements are the instruments used to keep record of information on the status of the system and changes over time. 参见条目 4 关于一般概念的讨论。数据元素是仪器使用保留关于系统状态和随时间…

【Kubernetes】常见面试题汇总(四十五)

目录 102.使用 Kubernetes 时可以采取的最佳安全措施是什么&#xff1f; 103.什么是联合集群&#xff1f; 特别说明&#xff1a; 题目 1-68 属于【Kubernetes】的常规概念题&#xff0c;即 “ 汇总&#xff08;一&#xff09;~&#xff08;二十二&#xff09;” 。 题目…

1688商品详情关键词数据-API

要利用 Python 爬虫采集 1688 商品详情数据&#xff0c;需要先了解 1688 网站的页面结构和数据请求方式。一般使用 requests 库请求网站的数据&#xff0c;使用 BeautifulSoup 库解析网页中的数据。 以下是一个简单的 Python 爬虫采集 1688 商品详情数据的示例代码&#xff1a…

二、变量与基本类型

变量与基本类型 变量定义声明和使用 基本类型数字类型介绍运算算术运算符位运算符赋值运算符运算符优先级 布尔类型字符类型字符串类型 变量 定义 变量&#xff0c;指值可以变的量。变量以非数字的符号来表达&#xff0c;一般用拉丁字母。变量的用处在于能一般化描述指令的方式…

Java_Se 泛型

泛型基本概念&#xff1a; 泛型是JDK5.0以后增加的新特性。泛型的本质就是“数据类型的参数化”&#xff0c;处理的数据类型不是固定的&#xff0c;而是可以作为参数传入。我们可以把“泛型”理解为数据类型的一个占位符(类似&#xff1a;形式参数)&#xff0c;即告诉编译器&am…

如何搭建自己的域名邮箱服务器?Poste.io邮箱服务器搭建教程,Linux+Docker搭建邮件服务器的教程

Linux系统Docker搭建Poste.io电子邮件服务器&#xff0c;搭建属于自己的域名邮箱服务器&#xff0c;可以无限收发电子邮件&#xff08;Email&#xff09;&#xff01; 视频教程&#xff1a;https://www.bilibili.com/video/BV11p1mYaEpM/ 前言 什么是域名邮箱&#xff1f; …

【深度学习】— softmax回归、网络架构、softmax 运算、小批量样本的向量化、交叉熵

【深度学习】— softmax回归、网络架构、softmax 运算、小批量样本的向量化、交叉熵 3.4 Softmax 回归3.4.1 分类问题3.4.2 网络架构 3.4.3 全连接层的参数开销3.4.4 softmax 运算3.4.5 小批量样本的向量化3.4.6 损失函数对数似然softmax 的导数 3.4.7 信息论基础熵信息量重新审…

MySQL 和 Elasticsearch 的应用场景

MySQL 和 Elasticsearch 的应用场景 一、MySQL 关系型数据库管理系统&#xff0c;用于存储和管理结构化数据。 存储数据场景&#xff1a; 企业的财务系统、人力资源系统等&#xff0c;需要存储和管理具有明确关系的数据&#xff0c;如员工信息表、工资表等&#xff0c;这些表…

一阶差分模板的频率响应

一阶差分模板不同于二阶差分模板&#xff0c;它是一个奇对称的模板&#xff0c;傅里叶变换是纯虚数&#xff0c;无法用图形直接显示傅里叶变换&#xff0c;只能显示幅值谱。 冈萨雷斯的这个图我一直很好奇是怎么显示的&#xff0c;也没有坐标轴标出变量表示。 如今终于想明白…

基于Es的分词查询通过高亮效果实现前端高亮显示!!!!

引言&#xff1a; 经常我们在浏览器界面搜索关键词的时候&#xff0c;浏览器返回给我们的页面都是高亮显示关键词的效果&#xff0c; 如下&#xff1a; 我们要简单实现这个效果很简单&#xff0c;可以通过多种办法&#xff0c;这里通过Es 的高亮效果实现给我们关键字字段加自…

FRP搭建内网穿透:云服务端 + 家用Linux/Windows主机【2024】

介绍 FRP是一个可以自己搭建内网穿透服务的开源项目&#xff0c;开源地址直达&#xff1a; FRP-GitHub 实际上frp由两个程序组成 ①frps:在服务端运行的程序 ②frpc:在客户端运行的程序 运作方式示意图如下 服务端 因为服务上使用了1Panel面板&#xff0c;直接在应用商店安…

每日一题|134. 加油站|循环数组单次遍历

本题题目比较绕&#xff0c;理解了之后发现就是给一个一维数组表示余量&#xff0c;找出能够首尾相连且后构成每个位置处的累积和都是正数的索引。 首先&#xff0c;根据cost和gas相减&#xff0c;确定每个位置出发去下一个位置所剩余的gas。 这里可以直接统计全部的余量和&…

【德国EnMAP高光谱卫星】

德国EnMAP&#xff08;Environmental Mapping and Analysis Program&#xff09;高光谱卫星是德国在地球观测领域的一项重要成就&#xff0c;以下是对该卫星的详细介绍&#xff1a; 一、基本信息 发射时间&#xff1a;2022年4月1日研发机构&#xff1a;由德国航空航天中心&a…

【多模态项目实战】-模态表示:基于对应表示的跨模态检索(图文互搜)

【多模态项目实战】-模态表示&#xff1a;基于对应表示的跨模态检索 文章目录 【多模态项目实战】-模态表示&#xff1a;基于对应表示的跨模态检索1.任务介绍2.跨模态检索技术简介3.模型训练流程3.1读取数据1)下载数据集&#x1f680;2)整理数据集3)定义数据集类4)批量读取数据…

zutilo不支持zotero7,zotero7实现复制条目链接方法。

更新zotero7后原来的zutilo插件失效了&#xff0c;为其中复制条目链接这个功能修改了一个脚本&#xff0c;仅粘贴链接&#xff0c;无标题。 {"translatorID": "2de2b1a5-5725-494c-9224-5781cdf9b7ef","label": "Markdown ZotSelect"…