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
opencv 学习day02
猜你喜欢
转载自blog.csdn.net/qq_24137739/article/details/85124373
今日推荐
周排行