python的opencv使用记录(一)

前言

​ 最近在了解一个医学图像的项目,自己一个人开始调研并进行初步的可行性验证。所以重新开始写一些代码,选用的技术方案是python语言 + opencv图像处理库做一些图像上的处理。

​ 在过程中碰到一些具体的技术问题,做一个记录。

一些小技巧

图层相关操作

​ 数组array是Numpy库中最基本对象,而OPENCV通过cv2.imread函数(默认)读取进来的图像为
w i d t h ∗ h e i g t ∗ c h a n n e l s width * heigt * channels widthheigtchannels
的一个三维数组,这个三维数组就是通过np.array这个结构来保存的。

  • 数组切片

    图像操作中的一个常用的操作就是获取RGB中的其中一个图层,这里需要注意的一点是,虽然我们经常说RGB,但是通过cv2.imread函数读取进来的图层顺序是B(Blue), G(Green), R(Red)。所以获取一个图层单独数据的代码可以是:

    img = cv2.imread(src)
    img_blue = img[:, :, 0:1]
    img_green = img[:, :, 1:2]
    img_red = img[:, :, 2:3]
    
    print(img_blue.shape)
    

    通过python语言中的切片操作来获取某一个图层的数据,这样获得的数据结构是一个
    w i d t h ∗ h e i g t ∗ 1 width*heigt*1 widthheigt1
    的三维数组。

  • 数组降维

    opencv中很多函数的处理对象都是二值化图像,而二值化函数

    cv2.threshold(img, threshold_value, 255, cv2.THRESH_BINARY)
    

    的处理对象只能是一个二维数组,上述切片操作获得图层数据后,还需要进行降维操作,可通过代码:

    img_red_2D = img_red[:, :, 0] 
    
    print(img_red_2D.shape)
    

    来获得一个二维数组,这样代码的输出结果就是
    w i d t h ∗ h e i g t width*heigt widthheigt
    的二维数组。

  • 和cv2.cvtColor的关系

    在opencv中,cv2.imread函数可以加上参数:

    img = cv2.imread(src, cv2.COLOR_BGR2GRAY)
    

    来确定通过什么样的方式来加载图像。opencv会根据原始图像是否有多个图层来进行计算,具体计算规则可以参考opencv的官方文档。

    就具体问题而言,我接触到的项目中,原始图像是分成三个文件,每个文件保存一个图层的数据,我的处理方式就是通过多个对象来保存数据:

    blue = cv2.imread(src_blue, cv2.COLOR_BGR2GRAY)
    green = cv2.imread(src_green, cv2.COLOR_BGR2GRAY)
    red = cv2.imread(src_red, cv2.COLOR_BGR2GRAY)
    

    当然,也可以不加参数直接加载单层图像,opencv会自动将其扩展为3个通道:

    img = cv2.imread(src_blue)
    

    通过调试来观察其区别:

    img的结构(自动扩展):

在这里插入图片描述

blue的结构(单图层结构):

在这里插入图片描述

可以看出,对于单图层,如果不指定加载方式,opencv会自动将单图层的数据复制三份。这样加载后再通过切片降维后得到的数据是一样的。

  • 图层合并 & 数组升维

    我的项目中,原始图像是单通道图像,所以我是通过指定cv2.COLOR_BGR2GRAY的方式加载,得到的是一个二维数组,而最终需要展示出一个RGB图像,所以需要对这些数据进行合并。

    我的合并代码如下:

    def combineMutiChannel(blue, green, red):
        img_combine = np.zeros((blue.shape[0], blue.shape[1], 3), dtype="uint8")
    
        img_combine[:, :, 0:1] = blue[:, :, np.newaxis]
        img_combine[:, :, 1:2] = green[:, :, np.newaxis]
        img_combine[:, :, 2:3] = red[:, :, np.newaxis]
    
        return img_combine
    

    通过blue[:, :, np.newaxis]将二维数组补充一个新的维度,再通过切片操作进行赋值。

    这里有一个需要注意的点,如果是通过np.zeros/np.ones等函数创建的数组,最好是显式的指定数据格式,因为RGB的数据都是UINT8,而np有时候得到的数据会是float64等数据类型,这样在opencv的很多操作中都会报错。

OPENCV图像操作

​ 在使用opencv的过程中,用到了几个基本的图像处理函数,做个记录,用于后续备查。

  • 掩膜 & 连通域

    掩膜操作是图像处理中非常常见的一个操作:相当于使用一个和目标区域相同大小的布尔值矩阵,如果为true,就将这个像素点取出

    我在项目中的用处主要是找连通域,在opencv的找连通域函数connectedComponentsWithStats中,会返回一个和目标图像尺寸相同的标记图像,用不同的数字来标记不同的连通域。

    代码如下:

    def filterConnectZone(src_img):
        # 膨胀操作
        kernel2 = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
        bin_clo = cv2.dilate(src_img, kernel2, iterations=1)
    
        num_labels, labels, stats, centroids = cv2.connectedComponentsWithStats(bin_clo, connectivity=8)
    
        # 查看各个返回值
        # 连通域数量
        # print('num_labels = ', num_labels)
        # # 连通域的信息:对应各个轮廓的x、y、width、height和面积
        # print('stats = ', stats)
        # # 连通域的中心点
        # print('centroids = ', centroids)
        # # 每一个像素的标签1、2、3.。。,同一个连通域的标签是一致的
        # print('labels = ', labels)
    
        # 过滤连通区域
        # 面积小于 100
        # 不是圆形,1 到x和到y的直径不一致,2 面积和圆形面积的比值
        # output = np.zeros((dst_blue.shape[0], dst_blue.shape[1], 1), np.uint8)
        output = np.zeros((dst_blue.shape[0], dst_blue.shape[1]), np.uint8)
        for i in range(1, num_labels):
            mask = labels == i
            output[:, :, 0][mask] = np.random.randint(0, 255)
            output[:, :, 1][mask] = np.random.randint(0, 255)
            output[:, :, 2][mask] = np.random.randint(0, 255)
    
    

    上述代码中,通过mask = labels == i获得一个和labels 尺寸相同的掩膜:mask

    对掩膜的使用就是:

    output[:, :, 0][mask] = np.random.randint(0, 255)
    
    x = output[:, :, 0][mask]
    

    相当于就是在output的第一个图层上套一个mask掩膜,输出是一个数组,这个数组就是mask中为true的位置所对应的像素点,并将这些像素点赋值为一个随机数。使用调试模式可以看到x为:

在这里插入图片描述

  • 获取感兴趣区域

    操作很简单,直接通过切片获得一个区域即可:

    roi = img_combine_final[roi_LT_y: roi_RB_y, roi_LT_x: roi_RB_x]
    

    需要注意的是,y坐标在前,x坐标在后。各位可以想一下x, y分别代表的含义就清楚了。

  • 寻找图层间的重叠区域

    我的方案是:使用cv2.bitwise_and求交集,再使用cv2.bitwise_or计算并集,再使用连通域求交并比,来判断重叠区域有多大。

    dst_green = cv2.bitwise_and(output_blue, dst_green)
    dst_red = cv2.bitwise_and(output_blue, dst_red)
    
    dst_green = cv2.bitwise_or(output_blue, dst_green)
    dst_red = cv2.bitwise_or(output_blue, dst_red)
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

新兴AI民工

码字不易,各位看客随意

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值