Numba坐标索引(CPU + 多线程)

news2025/1/21 16:38:05

文章目录

  • 一、测试样本 —— 创建样本mask,具有 N 个唯一像素值,每个值有 M 个坐标。
  • 二、加速方法
    • (1)多线程加速 —— 每次提取一个像素值,然后遍历图像,匹配并判断其与初始化坐标的关系。
    • (2)Numba-CPU加速 —— 每次提取一个像素值,然后遍历图像,匹配并判断其与初始化坐标的关系。
    • (3)Numba-CPU加速 —— 只遍历一次图像,匹配并判断其与初始化坐标的关系。

在这里插入图片描述

使用Numba索引图像中每个像素值的最小最大坐标(CPU + 多线程)

输入图像时耗
(1)多线程(每一个像素值遍历一次图像)ZYX=(2182, 431, 548)80.41秒
(2)Numba-CPU(每一个像素值遍历一次图像)ZYX=(2182, 431, 548)81.68秒
(3)Numba-CPU(只遍历一次图像并匹配像素值)ZYX=(2182, 431, 548)1.56秒

一、测试样本 —— 创建样本mask,具有 N 个唯一像素值,每个值有 M 个坐标。

import numpy as np

def create_mask(shape, num_values):
    """创建一个 uint16 类型的 mask,并为每个像素值设置多个坐标点。
	    :param shape: mask 数组的形状 (z, y, x)
	    :param num_values: 不同的像素值数量
	    :return: mask 数组
    """
    # 初始化 mask 数组
    mask = np.zeros(shape, dtype=np.uint16)

    # 遍历每个像素值并设置多个坐标点
    for value in range(1, num_values + 1):
        # 生成随机坐标
        num_coords = int(shape[0] * shape[1] * shape[2] / num_values * 0.1)  # 每个像素值设置N个坐标点
        for _ in range(num_coords):
            z = np.random.randint(0, shape[0])
            y = np.random.randint(0, shape[1])
            x = np.random.randint(0, shape[2])
            mask[z, y, x] = value

    return mask


if __name__ == '__main__':
	shape = (1024, 1024, 1024)  # 设置 mask 的大小
	num_values = 619  # 不同的像素值数量
	mask = create_mask(shape, num_values)
	
	print(f"mask 数组的形状: {mask.shape}")
	print(f"mask 数组的唯一像素值: {np.unique(mask)}")

二、加速方法

(1)多线程加速 —— 每次提取一个像素值,然后遍历图像,匹配并判断其与初始化坐标的关系。

import numpy as np
import tifffile
import concurrent.futures
import pandas as pd
import time


def calculate_coordinates(target_value, array):
    """在满足条件的N个坐标中,提取最小x/y/z值。
	    备注1:x/y/z可以不在同一个坐标中。
	    备注2:由于需要使用np.argwhere进行坐标索引,故有时耗问题。
    """
    start_time = time.time()
    mask = (array == target_value)  # 创建布尔掩码
    coordinates = np.argwhere(mask)  # 查找True值的坐标

    min_coords = np.min(coordinates, axis=0)  # 获取所有列中每一列的最小值  # 坐标: [z, y, x]
    max_coords = np.max(coordinates, axis=0)  # 获取所有列中每一列的最大值  # 坐标: [z, y, x]
    value = [target_value, *min_coords[::-1], *max_coords[::-1]]  # 坐标: [gray, min_x, min_y, min_z, max_x, max_y, max_z]
    print(f"gray={target_value}", f"最小坐标={min_coords[::-1]}", f"最大坐标:{max_coords[::-1]}", time.time()-start_time)
    return value


def main(image_path, output_path):
    start_time = time.time()

    image = tifffile.imread(image_path)  # 读取图像
    unique_values = np.unique(image)  # 获取图像中的像素唯一值
    sorted_unique_values = np.sort(unique_values)  # 排序
    box3DMap = []

    flag = 1  # 是否加速
    if flag == 1:
        with concurrent.futures.ThreadPoolExecutor(max_workers=os.cpu_count()) as executor:
            futures = [executor.submit(calculate_coordinates, value, image) for value in sorted_unique_values[1:]]

            for future in concurrent.futures.as_completed(futures):
                result = future.result()
                box3DMap.append(result)
    else:  # 不加速版本
        for ii in range(1, len(sorted_unique_values)):
            start_time = time.time()
            
            target_value = ii  # 指定要查找的灰度值
            coordinates = np.argwhere(image == target_value)  # 提取满足条件的坐标
            min_coords = np.min(coordinates, axis=0)  # 获取所有列中每一列的最小值  # 坐标: [z, y, x]
            max_coords = np.max(coordinates, axis=0)  # 获取所有列中每一列的最大值  # 坐标: [z, y, x]
            temp = [ii, *min_coords, *max_coords]
            print(f"gray={ii}", f"最小坐标={min_coords}", f"最大坐标:{max_coords}")
            
            print(f"共用时:{time.time() - start_time}")
            box3DMap.append(temp)

    df = pd.DataFrame(box3DMap, columns=["Gray", "Min_X", "Min_Y", "Min_Z", "Max_X", "Max_Y", "Max_Z"])
    df.to_excel(output_path, index=False, engine='openpyxl')
    print(f'Data saved to={output_path}')
    print(f"计算共用时={time.time()-start_time} 秒")


if __name__ == '__main__':
    image_path = r"F:\annotation.tif"
    output_path = r"F:\output.xlsx"
    main(image_path, output_path)

(2)Numba-CPU加速 —— 每次提取一个像素值,然后遍历图像,匹配并判断其与初始化坐标的关系。

import numpy as np
import tifffile
import time
from numba import njit


@njit
def calculate_coordinates(num_values, array):
    """计算每个唯一值的最小和最大坐标。
	    num_values: 排序后的唯一像素值数组
	    array: 输入图像
	    返回值:每个像素值的最小和最大坐标
    """
    shape = array.shape
    num_values_size = num_values.size
    box3DMap = np.empty((num_values_size, 7), dtype=np.int64)  # 初始化结果数组

    for idx in range(num_values_size):
        target_value = num_values[idx]
        min_coords = np.array([shape[0], shape[1], shape[2]], dtype=np.int64)  # 初始化为图像的最大坐标值
        max_coords = np.array([-1, -1, -1], dtype=np.int64)  # 初始化为图像的最小坐标值

        for i in range(shape[0]):
            for j in range(shape[1]):
                for k in range(shape[2]):
                    if array[i, j, k] == target_value:
                        min_coords[0] = min(min_coords[0], i)
                        min_coords[1] = min(min_coords[1], j)
                        min_coords[2] = min(min_coords[2], k)
                        max_coords[0] = max(max_coords[0], i)
                        max_coords[1] = max(max_coords[1], j)
                        max_coords[2] = max(max_coords[2], k)
        coors = [target_value, min_coords[2], min_coords[1], min_coords[0], max_coords[2], max_coords[1], max_coords[0]]
        print(coors)
        box3DMap[idx] = coors
        
    return box3DMap


def main(image_path, output_path):
    image = tifffile.imread(image_path)  # 读取图像
    unique_values = np.unique(image)  # 获取图像中的像素唯一值
    sorted_unique_values = np.sort(unique_values[unique_values != 0])  # 排序并排除0
    print(f"唯一像素值数量(排除0):{len(sorted_unique_values)}")

    # Numba 加速
    start_time = time.time()
    box3DMap = calculate_coordinates(sorted_unique_values, image)
	print(f"计算共用时:{time.time() - start_time}")
    
    # 保存到EXCEL中
    import pandas as pd
    df = pd.DataFrame(box3DMap, columns=["Gray", "Min_X", "Min_Y", "Min_Z", "Max_X", "Max_Y", "Max_Z"])
    df.to_excel(output_path, index=False, engine='openpyxl')
    print(f'Data saved to={output_path}')


if __name__ == '__main__':
    image_path = r'F:\annotation.tif'
    output_path = r'F:\output.xls'
    main(image_path, output_path)

(3)Numba-CPU加速 —— 只遍历一次图像,匹配并判断其与初始化坐标的关系。

import numpy as np
import tifffile
import time
from numba import njit


@njit
def calculate_coordinates(num_values, array):
    """计算每个唯一值的最小和最大坐标。
	    num_values: 排序后的唯一像素值数组(排除0)
	    array: 输入图像
	    返回值:每个像素值的最小和最大坐标
    """
    shape = array.shape
    num_values_size = num_values.size
    box3DMap = np.empty((num_values_size, 7), dtype=np.int64)

    # 随机初始化:每个像素值的最小和最大坐标
    min_coords = np.empty((num_values_size, 3), dtype=np.int64)
    max_coords = np.empty((num_values_size, 3), dtype=np.int64)

    # 用最大坐标初始化 min_coords,用最小坐标初始化 max_coords
    for i in range(num_values_size):
        min_coords[i, 0] = shape[0]
        min_coords[i, 1] = shape[1]
        min_coords[i, 2] = shape[2]
        max_coords[i, 0] = -1
        max_coords[i, 1] = -1
        max_coords[i, 2] = -1

    # 为每个唯一值设置索引
    value_to_index = np.zeros(100000, dtype=np.int64)  # 假设最大像素值为255
    for i in range(num_values_size):
        value_to_index[num_values[i]] = i

    print("开始遍历图像,计算坐标...")
    # 遍历图像的所有坐标点
    for i in range(shape[0]):
        for j in range(shape[1]):
            for k in range(shape[2]):
                pixel_value = array[i, j, k]
                if pixel_value == 0:
                    continue
                idx = value_to_index[pixel_value]
                if idx >= 0:
                    min_coords[idx, 0] = min(min_coords[idx, 0], i)
                    min_coords[idx, 1] = min(min_coords[idx, 1], j)
                    min_coords[idx, 2] = min(min_coords[idx, 2], k)
                    max_coords[idx, 0] = max(max_coords[idx, 0], i)
                    max_coords[idx, 1] = max(max_coords[idx, 1], j)
                    max_coords[idx, 2] = max(max_coords[idx, 2], k)

    # 组合最小和最大坐标
    for idx in range(num_values_size):
        coors = [num_values[idx],
                 min_coords[idx, 2], min_coords[idx, 1], min_coords[idx, 0],
                 max_coords[idx, 2], max_coords[idx, 1], max_coords[idx, 0]]
        box3DMap[idx] = coors

    return box3DMap


def main(image_path, output_path):
    print(f"开始读取图像:{image_path}")
    image = tifffile.imread(image_path)  # 读取图像
    unique_values = np.unique(image)  # 获取图像中的像素唯一值
    sorted_unique_values = np.sort(unique_values[unique_values != 0])  # 排序并排除0
    print(f"图像读取完成。唯一像素值数量(排除0):{len(sorted_unique_values)}")

    # Numba加速
    start_time = time.time()
    print(f"开始计算坐标...")
    box3DMap = calculate_coordinates(sorted_unique_values, image)
    print(f"坐标计算完成,结果条目数:{box3DMap.shape[0]}")
    print(f"计算共用时:{time.time() - start_time}")

    # 保存到EXCEL中
    import pandas as pd
    df = pd.DataFrame(box3DMap, columns=["Gray", "Min_X", "Min_Y", "Min_Z", "Max_X", "Max_Y", "Max_Z"])
    df.to_excel(output_path, index=False, engine='openpyxl')
    print(f"数据已保存到={output_path}")


if __name__ == '__main__':
    # 示例路径,修改为实际文件路径
    image_path = r'F:\annotation.tif'
    output_path = r'F:\output.xls'
    main(image_path, output_path)

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

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

相关文章

传输层 I(传输层提供的服务、UDP协议)【★★★★】

(★★)代表非常重要的知识点,(★)代表重要的知识点。 运输层是整个网络体系结构中的关键层次之一。一定要弄清以下一些重要概念: (1) 运输层为相互通信的应用进程提供逻辑通信。 (2) 端口和套接字的意义。 …

OpenCV 之 模版匹配多个对象、图片旋转 综合应用

引言 在图像处理和计算机视觉中,模板匹配是一种常用的技术,用于在一幅较大的图像中查找与给定模板图像相似的部分。然而,在实际应用中,目标物体可能会出现在不同的角度,这就需要我们在匹配之前对模板进行旋转处理。本…

[AHK]动态创建带ListBox的窗口,答选择题的界面

根据传入的窗口标题、提示信息(题干)、列表(选项)生成一个带ListBox的窗口(向导界面)。 AHK v1代码 if(A_ScriptFullPath=A_LineFile)MsgBox % ListBox("窗口标题", "这是一个生成listbox的Demo", "a|b|c|d|",3) return ;-------------…

清华智普ChatGlm批量API多线程写文章软件【glm-4-flash的key免费无限写 】

清华智普GLM-4-Flash经全面测评,在语义理解、数学逻辑、逻辑推理、代码执行以及广泛知识覆盖等方面,其表现显著超越了Llama-3-8B模型。 清华智普GLM-4-Flash模型还具备多种核心功能,包括但不限于流畅的多轮对话能力、内置的网页浏览功能、直…

线上购物商城小程序,uniapp,PHP语言开发在线购物商城小程序

前言: 商城小程序能够帮助商家降低成本、提高效率,为用户提供更加便捷和个性化的购物体验,是移动互联网时代的一种高效商业工具。 一、商城小程序功能有哪些? 基础功能需求 用户注册与登录 - 用户可以通过手机号、微信等方式进…

【第25章】Spring Cloud之Sentinel控制台详解

文章目录 前言一、实时监控二、簇点链路三、流控规则四、熔断规则五、热点规则六、系统规则七、授权规则八、集群流控九、机器列表总结 前言 前面我们详细介绍了Sentinel控制台的安装过程,这里我们来了解各个菜单的功能作用。 一、实时监控 同一个服务下的所有机器…

【网络安全】分析JS文件实现账户接管

未经许可,不得转载。 文章目录 正文正文 网站使用的是简单的OTP(一次性密码)验证机制,通过用户注册时提供的电子邮件发送邮箱验证码。在功能有限的情况下,我选择去分析网站加载的JavaScript文件。 我发现了一个名为 saveJobseekerPasswordInCache 的函数: 这个函数虽然…

等待实质审查的商标可以用吗!

申请注册商标受理书下来后,会有一个等待实质审查,这个审查出来就会出现要么通过初审,要么驳回,要么部分驳回,普推知产商标老杨发现时间大约是三个月左右,所以基本从申请3个月左右就知道结果了。 申请注册商…

智算时空 重塑视界│智汇云舟2024视频孪生产品发布会圆满举行,多个“全球首款”重磅亮相

​秋风送爽,丹桂飘香。9月6日,由北京智汇云舟科技有限公司主办(简称:智汇云舟),北京北科软科技有限公司(简称:北科软)、北京恒升联合科技有限公司(简称&#…

【北京迅为】《STM32MP157开发板使用手册》- 第十一章 编译U-Boot

iTOP-STM32MP157开发板采用ST推出的双核cortex-A7单核cortex-M4异构处理器,既可用Linux、又可以用于STM32单片机开发。开发板采用核心板底板结构,主频650M、1G内存、8G存储,核心板采用工业级板对板连接器,高可靠,牢固耐…

TPM管理培训为何难以落地?原因解析与解决之道

近年来,TPM管理被视为提升设备效率、减少故障率、降低生产成本的关键。然而,尽管TPM的理念被广泛接受,其在实践中的落地却常常面临各种挑战。本文,深圳天行健企业管理咨询公司将深入解析TPM管理培训难以落地的根本原因&#xff0c…

微信小程序登录与获取手机号 (Python)

文章目录 相关术语登录逻辑登录设计登录代码 相关术语 调用接口[wx.login()]获取登录凭证(code)。通过凭证进而换取用户登录态信息,包括用户在当前小程序的唯一标识(openid)、微信开放平台账号下的唯一标识&#xff0…

华为防火墙 nat64

如果设备接收到的IPv6报文的前缀是设备为NAT64定义的前缀,说明报文的目的地址是IPv4网络,报文将经过NAT64处理后被转发至IPv4网络。 如果设备接收到的IPv6报文的前缀不是设备为NAT64定义的前缀,说明报文的目的地址是IPv6网络,报文…

强烈推荐!分享5款ai论文生成软件

在当今学术研究和写作领域,AI论文生成工具的出现极大地提高了写作效率和质量。这些工具不仅能够帮助研究人员快速生成论文草稿,还能进行内容优化、查重和排版等操作。以下是五款值得推荐的AI论文生成软件,特别是千笔-AIPassPaper。 ### 千笔-…

Gin-封装自动路由

O.0 思路一、API二、控制层三、自动路由核心四、分组路由外加中间件使用 思路 由于Java转Go直接使用的goframe框架,然学习Gin时觉得一个接口一个路由太麻烦,于是有了...1、在请求结构体中采用标签的形式,直接给出路由和请求方式 2、在控制层…

yum源配置与静态配置地址

网络yum源 备份配置文件 下载新的CentOS-Base.repo文件到/etc/yum.repos.d/目录下 执行yum clean all清除原有 yum 缓存 执行yum makecache(刷新缓存) 本地yum 将/etc/yum/repos.d/下的文件a都移走,此处移到了该目录下的bak中 找到光盘路…

【重学 MySQL】二十二、limit 实现分页

【重学 MySQL】二十二、limit 实现分页 基本语法实现分页第一页第二页通用公式注意事项在 MySQL 中,LIMIT 子句非常强大,它允许你限制查询结果的数量,同时也经常被用来实现分页功能。分页是 Web 开发中常见的需求,它允许用户浏览大量数据时,一次只查看一小部分数据。 基本…

【重学 MySQL】二十一、order by 实现数据排序

【重学 MySQL】二十一、order by 实现数据排序 基本语法示例按薪水升序排序按薪水降序排序根据多个列排序 注意事项 在MySQL中,ORDER BY子句用于对结果集中的数据进行排序。你可以根据一个或多个列对结果进行升序(ASC)或降序(DESC…

JavaEE:文件操作

文章目录 文件操作和IO文件系统操作File介绍属性构造方法方法 代码演示前四个listmkdirrenameTo 文件操作和IO 文件系统操作 创建文件,删除文件,创建目录,重命名… Java中有一个类,可以帮我们完成上述操作. 这个类叫做File类. File介绍 属性 这个表格描述了文件路径的分隔符…

【IIS实战】ERR_SSL_KEY_USAGE_INCOMPATIBLE

当我们第一次配置IIS服务器做测试环境网站时,如果没有插手做自签名证书,而是用IIS自带的自签名证书,那么现代浏览器访问HTTPS测试站点大概率会有下图所示的报错: (IE:我能打开( •̀ ω •́ )y&#xff0…