NO.2 机器视觉 几何变化 & 特效处理

零蚀


几何操作

  • 图像的放大缩小
    • 图像的放大&缩小,是将 图片变大变小,由于图像的宽高发生了变化,所以我们需要重新计算每个位置的图像像素的值。

    • 图像常见的缩放算法有以下4种

      • 最近领域插值法
      • 双线插值
      • 像素关系重采样
      • 立方插值
    • 最近领域插值,是将图像扩大后的空白像素点,由附近的像素颜色进行计算填充。

    • 手动实现缩放,在缩小时候 ,以下方法会有像素丢失,放大也会导致像素严重失真,因为会获取到临近点的像素值,(这也是最近领域插值)。

    import cv2 as cv
    import numpy as np
    
    if __name__ == '__main__':
        src = cv.imread("../source/android.png")
    
        height = src.shape[0]
        width = src.shape[1]
    
        # 缩放的系数
        scale = 2
    
        # 构建行的mat
        n_height = int(height * scale)
        n_width = int(width * scale)
        dst = np.zeros((n_height, n_width, 3), np.uint8)
    
        for row in range(n_height):
            for col in range(n_width):
                # 找到对应在原图的像素位置的像素点
                current_row_value = int(row / scale)
                current_col_value = int(col / scale)
                dst[row, col] = src[current_row_value, current_col_value]
        cv.imshow("", src)
        cv.imshow("", dst)
        cv.waitKey(0)
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QNJXlIAl-1600576617797)(media/15987925486263/15999902788744.jpg)]

    • 双线插值,如下图所示,他是计算出这个小数点对应的原图的坐标位置然后进行色值权重计算,得出新的色值,比如(1.2 ,2.3)如果是最近领域插值法,就会直接进行直接的取整,就是(1 ,2)的像素点坐标,但是这种方式,在色彩波动较大的区域会导致取值很不友好,所以双线插值根据四周的情况进行一个取值计算,这就像根据坐标算出卷积核,然后再用卷积算出当前点的色值。
  • 根据矩阵来操作图像
    • 基本的图像操作会矩阵如下图所示操作,根具与我们的每个像素点的操作来计算出变化后的位置

    缩 放 = [ k x 0 0 0 k y 0 0 0 1 ] 旋 转 = [ c o s θ − s i n θ 0 s i n θ c o s θ 0 0 0 1 ] 位 移 = [ 1 0 t x 0 1 t y 0 0 1 ] 缩放= \begin{bmatrix}k_x & 0 & 0 \\ 0 & k_y & 0\\ 0 & 0 & 1\end{bmatrix} 旋转=\begin{bmatrix}cos\theta & -sin\theta & 0 \\ sin\theta & cos\theta & 0 \\ 0 & 0 & 1 \end{bmatrix} 位移 = \begin{bmatrix} 1 & 0 & t_x \\ 0 & 1 & t_y \\ 0 & 0 & 1\end{bmatrix} =kx000ky0001=cosθsinθ0sinθcosθ0001=100010txty1

    # 坐标(为了满足矩阵相乘而补的齐次矩阵,最后一个参数也可以作为平移的单位的倍数)
    matrixA = np.array([x, y, 1])
    
    # 平移矩阵(相当于x向右平移200,y向右平移100)
    matrixB = np.array([[1, 0, 200],
                        [0, 1, 100]])
    
    # 平移矩阵 * 坐标矩阵的转秩
    print(matrixB.dot(matrixA.T))
    
    • 手动实现图像的平移
    import cv2 as cv
    import numpy as np
    
    if __name__ == '__main__':
        src = cv.imread("../source/android.png")
    
        height = src.shape[0]
        width = src.shape[1]
    
        dst = np.zeros(src.shape, np.uint8)
    
        x = 3
        y = 2
    
        for row in range(height):
            for col in range(width):
                matrix_src = np.array([col, row, 1])
    
                matrix_tool = np.array([[1, 0, 100],
                                        [0, 1, 50]])
    
                # 得到新的像素点位置
                result = matrix_tool.dot(matrix_src)
    
                new_col = result[0]
                new_row = result[1]
    
                if new_row < height and new_col < width:
                    dst[new_row, new_col] = src[row, col]
    
        cv.imshow("1", src)
        cv.imshow("2", dst)
        cv.waitKey(0)
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kRZFNbaR-1600576617799)(media/15987925486263/16000023370806.jpg)]

    • 上述原理实现平移的过程,opencv有API,
    import cv2 as cv
    import numpy as np
    import math
    
    src = cv.imread("../source/android.png")
    height = src.shape[0]
    width = src.shape[1]
    
    # 平移以前版本不支持np.array
    matrixTranslate = np.float32([[1, 0, 100],
                                 [0, 1, 50]])
    # 仿射交换(matrixTranslate 必须是2行3列)
    dst = cv.warpAffine(src, matrixTranslate, (width, height))
    
    cv.imshow("1", src)
    cv.imshow("2", dst)
    
    cv.waitKey(0)
    
    • 旋转图像的API,如果设置旋转中心(0,0)的话,坐标系和android的坐标系是一致的(左上角原点向右下为正方向)
       """
       :param center 旋转中心
       :param angle 角度
       :param scale 缩放
       """
       matrixTranslate = cv.getRotationMatrix2D((width / 2, height / 2), 45, 0.8)
       dst = cv.warpAffine(src, matrixTranslate, (width, height))
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FPMWCYQQ-1600576617800)(media/15987925486263/16000040854622.jpg)]

    • 矩阵变换:我们可以根据矩阵的三个点的坐标变化来进行拉伸变化,但是图像信息并不会丢失,如下图所示。(需要注意的是这里只是改变3个坐标点,)
    # 初始矩阵(四点坐标列表)
    matrix_origin = np.float32([[0, 0], [0, height], [width, 0]])
    # 目标矩阵
    matrix_aim = np.float32([[0, 50], [0, height - 50],  [width, 0]])
    # 变化矩阵
    matrix_change = cv.getAffineTransform(matrix_origin, matrix_aim)
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PhYdXMjr-1600576617801)(media/15987925486263/16000066640788.jpg)]

  • 金字塔
    • 图像分析时候,缩小图像如果使用cv.resize(mat,(w,h))图像信息会像素失真严重,所以为了保证图像轮廓保持清晰,我们会使用下采样的方式,图像金字塔中的上采样和下采样不会使得图像的像素轮廓信息丢失严重,它的内部是依赖于高斯模糊来实现。
    import cv2 as cv
    
    src = cv.imread("../source/android.png")
    cv.imshow("1",src)
    # 上采样
    #dst=cv.pyrUp(src)
    # 下采样(每次下采样,会将分辨率低1/2)
    dst=cv.pyrDown(src)
    
    cv.imshow("2",dst)
    cv.waitKey()
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VvQ0iJMW-1600576617802)(media/15987925486263/16000088069131.jpg)]

    import cv2 as cv
    
    src1 = cv.imread("../source/android.png")
    src2 = cv.imread("../source/clothes.png")
    
    # 两个图像融合(信息重叠)需要图像长,宽相同
    
    dst = cv.addWeighted(src1, 0.5, src2, 0.5, 0)
    
    cv.imshow("1", src1)
    cv.imshow("2", src2)
    cv.imshow("3", dst)
    cv.waitKey()
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ohAFTNXh-1600576617803)(media/15987925486263/16000095040965.jpg)]


特效处理

  • 灰度图像处理
    • 单通道处理,这里首先是将一个图像的BGR值进行剥离,分别用三个图像来展示这个图像中的BGR的单个通道值。
    import cv2 as cv
    
    src = cv.imread('../source/android.png')
    # 分离的每个channel的数值,分别是BGR
    result = cv.split(src)
    cv.imshow("blue", result[0])
    cv.imshow("green", result[1])
    cv.imshow("red", result[2])
    cv.waitKey(0)
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wwRUupaa-1600576617804)(media/15987925486263/16005156122267.jpg)]

    • 如果我们想吧一个图像变成灰度图,可以有几种方法:一种是我们在读取的时候直接以灰度图的方式进行读取。
    # 读取的时候直接以灰度图读取
    src = cv.imread('../source/android.png', cv.IMREAD_GRAYSCALE)
    # cvtColor方式,和Android 一致
    dst = cv.cvtColor(src, cv.COLOR_BGRA2GRAY)
    
  • 颜色取反&浮雕&马赛克
    • 取反,与运算,或运算,与或运算,这里所有的操作都是对像素的操作,他的操作如下所示,要注意的是,我们这些操作的图片的大小一定要相同,不然会报错。
    import cv2 as cv
    import numpy as np
    
    src = cv.imread('../source/android.png')
    src1 = cv.imread('../source/clothes.png')
    
    dst1 = np.zeros(src.shape, src.dtype)
    dst2 = np.zeros(src.shape, src.dtype)
    dst3 = np.zeros(src.shape, src.dtype)
    dst4 = np.zeros(src.shape, src.dtype)
    # 1取反
    
    cv.bitwise_not(src, dst1)
    # 2与运算
    cv.bitwise_and(src, src1, dst2)
    # 3或运算
    cv.bitwise_or(src, src1, dst3)
    # 4与或运算
    cv.bitwise_xor(src, src1, dst4)
    
    cv.imshow("1", dst1)
    cv.imshow("2", dst2)
    cv.imshow("3", dst3)
    cv.imshow("4", dst4)
    cv.waitKey(0)
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-enTeXrxt-1600576617805)(media/15987925486263/16005183082063.jpg)]

    • 均值模糊代码,通过卷积的相同得权重从而获取的模糊效果。Android**🔗 NO.3 Android Opencv 图像处理**中已经对每个模糊手段的原理和方式进行解答,这里不再赘述,感兴趣可以看看原理和公式。
    src = cv.imread('../source/android.png')
    dst = np.zeros(src.shape, src.dtype)
    """
    // 均值模糊
    :param src 源数据
    :param ksize 卷积和的范围
    :param dst 输出数据
    :param point 位置默认是(-1,-1)
    :param type 边缘类型
    """
    cv.blur(src, (15, 1), dst, (-1, -1), cv.BORDER_DEFAULT)
    cv.imshow("1", dst)
    cv.waitKey()
    
    
    • 马塞克的原理,马赛克的原理,就是将某个像素点的额色值复制给周边像素,导致颜色区域变大,最后轮廓失真导致马赛克,那么我们手写一个马赛克。
    src = cv.imread('../source/android.png')
    dst = np.zeros(src.shape, src.dtype)
    
    height = src.shape[0]
    width = src.shape[1]
    
    maxLine = 100
    
    color = src[0, 0]
    # 马赛克范围大小
    offset = 10
    
    for rows in range(height):
        for cols in range(width):
            if rows < maxLine:
                if rows % offset == 0 and cols % offset == 0:
                    color = src[rows, cols]
                    # 将 10 * 10 的区域同色化
                    for i in range(offset):
                        for j in range(offset):
                            src[rows + i, cols + j] = color
    
    cv.imshow("1", src)
    cv.waitKey()
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aPGgUfCW-1600576617805)(media/15987925486263/16005235099180.jpg)]

    • 浮雕效果,模糊有些事让边缘处于一种不清晰状态,而浮雕效果则是让轮廓更加明显。这就类似最简单的边缘检测,通过梯度方式(一阶导数),如果变化平坦就舍弃,如果有边界就保留。(一下就是当前像素减去前一个像素,差值的绝对值为当前像素值)
    src = cv.imread("../source/android.png")
    gray = cv.cvtColor(src, cv.COLOR_BGRA2GRAY)
    dst = np.zeros(src.shape, src.dtype)
    
    height = src.shape[0]
    width = src.shape[1]
    
    for row in range(height):
        for cols in range(1, width):
            # 获取前一个灰度值
            gray1 = gray[row, cols - 1]
            # 获取当前的灰度值
            gray2 = gray[row, cols]
            # 因为是uint8格式,如果是负数,会高位填充导致数据错误
            # 获取梯度值
            gradient = abs(int(gray2) - int(gray1))
            dst[row, cols] = gradient
    
    cv.imshow("1",dst)
    cv.waitKey()
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vRirg8xT-1600576617806)(media/15987925486263/16005303846289.jpg)]

  • 形状绘制
    • 绘制形状,这里的绘制形状和android有些不同,Android里如果想绘制出来的形状有颜色必须要将BRGA的类型转变为BGR才可以进行颜色绘制。而python中不需要计较这些。(参数参考源码)
    import cv2 as cv
    import numpy as np
    
    src = cv.imread("../source/android.png")
    src1 = cv.imread("../source/android.png")
    src2 = cv.imread("../source/android.png")
    # 画线
    cv.line(src, (0, 0), (200, 200), (255, 255, 0), 8)
    # 画圆
    cv.circle(src1, (100, 100), 50, (100, 100, 0), 8)
    # 画矩形
    cv.rectangle(src2, (50, 50), (150, 150), (0, 0, 255), 8)
    
    cv.imshow("1", src)
    cv.imshow("2", src1)
    cv.imshow("3", src2)
    cv.waitKey()
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4EDWxeOH-1600576617806)(media/15987925486263/16005695978166.jpg)]

    • 绘制文字,
    """
    绘制文本(不支持中文)
    org 位置
    fontface 样式
    fontscale 缩放
    """
    cv.putText(src4, "this is text", (0, 50), cv.FONT_HERSHEY_COMPLEX, 1, (0, 0, 255), 2)
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eZsuS3vM-1600576617807)(media/15987925486263/16005729070173.jpg)]

  • 滑动进度条的使用。

    src = cv.imread("../source/android.png")
    
    
    def change_offset(offset):
        height = src.shape[0]
        width = src.shape[1]
    
        for i in range(height):
            for j in range(width):
                B = offset if offset < 255 else 255
                src[i, j][0] = B
    
        cv.imshow("dst", src)
        print(offset)
    
    
    """
    创建滑动条
        ⚠️:进度条要在imshow之后创建,因为他要根据名称来确定添加的窗口
        :param name 滑动条的名称(滑动条前面的的文字label)
        :param windowname 需要定位的窗口名称
        :param value 起始值
        :param count 数值长度
        :param onChange 回调函数 (fun(value)形式)
    """
    change_offset(0)
    cv.createTrackbar("process", "dst", 0, 255, change_offset)
    

    在这里插入图片描述


🔗 前言
🔗 机器人视觉篇
🔗 NO.1 机器视觉 前言
🔗 NO.3 机器视觉 直方图 & 帧提取
🔗 NO.4 机器视觉 人脸识别&色彩过滤
🔗 NO.5 机器人视觉 二值化 & 卷积
🔗 NO.6 机器人视觉 霍夫检测 & 边缘查找
🔗 NO.7 C++中使用Opencv
🔗 NO.8 C++ 直方图 & 卷积
🔗 NO.9 C++ 匹配 & 变化
🔗 NO.10 C++ 图像算法

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

零蚀zero eclipse

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值