opencv 学习day02

1.图像的基础操作
  目标: 获取像素值并修改
        获取图像的属性(信息)
        图像的ROI ()
        图像通道的拆分及合并

       几乎所有这些操做与Numpy的关系都比与OpenCV的关系更加紧密,一次熟悉Numpy可以帮锥们写出性能更好的代码

       你可以根据像素的行和列的坐标获取他的像素值。对BGR图像而言,返回值为B,G,R的值,对灰度图像而言,会返回他的灰度值(亮度?intensity)
  1. 获取并修改像素值
       # 获取像素值
        img = cv2.imread('timg.jpg')
        px = img[100,100]
        print(px)
        # 第三个参数为获取到颜色通道中第(0(蓝色通道)/1(绿色通道)/2(红色通道))个数据
        blue = img[100,100,0]
        print(blue)

        注: Numpy 是经过优化乐的进行快速矩阵运算的软件包。所以我们不推荐逐个获取像素值并修改,这样会很慢,能有矩阵运算就不要用循环
          上面提到的方法被用来选取矩阵的一个区域,比如说前5行的后三列。对于获取每一个像素值,也许使用Numpy的array.item()和array.itemset()
          会更好。但丝毫返回值是标量。如果你想获得所有B,G,R的值,你需要使用array.item() 分割他们。

          例:
            # 获取像素及修改更好的方法
            img =cv2.imread('timg.jpg')
            print(img.item(10,10,2)) # 40
            # 修改img[10,10]的[,,40] 为[,,100]
            img.itemset((10,10,2),100)
            print(img.item(10,10,2))  # 10

  2. 获取图像属性
        图像的属性包括: 行,列,通道,图像数据类型,像素数目等img.shape 可以获取图像的形状。他的返回值是一个包含行数,列数,通道数的元组。
        img = cv2.imread('timg.jpg')
        # img.shape 返回图像的行数,列数,通道数
        print(img.shape)  # (868, 1280, 3)

        # 注意: 如果图像是灰度图,返回值仅有行数和列数。所以通过检查这个返回值就可以知道加载的是灰度图或者彩色图

        img = cv2.imread('timg.jpg')
        # img.size 可以返回图像的像素数目;img.dtype 返回图像的数据类型
        print(img.size,img.dtype)  # 3333120 uint8

  3. 图像 ROI
     有事你需要一幅图像的特定区域进行操作。例如我们要检测一幅图像中的眼睛的位置,我们首先应该在图像中找到脸,再在脸的区域
     中找眼镜,而不是直接在一幅图像中搜索。这样会提高程序的准确性和性能
     在一幅图像中搜索。这样会提高程序的准确性和性能
     ROI 也是使用Numpy索引来获得的。

     例:
        # 图像ROI
        img = cv2.imread('abc.jpg')
        print(img.shape) # 返回值 行,列,通道数
        # 注意: 行=y轴 , 列=x轴, 所以在使用 img进行区域切割的时候需要注意何总坐标位置

        mouse = img[130:540,40:350]

        img[130:540,370:680] = mouse
        cv2.imshow('image',img)
        cv2.waitKey(0)

  4. 拆分及合并图像通道
     有时我们需要对 BGR 三个通道分别进行操作。这时你就需要把BGR拆分成点那个通道。有时你需要把独立通道的图片
     合并称一个BGR图像。

     img = cv2.imread('timg.jpg')
     b,g,r = cv2.split(img)
     # 注意 通道合并函数 cv2.merge()参数为一个数组
     img = cv2.merge([b,g,r])

     例:
        # 拆分及合并图像通道
        img = cv2.imread('timg.jpg')
        b,g,r = cv2.split(img)
        cv2.imshow('blue',b)
        cv2.imshow('green',g)
        cv2.imshow('red',r)
        print(b,g,r)

        # 显示蓝色通道:
        # img = cv2.merge([b,zeros,zeros])

        img = cv2.merge([b,g,r])
        cv2.imshow('img',img)
        cv2.waitKey(0)


         或者

         img = cv2.imread('timg.jpg')
         b = img[:,:,0]

     加入你想是所有像素的红色通道都为0, 你不必先拆分在复制,你可以直接使用Numpy索引

     img = cv2.imread('timg.jpg')
     img[:,:,2] = 0

     注意: cv2.split() 是一个比较耗时的操作,只有真正需要时才用它,能用Numpy索引就尽量用

  5. 为图像扩边(填充)
     如果你想在图像周围创建一个边,就像相框一样,你可以使用cv2.copyMakeBorder()函数。这经常在卷积运算或
     0 填充是被用到。这个函数参数如下:
        src : 输入图像
        top,bottom,left,right 对应便捷的像素数目
        borderType 要添加那种类型的边界,类型如下:
            – cv2.BORDER_CONSTANT 添加有颜色的常数值边界,还需要下一个参数(value)。 (填充value中的颜色)
            – cv2.BORDER_REFLECT 边界元素的镜像。比如: fedcba|abcdefgh|hgfedcb    (头复制头,尾复制尾,但是方向与原图像对称)
            – cv2.BORDER_REFLECT_101 or cv2.BORDER_DEFAULT跟上面一样,但稍作改动。例如: gfedcb|abcdefgh|gfedcba  (头部复制去掉首部,[尾部,如果已经到达底部]的头部,尾部复制去除最后一行的尾部,方向与原图象对称)
            – cv2.BORDER_REPLICATE 重复最后一个元素。例如: aaaaaa|abcdefgh|hhhhhhh (头部复制第一行,尾部复制最后一行)
            – cv2.BORDER_WRAP 不知道怎么说了, 就像这样: cdefgh|abcdefgh|abcdefg  (头部复制除去第一行意外的部分,尾部复制除去最后一行以外的部分,方向与原图象相同)
        value : 边界颜色,如果边界的类型是cv2.BORDER_CONSTANT

2. 图像上的算术运算
    目标 : 学习图像上的算术运算,加法,减法,位运算等
    函数 : cv2.add(), cv2.addWeighted()等
    1. 图像的加法
        你可以使用函数 cv2.add()将两幅图像进行加法运算,当然也可以直接使用numpy,res = img1+ img
        两幅图像的大小,类型必须一致,或者第二个图像可以使一个简单的标量值
        注意:OpenCV中的加法与numpy中的加法是有所不同的,OpenCV中的加法是一种饱和操作,而Numpy的
        加法是一种模操作

        # 图像的加法操作
        例:
            x = np.uint8([250])
            y = np.uint8([10])
            print(cv2.add(x,y)) # 250 + 10 = 260 =>255  # 保留最大值
            # [[255]]

            print(x+y) # 250+10 = 260 % 256 =4  # 取模求余
            # [4]
        这种差别在对图像进行加法时会更加明显。OpenCV的结果会更好一点。所以我们尽量使用OpenCV中的函数

    2. 图像混合
       另一种方式的加法,不同的使两幅图像的权重不同,这就会给人混合或者透明的感觉,图像混合计算公式如下:
        g (x) = (1 − α)f 0 (x) + αf 1 (x)
        通过修改 α 的值(0 → 1),可以实现图像的混合。
        现在我们把两幅图混合在一起。第一幅图的权重是 0.7,第二幅图的权重是 0.3。函数 cv2.addWeighted() 可以按下面的公式对图片进行混合操作。
          dst = α · img1 + β · img2 + γ
        这里 γ 的取值为 0。

        # 图像的混合
        img1 = cv2.imread('abc.jpg')
        img2 = cv2.imread('timg.jpg')

        dst = cv2.addWeighted(img1, 0.7, img2, 0.3, 0)
        cv2.imshow('dst', dst)
        cv2.waitKey(0)
        cv2.destroyAllWindows()

        注: 应注意图像叠加,图像混合的图片应该大小,类型相同,否则会报错。

    3. 按位运算
        按位操作有: AND, OR, NOT, XOR等。当我们提取图像的一部分,选择非矩形ROI时这些操作会很有用。
        例子 : 改变一幅如的特定区域
            如果把Opencv的标志放到另一幅图上:
                方法1: 使用加法,但是颜色会改变
                方法2: 使用混合,但是会的得到透明效果,
                方法3: 如果他是矩形,我可以使用ROI,但是他不是矩形
                方法4: 使用位运算

            threshold:固定阈值二值化,

        ret, dst = cv2.threshold(src, thresh, maxval, type)
        参数:
            src: 输入图,只能输入单通道图像,通常来说为灰度图
            dst: 输出图
            thresh: 阈值
            maxval: 当像素值超过了阈值(或者小于阈值,根据type来决定),所赋予的值
            type:二值化操作的类型,包含以下5种类型: cv2.THRESH_BINARY; cv2.THRESH_BINARY_INV; cv2.THRESH_TRUNC; cv2.THRESH_TOZERO;cv2.THRESH_TOZERO_INV
                cv2.THRESH_BINARY  #黑白二值(二值阈值化)
                cv2.THRESH_BINARY_INV  #黑白二值反转(反转二值阈值化)
                cv2.THRESH_TRUNC  #得到的图像为多像素值(截断阈值化)
                cv2.THRESH_TOZERO  #阈值化到0
                cv2.THRESH_TOZERO_INV #反转阈值化到0


                # load two image
                img2 = cv2.imread('opencv_log.jpg')

                img1 = cv2.imread('abc.jpg')
                cv2.imshow('opencv_logo',img2)
                # I want to put logo on top_left corer, so I  create a ROI
                rows,cols,channels = img2.shape
                roi = img1[0:rows,0:cols]

                # Now create a mask of logo and create its inverse mask alse # 创建一个标志的掩码,并常见反向掩码
                # cv2.cvtColor() 颜色空间转换函数,以便生成mask图
                img2gray = cv2.cvtColor(img2,cv2.COLOR_BGR2GRAY) # 转变为灰度图
                cv2.imshow('img2gray',img2gray)

                # cv2.threahold() 固定阀值二值化, cv2.THRESH_BINARY  黑白阀值(阀值二值化)
                # 阀值设定为10 ,其灰度小与于0,保留,返回给mask,判断其是遵从大于还是小于看type(最后一个参数),
                ret,mask =cv2.threshold(img2gray,10,255,cv2.THRESH_BINARY)
                cv2.imshow('mask',mask)

                # mask 是 白底黑图
                # mask_inv 是 黑底白图

                # 对数据进行非操作 ~1=0  ~0=1
                mask_inv = cv2.bitwise_not(mask)
                cv2.imshow('mask_inv',mask_inv)
                # now black-out the area of logo in ROI # 现在将ROI中的logo区域涂黑
                img1_bg = cv2.bitwise_and(roi,roi,mask = mask_inv)
                cv2.imshow('img1_bg',img1_bg)
                # Take only region of logo from image. # 从中只取logo 区域
                img2_fg = cv2.bitwise_and(img2,img2,mask = mask)

                # put logo in ROI and modify the main image.
                dst = cv2.add(img1_bg,img2_fg)  # 图像相加, 饱和操作(即使相加大雨255,数值只会等于255)
                cv2.imshow('img2_fg',img2_fg)
                cv2.imshow('dst',dst)
                # 重新给区域赋值
                img1[0:rows,0:cols] = dst

                cv2.imshow('res',img1)
                cv2.waitKey(0)
                cv2.destroyAllWindows()

                # 解释参考博客:https://blog.csdn.net/weixin_35732969/article/details/83748054

3. 程序性能检测及优化
    检测程序的效率
    一些能能够提高程序效率的技巧
    你要学到的函数有: cv2.getTickCount, cv2.getTickFrequency等
    除了opencv,python 提供了time模块,你可以用来测量程序的运行时间
    例一个叫做profile的模块会帮你得到一份关于你的程序的详细报告,其中包含了代码中每个函数所需要的时间,以及每个函数被调用的次数

    1. 使用OpenCV检测程序效率
        cv2.getTickCount 函数返回从参考点到这个函数被执行的时钟数。随意你在执行一个函数的前后都调用它的话,你就会得到函数的执行时间(时钟数)
        cv2.getTickFrequency返回时钟频率,或者说每秒钟的时钟数
        例: 获取函数运行时间
            e1 = cv2.getTickCount()
            # your code execution
            e2 = cv2.getTickCount()
            time = (e2 - e1)/ cv2.getTickFrequency



         import time

        img1 = cv2.imread('timg.jpg')
        t1 = time.time()
        e1 = cv2.getTickCount()
        for i in range(5,49,2):
            img1 = cv2.medianBlur(img1,i)
            cv2.imshow('img1_i'+str(i),img1)
        e2 = cv2.getTickCount()
        t2 = time.time() # 精确度更高
        print(t2-t1)  #  8.808879852294922
        t = (e2 - e1) / cv2.getTickFrequency()
        print(t) #8.808619609
        cv2.waitKey(0)
        cv2.destroyAllWindows()

    2. OpenCV中的默认优化
        可以通过 cv2.useOptimized()来查看优化是否被开启了,使用函数cv2.setUseOptimized()来开启优化。
        # print(cv2.useOptimized())
        # cv2.setUseOptimized(False)
        # print(cv2.useOptimized())
         优化是默认开启的。

    3. 在Ipython中检测程序效率
        可以使用Ipython中的 %time命令
        x=5

        %timeit y=x**2
        # 285 ns ± 2.87 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

        %timeit y =x*x
        # 48.3 ns ± 0.112 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

        l = np.uint8(9)

        %timeit s=l*l
        # 94.6 ns ± 2.01 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

        %timeit s =np.square(l)
        # 1.28 µs ± 14 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

        注意:Python 的标量计算比 Nump 的标量计算要快。对于仅包含一两个元素的操作 Python 标量比 Numpy 的数组要快。
             但是当数组稍微大一点时Numpy 就会胜出了。

    4. 更多的Ipython 的魔法命令
        用来检测程序的效率: profiling , line profiling, 内存使用等

    5. 效率优化技术
        首先用简单的方式实现你的算法(结果最重要)
            1. 尽量避免使用循环,尤其是双层三层循环,
            2. 算法中尽量使用向量操作,因为Numpy 和 Opencv都对向量操作进行了优化
            3. 利用高速缓存的一致性
            4. 没有必要的话不要复制数组.以视图来代替复制,数组复制非常浪费资源

学习原博客地址:http://www.cnblogs.com/Undo-self-blog/p/8424220.html
发布了77 篇原创文章 · 获赞 3 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_24137739/article/details/85124373