基于OpenCV批量分片高像素影像

news2024/11/25 15:39:10

基于OpenCV批量分片高像素影像

为了更加精确的诊断和治疗,医疗影像往往是大像素(1920x1080)或超大像素图像(4k图像4096x2160)。这类图像的尺寸与深度学习实验数据常见尺寸(227x227,或32x32)有巨大的差别,不仅对网络的深度要求更高,所需的算力、内存、运算时间等成本也会更高。因此,在处理医疗图像或遥感图像这样的高像素图像时,往往都需要将其批量处理成小像素方片,并针对每一个方片进行识别或预测。

因此无需我们再人工进行处理,然而掌握高像素图像的分片技巧十分必要,我们将以数张大像素的图像为例展示批量分片高像素图像的代码与相关知识。

**星辰与病灶细胞一样,可能分布在图像的各个位置,也可能集中在图像上的某个区域,因此适合用来作为替代图。我们先以一张图像为例进行分片:

#!pip install opencv-python

import cv2
import os
import matplotlib.pyplot as plt
cv2.__version__
'4.5.5'
  • 导入图像,进行查看
#设置图像所在的文件夹目录,你可以自由设置你自己的目录
PATH = r"E:\02_2022DL\HealthCareProject\image"

#使用opencv读入图像
img = cv2.imread(os.path.join(PATH,"imge01.jpg"))

#由于opencv在读取图像时,没有成功读取也不会报错
#因此在读取图像后需要检查图像是否为None
if img is None:
    print("failed")
else:
    print("succeed")
succeed
img.shape #高,宽
(1600, 2560, 3)
#将图像进行可视化,由于OpenCV的默认通道顺序是BGR,因此在可视化时需要转换为RGB
#对图像进行浅复制,避免在操作中误覆盖原图
imgcopy = cv2.cvtColor(img, cv2.COLOR_BGR2RGB).copy()
plt.figure(dpi=200)
plt.imshow(imgcopy)
plt.axis("off");

在这里插入图片描述

imgcopy.shape #注意判断导入后的高宽顺序。我们平时说1920x1080是宽x高,现在导入后明显是高x宽
(1600, 2560, 3)
#像素值
imgcopy.shape[0] * imgcopy.shape[1]
4096000

我们的最终目标:将图像分割为数千个小型方片:

  • 将一张图像分割为两半

分割的本质就是先裁剪图像、再对裁剪后的图像进行保存。例如,假设我们现在要将以下图像按中线分割为两部分,最简单的手段就是先在原始图像上裁剪出左半边的图像,保存为一个单独的文件,再在原始图像上裁剪出右半边的图像,保存为一个单独的文件。在这个过程当中,我们没有对原始图像做任何的更改,却可以得到两张新的图像。

由于图像数据都是三维矩阵,因此只要通过索引就可以轻松将图像进行裁剪。对一张图像来说,索引的顺序是从上到下、从左到右,因此,如果要取出整个图像的左侧,则需要对图像进行如下索引:

imgcopy.shape #2560
(1600, 2560, 3)
imgcopy[:,0:1280].shape #取出一半的宽,全部的高,不对通道做任何处理
(1600, 1280, 3)
#尝试将索引出的图像可视化
plt.figure(dpi=140)
plt.imshow(imgcopy[:,0:1280])
plt.axis("off");

在这里插入图片描述

#也可以尝试索引出图像的右侧
plt.figure(dpi=140)
plt.imshow(imgcopy[:,1280:]) #依然是全部的高,不过宽是从1280中线开始向后取
plt.axis("off");

在这里插入图片描述

不难发现,对图像进行截取时,只需要按照图像[高的起点:高的终点,宽的起点:宽的终点]进行索引即可,只要我们知道图像当中的相对位置(四个坐标),就可以按照任意的起点和终点截取任何尺寸、任何形状的图片。接下来,当我们索引出想要的图像后,只需要将这张图像保存成新的图片文件即可。在这里我们要使用的是opencv中的经典方法imwrite:

cv2.imwrite(保存图像的目录+文件名,需要保存的图片对象)

例如,上述星辰图的左侧保存到之前设置好的PATH目录,则有:

PATH
'E:\\02_2022DL\\HealthCareProject\\image'
os.path.join(PATH,"star1.jpg") #确定文件名
'E:\\02_2022DL\\HealthCareProject\\image\\star1.jpg'
cv2.imwrite(os.path.join(PATH,"star2.jpg"),imgcopy[:,0:1280])
True

返回True,则说明保存成功,如果报错或返回False则保存失败。此时我们可以在PATH设定的目录下查看保存出的文件。

  • 将一张图像分割为小尺寸方片

将图像分割为小尺寸方片的原理与将图像分割成两半的原理完全一致:首先,从图像中裁剪出我们需要的小尺寸方片,然后将该方片对象保存为一张新的图像。然而,一张大尺寸图像可以被分割为成千上万的小尺寸方片,因此我们需要将每个小方片一一索引出来,再一一保存:

我们必然不可能手动一一裁剪方片,因此我们需要一个循环来帮助我们进行分割。观察上图,每个方片的尺寸为50x50,左上角第一个被切分出的方片索引为图像[:50,:50],紧接着左数第二个方片的索引为图像[:50,50:100],第三个方片的索引为图像[:50,100:150]以此类推,第一行的所有方片都可以被表示为图像[:50,x:x+50]。可见,我们只需要在宽度上进行循环,每次让宽的起点增加50,宽的终点增加50,就可以实现第一行的截取和分割。同理,第一列的所有方片都可以被表示为图像[y:y+50,:50],所以只要在高度上进行循环,每次让高的起点增加50,高的终点增加50,就可以实现第一列的截取和分割。那只要同时在高和宽上进行循环,就可以实现对上图中所有方片的截取和分割。

以宽为例,我们可以有:

imgcopy.shape[1]
2560
[*range(0,imgcopy.shape[1],50)] #从0开始,到宽的最大值结束,每50个数取出一个数
[0,
 50,
 100,
 150,
 200,
 250,
 300,
 350,
 400,
 450,
 500,
 550,
 600,
 650,
 700,
 750,
 800,
 850,
 900,
 950,
 1000,
 1050,
 1100,
 1150,
 1200,
 1250,
 1300,
 1350,
 1400,
 1450,
 1500,
 1550,
 1600,
 1650,
 1700,
 1750,
 1800,
 1850,
 1900,
 1950,
 2000,
 2050,
 2100,
 2150,
 2200,
 2250,
 2300,
 2350,
 2400,
 2450,
 2500,
 2550]
for x in range(0,imgcopy.shape[1],50): #把range中的值作为宽的起点,再给该起点加上50像素,作为终点
    print("[{}:{}]".format(x,x+50))
[0:50]
[50:100]
[100:150]
[150:200]
[200:250]
[250:300]
[300:350]
[350:400]
[400:450]
[450:500]
[500:550]
[550:600]
[600:650]
[650:700]
[700:750]
[750:800]
[800:850]
[850:900]
[900:950]
[950:1000]
[1000:1050]
[1050:1100]
[1100:1150]
[1150:1200]
[1200:1250]
[1250:1300]
[1300:1350]
[1350:1400]
[1400:1450]
[1450:1500]
[1500:1550]
[1550:1600]
[1600:1650]
[1650:1700]
[1700:1750]
[1750:1800]
[1800:1850]
[1850:1900]
[1900:1950]
[1950:2000]
[2000:2050]
[2050:2100]
[2100:2150]
[2150:2200]
[2200:2250]
[2250:2300]
[2300:2350]
[2350:2400]
[2400:2450]
[2450:2500]
[2500:2550]
[2550:2600]
imgcopy[:50,2550:2600].shape
(50, 10, 3)

现在,同时对宽和高执行循环:

#每次分割前,获取完整的原始图像
imgcopy = cv2.cvtColor(img, cv2.COLOR_BGR2RGB).copy()

#获取图像的高度和宽度
imgheight = imgcopy.shape[0]
imgwidth = imgcopy.shape[1]

#确定每个方片的尺寸
patch_height = 50
patch_weight = 50

#令x为宽上的起点,y为高上的起点,开始循环
for y in range(0, imgheight, patch_height):
    for x in range(0, imgwidth, patch_weight):
        
        #首先检查:设置的方片尺寸是否大于原始图像尺寸?如果是,则直接打断循环,不进行分割
        if patch_height > imgheight or patch_weight > imgwidth:
            print("方片尺寸过大,超过原始尺寸")
            break
        
        #方片尺寸没有大于原始图像尺寸,则计算宽和高上的终点
        y_ = y + patch_height
        x_ = x + patch_weight
        
        #接着检查,宽和高上索引的终点是否大于了原始图像尺寸?
        #当起点位于图像上,但终点落在图像外的时候,我们可以规定几种选择
        #舍弃所有不足规定方片尺寸的图像,或者保存这些残缺的图像
        #对于病理识别来说,损失边缘的一点点信息并无大碍
        #因此我们规定,只有当高和宽的终点都落在图像上时,才进行切片和保存
        if imgheight >= y_ and imgwidth >= x_:
            #索引出切片
            patch = imgcopy[y:y_, x:x_]
            
            #保存索引出的图像,如果想,可以在图像文件名中保存四角坐标,也可以选择只保存左上角坐标
            cv2.imwrite(os.path.join(PATH,"patches"
                                     ,"universe"+"x"+str(x)+"_"+str(x_)+"y"+str(y)+"_"+ str(y_) +".jpg")
                        , patch)
            
            #保存之后,在原始图像上对当前索引出的区域绘制白色边框
            #注意这一操作将会在正在被切片的图像上进行
            cv2.rectangle(imgcopy #要绘制长方体的对象
                          , (x, y), (x_, y_) #整个正方形的左上角和右下角的坐标
                          , (255, 255, 255) #使用的颜色
                          , 2 #线条的粗细,数字越大越粗
                         )
#循环完毕后,绘制被我们分割后的图像            
plt.figure(dpi=300)
plt.imshow(imgcopy)
plt.axis("off");

在这里插入图片描述

现在可以检查目标文件夹,观察所有被分割的图像了。

  • 批量处理大型图像

当我们有大量的大型图像需要处理时,我们首先要从文件夹中将所有的图像都读入。在这里,我们需要借助os库下著名函数listdir的力量:

os.listdir(path):读取目录中所有的文件名

只要有文件名,我们就可以在cv2.imread当中按照文件名一一读入相应的图像。同时,对于不是图片数据的文件名,cv.imread会读取失败,从而导致读入的对象为None。因此我们也需要对读入的对象进行检查,对于任何不是None的对象(也就是对于任意成功读取的图像),我们将其保存在列表当中:

def load_images_from_folder(folder):
    """批量读取文件夹中的图片"""
    images = [] #将准备读取的图像保存在列表当中,因为arrays是不允许在循环中逐渐添加对象的
    for filename in os.listdir(folder):
        img = cv2.imread(os.path.join(folder,filename))
        if img is not None:
            images.append(img)
    return images
images = load_images_from_folder(PATH)

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

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

相关文章

Inbound marketing | LTD入站营销是对Hubspot集客营销的升级

你如何理解Inbound marketing? 你如何理解Inbound marketing。 集客营销抑或是入站营销。 2006年,MIT的在校学生BrianHalligan和DharmeshShah(hubspot的创始人)首次提出Inbound marketing,有别于推广式营销的一种全…

【已解决】Vue项目中Vite以及Webpack代码混淆处理

🐱 个人主页:不叫猫先生,公众号:前端舵手 🙋‍♂️ 作者简介:前端领域优质作者、阿里云专家博主,共同学习共同进步,一起加油呀! 📢 资料领取:前端…

触发点击事件,标签高亮显示

文章目录 🎀前言:🏨技术选型:vue中v-bind、v-for、的使用以及三目表达式操作步骤:标签动态属性响应函数标签样式 🎀前言: 我们经常在点击菜单时,会有颜色高亮显示(以红色为例)。在点…

看来直播带货不会被取消了

我是卢松松,点点上面的头像,欢迎关注我哦! 这个月大家一直都在讨论印尼关闭电商直播,争论国内是否应该关闭直播电商,而且讨论的愈演愈烈,卢松松也发布了很多相关的信息和言论。 结果10月20日,…

Microsoft Edge浏览器中使用免费的ChatGPT

一、双击打开浏览器 找到:扩展,打开 二、打开Microsoft Edge加载项 三、Move tab新标签 获取免费ChatGPT 四、启用Move tab。启用ChatGPT。 扩展 管理扩展 启用 五、新建标签页,使用GPT 六、使用举例 提问 GPT回复

因为做了这样的项目,成为了offer收割机!

作者:小傅哥 博客:https://bugstack.cn 沉淀、分享、成长,让自己和他人都能有所收获!😄 文章目录 一、项目视图二、学习路线1. 实习生2. 校招生3. 社招生 四、目标路径五、项目组合 注意:小傅哥的星球&…

紫光同创FPGA实现HSSTLP高速接口视频传输,8b/10b编解码,OV5640采集,提供PDS工程源码和技术支持

目录 1、前言免责声明 2、我这里已有的 GT 高速接口解决方案3、设计思路框架设计框图OV5640摄像头配置及采集视频数据封装按键选择HSSTLP高速收发器详解HSSTLP基本了解HSSTLP之时钟HSSTLP之PCSHSSTLP之PMAHSSTLP之接口说明硬件设计HSSTLP IP调用和配置 SFP连接方案选择视频数据…

(免费领源码)hadoop#Mysql离线与实时的离线与实时的电影推荐系统10338-计算机毕业设计项目选题推荐

摘 要 随着互联网与移动互联网迅速普及,网络上的电影娱乐信息数量相当庞大,人们对获取感兴趣的电影娱乐信息的需求越来越大,个性化的离线与实时的电影推荐系统 成为一个热门。然而电影信息的表示相当复杂,己有的相似度计算方法与推荐算法都各…

支持语音与视频即时通讯项目杂记(二)

目录 概念: 视频帧(Video Frame)是组成视频的基本单元。它可以被视为一幅静止的图像,它在一定的时间间隔内连续播放,从而形成了流畅的视频。 Changes to Qt Multimedia New features in Qt 6 Removed features C…

【具身智能模型2】RT-1: Robotics Transformer for Real-World Control at Scale

论文标题:RT-1: Robotics Transformer for Real-World Control at Scale 论文作者:Anthony Brohan, Noah Brown, Justice Carbajal, Yevgen Chebotar, Joseph Dabis, Chelsea Finn, Keerthana Gopalakrishnan, Karol Hausman, Alex Herzog, Jasmine Hsu,…

如何处理前端打包体积过大的问题?

聚沙成塔每天进步一点点 ⭐ 专栏简介 前端入门之旅:探索Web开发的奇妙世界 欢迎来到前端入门之旅!感兴趣的可以订阅本专栏哦!这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打造的。无论你是完全的新手还是有一些基础的开发…

如何使用前端桌面应用程序框架(Electron等)?

聚沙成塔每天进步一点点 ⭐ 专栏简介 前端入门之旅:探索Web开发的奇妙世界 欢迎来到前端入门之旅!感兴趣的可以订阅本专栏哦!这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打造的。无论你是完全的新手还是有一些基础的开发…

STM32实现USB转TTL串口工具

STM32实现USB转TTL串口工具 具有USB接口和UART接口的STM32芯片,如STM32F1, STM32F4等等,都可以实现USB转TTL串口工具的制作。目前具有USB接口的最小资源的芯片是STM32F103C6T6。这里介绍USB转UART的代码设计。 STM32例化的USB VCOM,数据通讯…

(1)(1.1) Bluetooth

文章目录 前言 1 连接到自动驾驶仪 2 连接Mission Planner快速入门 3 与Mission Planner的详细连接 4 从安卓地面站连接 5 如何更改波特率、设备名称和设备密码 6 故障排除 7 产品规格 前言 蓝牙数据链路(如 HC-06 模块)(HC-06 module)可用于将…

Node.JS---npm相关

文章目录 前言一、package.json配置项version:1.0.0devDependenciesdependenciespeerDependenciesoptionalDependencies 二、npm命令1、npm config listxmzs使用2、npm installpackage-lock.json作用 3、npm run4、 查看全局安装的可执行文件 npm生命周期npxnpx简介…

对象属性的读写两种方法

【小白从小学Python、C、Java】 【计算机等考500强证书考研】 【Python-数据分析】 对象属性的读写 两种方法 选择题 下列代码执行输出的结果是? class C(object): name hello c1 C() print("【执行】c1C()") print("【显示】print(c1.name)") print(c…

伽马函数:将阶乘函数扩展到正整数之外

一、说明 ,是对阶乘这种运算的实数域拓展。属于高级的数学模型,在高级概率模型用于定义分布函数。本文将介绍这个函数的基础概念和属性。 二、gamma函数定义 众所周知,阶乘这个运算本来是用于简化形如 n(n−1)(n−2)…321 的乘积的&#xff0…

OCR文字识别软件对于硬件的哪方面需求较高?

这个还得看OCR软件是远程识别还是本地识别,前者对电脑配置要求相对较低,因为OCR识别是在远程服务器上进行的,本地只是负责优化图片和保存识别结果,如金鸣表格文字识别和眼精星表格文字识别这类的软件就是基于远程的OCR识别方案&am…

MySQL性能优化指南:深入分析重做日志刷新到磁盘的机制

文章目录 🌟 MySQL重做日志性能优化指南🍊 重做日志对数据库性能的影响🍊 重做日志刷入磁盘的机制🍊 实战使用🎉 1. 确认MySQL的redo log配置🎉 2. 强制刷新重做日志🎉 3. 检查重做日志是否已经…

【GIS前言技术】到底什么是实景三维?

文章目录 什么是实景三维?实景三维是怎么制作的?实景三维有哪些应用? 什么是实景三维? 实景三维是客观真实反映现实世界的三维模型,具有单体化、实体化、结构化、语义化的特点,通过融合模型三维、倾斜三维…