小杰机械视觉(two day)—— 形态学变换,颜色替换, ROI切割

#【投稿赢 iPhone 17】「我的第一个开源项目」故事征集:用代码换C位出道!#

核心:

开闭操作: cv2.MORPH_OPEN                 cv2.MORPH_CLOSE           

                   先腐蚀(erode)后膨胀(),先膨胀后腐蚀

                   1.降噪,2断开细小连接            1.进行图形修边

核: kennel         形状      cv2.getStructuringElement

                        MORPH_RECT 矩形

                        MORPH_ELLIPSE 椭圆

                        MORPH_CROSS 十字形

掩膜  inRange        查找某一颜色的图象

颜色替换:        循环,找到掩膜为白色区域,给原图换色。

ROI切割 :  需要注意x(列数)和y(行数)的顺序

1.形态学变换

(1)概念

        形态学变换(Morphological Transformations)是一种基于形状的简单变换,它的处理对象通常是二值化后(白色前景,黑色背景)的图像。

形态学变换需要两个输入:

  • 源图像(二值化)
  • 核(结构化元素)

输出为形态学变换后的图像:

  • 腐蚀        位与操作
  • 膨胀        位或操作

上面两种形态学变换的处理结果是相反的,腐蚀会让较亮的元素变少,膨胀会让较亮的元素变多。

腐蚀和膨胀

(2)核

        为一个小区域,且为奇数矩阵,在本章形态学内,核会增加结构

其结构为三类:

  • 矩形结构
  • 椭圆结构
  • 十字形结构

通过不同的结构可以对不同特征的图像进行形态学操作的处理。

节点参数如下:

  • morph_op_type 形态学操作类型
    • erode 腐蚀
    • dilate 膨胀
  • shape 核的形状
    • MORPH_RECT 矩形
    • MORPH_ELLIPSE 椭圆
    • MORPH_CROSS 十字形
  • ksize 核尺寸
  • 核的创建 : kernel = cv2.getStructuringElement(
            cv2.MORPH_ELLIPSE,  # 核的形状
            (3, 3)  # 核的尺寸
        )

(3)代码

import cv2
import numpy as np

if __name__ == '__main__':
    # 1. 图片输入
    path = 'image.png'
    image_np = cv2.imread(path)

    # 2. 灰度化
    image_np_gray = cv2.cvtColor(image_np, cv2.COLOR_BGR2GRAY)

    # 3. 二值化
    ret, image_np_thresh = cv2.threshold(image_np_gray, 127, 255, cv2.THRESH_BINARY)

    # 4. 形态操作
    # 创建一个核
    kernel = cv2.getStructuringElement(
        cv2.MORPH_ELLIPSE,  # 核的形状
        (3, 3)  # 核的尺寸
    )
    print(kernel)
    # 腐蚀使用erode函数,膨胀使用dilate函数
    # 返回值是形态处理之后的图像
    morph_image = cv2.dilate(
        image_np_thresh,  # 二值化图像
        kernel  # 核
    )

    # 5. 图像输出
    cv2.imshow('morph_image',morph_image)
    cv2.waitKey(0)

腐蚀掉空心星星,尽量让实心星星形状保持原样(颜色无所谓)。

解决思路,先腐蚀再膨胀         (开运算)

import cv2
# From 25072 张家豪

if __name__ == '__main__':
    path = 'star.png'
    img = cv2.imread(path)
    # 灰度化
    img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    # OTSU二值化
    _, img_binary = cv2.threshold(img_gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
    # 创建一个核
    kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (9, 9))
    # 腐蚀
    eroded = cv2.erode(img_gray, kernel)
    # # 膨胀
    kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
    dilated = cv2.dilate(eroded, kernel)
    # 使用CV2绘图
    cv2.imshow('eroded', dilated)
    cv2.waitKey(0)

2.颜色的识别

(1)RGB颜色空间

        电脑显示屏以及上面实验中所介绍的RGB彩色图。

        RGB颜色模型基于笛卡尔坐标系,如下图所示,RGB原色值位于3个角上,二次色青色、红色和黄色位于另外三个角上,黑色位于原点处,白色位于离原点最远的角上。因为黑色在RGB三通道中表现为(0,0,0),所以映射到这里就是原点;而白色是(255,255,255),所以映射到这里就是三个坐标为最大值的点。

        RGB颜色空间可以产生大约1600万种颜色,几乎包括了世界上的所有颜色,也就是说可以使用RGB颜色空间来生成任意一种颜色。

(2)HSV颜色空间

HSV颜色空间(HSV颜色模型,也成为HSL)是一种与RGB颜色模型并列的颜色空间表示法。

        HSV颜色空间使用色调或色相(Hue)饱和度(Saturation)亮度或明度(Value)三个参数来表示颜色,色调H表示颜色的种类,如红色、绿色、蓝色等;饱和度表示颜色的纯度或强度,如红色越纯,饱和度就越高;亮度表示颜色的明暗程度,如黑色比白色亮度低。HSV颜色模型是一种六角锥体模型。

      

由于HSV的颜色是连续的,比RGB更适合进行颜色范围划分,常见的颜色经过试验得到的范围如下:

由于颜色是8位的,所以最多表示256个数字,无法完全表示360°,OpenCV重新换算了色调的角度,范围是0到180°。

HSV三个属性是相互共同作用的,例如橙色必须是H范围11-25且S范围是43-255且V范围46-255。

  

2)掩膜        inRange()

mask1 = cv2.inRange(

hsv_image_np, # 基于哪个图像

red_low, # 下限

red_high # 上限

)

掩膜与原图的大小相同,并且像素的一一对应的

        掩膜通常是一个二值化图像,并且与原图相同大小,其中目标区域被设置为255(白色),而其他区域设置为0(黑色),目标区域可以根据HSV的参数修改,上左图中就是制作红色掩膜的过程。

通过掩膜可以使用白色区域操作原图中的同位置像素。

2.颜色的替换

(1)开闭操作

开操作        先腐蚀,后膨胀        cv2.MORPH_OPEN

特点:   1.降噪,2.断开细小连接

闭操作(用的少)        cv2.MORPH_CLOSE

(2)颜色替换

        可以在图像中识别某一种(多种)颜色,那么就可以对这些颜色进行单独操作,比如替换成其他的颜色,原理就是在得到掩膜后,对掩膜中白色区域的原图进行一个像素值的修改。

        由于掩膜与原图的大小相同,并且像素的一一对应的,可以得到掩膜中的白色区域坐标,把掩膜中所有白色区域的坐标带入到原图中,就可以得到原图中所有红色区域的坐标。拿到原图红色的坐标后,可以进行任何红色像素值的操作,例如修改颜色。

例:

修改红色圆圈为蓝色,不修改红色噪点。

import cv2
import numpy as np

if __name__ == '__main__':
    # 1. 图片输入
    path = 'Circles.png'
    image_np = cv2.imread(path)

    # 2. HSV空间转换
    hsv_image_np = cv2.cvtColor(image_np, cv2.COLOR_BGR2HSV)
    print(hsv_image_np.shape)
    # print(hsv_image_np)

    # 3. 制作掩膜
    # 定义红色范围1
    red_low = np.array([0, 43, 46])
    red_high = np.array([10, 255, 255])
    # 制作掩膜1
    mask1 = cv2.inRange(
        hsv_image_np,  # 基于哪个图像
        red_low,  # 下限
        red_high  # 上限
    )
    print(mask1.shape)
    print(mask1)
    # 定义红色范围2
    red_low = np.array([156, 43, 46])
    red_high = np.array([180, 255, 255])
    # 制作掩膜2
    mask2 = cv2.inRange(
        hsv_image_np,  # 基于哪个图像
        red_low,  # 下限
        red_high  # 上限
    )

    # 合并掩膜
    mask_image_np = cv2.bitwise_or(mask1, mask2)
    print(mask_image_np.shape)
    print(mask_image_np)

    # 4. 开运算
    # 创建一个核
    kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
    # 开运算
    open_image_np = cv2.morphologyEx(
        src=mask_image_np,  # 需要计算的二值化图像
        op=cv2.MORPH_OPEN,  # 开操作还是闭操作cv2.MORPH_CLOSE
        kernel=kernel  # 核
    )

    # 7. 颜色替换
    for i in range(open_image_np.shape[0]):
        for j in range(open_image_np.shape[1]):
            # 如果当前遍历的像素点是掩膜的白色
            if open_image_np[i, j] == 255:
                # 给原图进行颜色替换为蓝色
                image_np[i, j] = (255, 0, 0)

    # 6. 图片输出
    cv2.imshow('mask_image_np', mask_image_np)
    cv2.imshow('open_image_np', open_image_np)
    cv2.imshow('image_np',image_np)
    cv2.waitKey(0)

3. ROI 切割   cv2.rectangle()

        ROI(Region of Interest,感兴趣区域)指的是从原始图像中定义处特定的区域,该区域对于后续的分析、处理具有特别的意义。

本质上是通过Numpy数组的切片操作完成。

参数如下:

  • x_min:ROI区域最小的横坐标
  • x_max:ROI区域最大的横坐标
  • y_min:ROI区域最小的纵坐标
  • y_max:ROI区域最大的纵坐标

在OpenCV中坐标的x轴正方向是水平向右的,y轴的正方向是垂直向下的。

另外Numpy存储图像是一个三维数组:

  • 第一个维度(0):高度(行数)
  • 第二个维度(1):宽度(列数)
  • 第三个维度(2):三个通道BGR的像素值

实际处理中需要注意x(列数)和y(行数)的顺序。

具体操作:有切割时具体线宽

# 框的宽度

line_width = 2

image_np_copy = image_np.copy()

# 画出ROI区域

cv2.rectangle(

image_np,

(x_min, y_min),

(x_max, y_max),

(0, 0, 255),

line_width

)

# 切片(左闭右开)

ROI_imge = image_np_copy[y_min:y_max, x_min:x_max]

例:

使用ROI切割,截取坤坤的篮球。

import cv2
import numpy as np

if __name__ == '__main__':
    # 1. 图片输入
    path = 'kunkun.png'
    # 因为ROI区域可能越界,可以加入异常处理机制
    try:
        image_np = cv2.imread(path)
        # 获得图像尺寸
        (h, w, _) = image_np.shape
        print(h, w)

        # 2. 图片切割
        x_min, x_max = 510, 602
        y_min, y_max = 271, 361

        # 判断ROI区域是否合理
        if not ((x_min > 0) and (x_max < w) and (y_min > 0) and (y_max < h)):
            raise OverflowError('范围越界!!!')
        if (x_min >= x_max) or (y_min >= y_max):
            raise ValueError("最值错误!!!")

        # 框的宽度
        line_width = 2
        image_np_copy = image_np.copy()
        # 画出ROI区域
        cv2.rectangle(
            image_np,
            (x_min, y_min),
            (x_max, y_max),
            (0, 0, 255),
            line_width
        )

        # 切片(左闭右开)
        ROI_imge = image_np_copy[y_min:y_max, x_min:x_max]

        # 3. 图片输出
        cv2.imshow('image_np', image_np)
        cv2.imshow('ROI_imge', ROI_imge)
        cv2.waitKey(0)

    except Exception as e:
        # 如果出错,弹出错误信息
        print('错误信息:', e)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值