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

基于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)

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

OpenCV实现物体尺寸的测量

一 ,项目分析 物体尺寸测量的思路是找一个确定尺寸的物体作为参照物,根据已知的计算未知物体尺寸。 如下图所示,绿色的板子尺寸为220*300(单位:毫米),通过程序计算白色纸片的长度。 主要是通过…

我国有多少个港口?

港口是什么? 港口是海洋运输中不可或缺的重要设施之一,是连接陆路和水路运输的重要节点。港口通常是指位于沿海地区的水陆交通枢纽,是船舶停靠、装卸货物、储存物资和维修船只的场所。港口一般由码头、泊位、仓库、货场、客运站等设施组成&a…

数据结构和算法概述

什么是数据结构? 官方解释: 数据结构是一门研究非数值计算的程序设计问题中的操作对象,以及他们之间的关系和操作等相关问题的学科。 大白话: 数据结构就是把数据元素按照一定的关系组织起来的集合,用来组织和存储…

【网安大模型专题10.19】※论文5:ChatGPT+漏洞定位+补丁生成+补丁验证+APR方法+ChatRepair+不同修复场景+修复效果(韦恩图展示)

Keep the Conversation Going: Fixing 162 out of 337 bugs for $0.42 each using ChatGPT 写在最前面背景介绍自动程序修复流程Process of APR (automated program repair)1、漏洞程序2、漏洞定位模块3、补丁生成4、补丁验证 (可以学习的PPT设计)经典的…

Spring Cloud之服务熔断与降级(Hystrix)

目录 Hystrix 概念 作用 服务降级 简介 使用场景 接口降级 服务端服务降级 1.添加依赖 2.定义接口 3.实现接口 4.Controller类使用 5.启动类添加注释 6.浏览器访问 客户端服务降级 1.添加依赖 2.application.yml 中添加配置 3.定义接口 4.Controller类使用 …

解读意大利葡萄酒分类系统

由于该国众多的产区和复杂的品种,要想真正掌握意大利葡萄酒是相当困难的。仅仅是试图从复杂混乱的葡萄酒标签中辨别信息的想法就足以让许多人焦虑不安。 位于托斯卡纳的基安蒂酒地区,Il Ciliegio生产的葡萄酒标签上包含以下名称之一:基安蒂酒科利塞内西…

通过IP地址可以做什么

通过IP地址可以做很多事情,因为它是互联网通信的基础之一。本文将探讨IP地址的定义、用途以及一些可能的应用。 IP地址的用途 1. 设备标识:IP地址用于标识互联网上的每个设备,这包括计算机、服务器、路由器、智能手机等。它类似于我们日常生…

unity 一键替换 UI上所有字体,批量替换字体(包括:Text和Text (TMP))

前言:在开发中会遇到这种情况,开发完了,发现UI字体没有替换,特别是需要发布到WebGL端的同学,突然发现无法显示汉字了。下面一个非常方便的方法完美解决。 1.解压出来的脚本放在Edit文件下,没有的创建一个 2…

Linux 基于sysfs的GPIO读写操作

https://bbs.huaweicloud.com/blogs/297252 前言 最近接触到Linux系统中的GPIO开发,这里做个小总结,也分享一下;本文会介绍GPIO的读写,介绍基本原理,以及不同读写方式的性能。 一、GPIO sysfs interface 基本原理 …

计算机视觉中的数据预处理与模型训练技巧总结

计算机视觉主要问题有图像分类、目标检测和图像分割等。针对图像分类任务,提升准确率的方法路线有两条,一个是模型的修改,另一个是各种数据处理和训练的技巧(tricks)。图像分类中的各种技巧对于目标检测、图像分割等任务也有很好的作用&#…

Http长连接同一个socket多个请求和响应如何保证一一对应?

HTTP/2引入二进制数据帧和流的概念,其中帧对数据进行顺序标识,如下图所示,这样浏览器收到数据之后,就可以按照序列对数据进行合并,而不会出现合并后数据错乱的情况。同样是因为有了序列,服务器就可以并行的…

从REST到GraphQL:升级你的Apollo体验

前言 「作者主页」:雪碧有白泡泡 「个人网站」:雪碧的个人网站 「推荐专栏」: ★java一站式服务 ★ ★ React从入门到精通★ ★前端炫酷代码分享 ★ ★ 从0到英雄,vue成神之路★ ★ uniapp-从构建到提升★ ★ 从0到英雄&#xff…

【Java系列】ArrayList

ArrayList 添加元素访问元素修改元素删除元素计算大小迭代数组列表其他的引用类型ArrayList 排序Java ArrayList 方法系列文章系列文章版本记录 引言 ArrayList 类是一个可以动态修改的数组,与普通数组的区别就是它是没有固定大小的限制,我们可以添加或删…

Guava-RateLimiter详解

简介: 常用的限流算法有漏桶算法和令牌桶算法,guava的RateLimiter使用的是令牌桶算法,也就是以固定的频率向桶中放入令牌,例如一秒钟10枚令牌,实际业务在每次响应请求之前都从桶中获取令牌,只有取到令牌的请…

structs2 重构成SpringBoot架构

structs2 重构成SpringBoot架构 目录参考资料和推荐阅读 Survive by day and develop by night. talk for import biz , show your perfect code,full busy,skip hardness,make a better result,wait for change,challenge Survive. happy for hardess to solve den…

JAVA电商平台免费搭建 B2B2C商城系统 多用户商城系统 直播带货 新零售商城 o2o商城 电子商务 拼团商城 分销商城

涉及平台 平台管理、商家端(PC端、手机端)、买家平台(H5/公众号、小程序、APP端(IOS/Android)、微服务平台(业务服务) 2. 核心架构 Spring Cloud、Spring Boot、Mybatis、Redis …

vue如何使用冻结对象提升代码效率及其原理解析

先给大家伙整个实际工作中一定会碰到的问题 如下vue dome ,它的代码非常简单功能也1非常简单,就是一个按钮,点击后会显示有多少条数据 来看看源码, html部分就是一个按钮绑定了一个loadData事件,然后在p标签内展示了这个myData这个数据的长度 <template><div id&quo…

竞赛选题 深度学习卫星遥感图像检测与识别 -opencv python 目标检测

文章目录 0 前言1 课题背景2 实现效果3 Yolov5算法4 数据处理和训练5 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; **深度学习卫星遥感图像检测与识别 ** 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学长非常推荐…

知识图谱+推荐系统 文献阅读

文献阅读及整理 知识图谱推荐系统 知识图谱 1 基于知识图谱的电商领域智能问答系统研究与实现 [1]蒲海坤. 基于知识图谱的电商领域智能问答系统研究与实现[D].西京学院,2022.DOI:10.27831/d.cnki.gxjxy.2021.000079. 知识点 BIO标记策略进行人工标记,构建了电商领域商品…

嚼一嚼Halcon中的3D手眼标定

文章目录 一、问题概述1、何为手眼标定&#xff1f;2、手眼标定的2种形式1&#xff09;眼在手上&#xff08;eye in hand&#xff09;&#xff1a;即相机固定在机械臂末端2&#xff09;眼在手外&#xff08;eye to hand&#xff09;&#xff1a;即相机固定在机械臂以外的地方 3…