opencv学习第二天(今天学的有点少)

基本的图像运算

import numpy as np
import cv2 as cv
img = cv.imread('1.jpg')
cv.imshow('img',img)
cv.waitKey(0)

# 可以通过它的行和列坐标访问一个像素值。对于BGR图像,它返回一个Blue、Green、Red值数组。对于灰度图像,只返回对应的强度。
px = img[100,100]
print( px )#[194  91   5]

#只访问蓝色像素
blue = img[100,100,0]#三个索引是:行,列,通道  这里访问的是第一个通道的第100行100列
print( blue )#194

# 您可以以同样的方式修改像素值。
img[100,100] = [255,255,255]
print( img[100,100] )#[255 255 255]

'''Numpy是用于快速数组计算的优化库。因此,简单地获取每个像素值并对其进行修改会非常缓慢,也是不可取的。
说明
上面的方法通常用于选择数组的一个区域,例如前5行和最后3列。对于单个像素访问,Numpy阵列方法、array . item ( )和array.itemset( )被认为更好。但是,它们总是返回一个标量,因此如果要访问所有的B、G、R值,就需要对每个值单独调用array . item ( )。
更好的像素访问和编辑方法:'''
# accessing RED value
print(img.item(10,10,2))#198

# modifying RED value
img.itemset((10,10,2),100)
print(img.item(10,10,2))#100

'''访问图像属性
图像属性包括行数、列数和通道数;图像数据的类型;像素数;等。
图像的形状通过img . shape获取。它返回一个行、列和通道数(如果图像为彩色)的元组:
'''


print(img.shape)#(200, 200, 3) 200行,200列,3个通道
# 如果一幅图像是灰度图像,则返回的元组只包含行数和列数,因此是检查加载图像是灰度还是颜色的好方法。
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
print(gray.shape)#(200, 200)

# 总像素数量通过img . size访问:
print( img.size )#120000

# 图像数据类型通过' img.dtype '获得:注意img . dtype在调试时非常重要,因为OpenCV - Python代码中的大量错误是由无效数据类型引起的。
print( img.dtype )#uint8


'''图像ROI:region of interest
有时候,你将不得不玩某些区域的图像。对于图像中的眼睛检测,首先对整幅图像进行人脸检测。当获得一张人脸后,我们单独选择人脸区域并在其内部搜索眼睛,而不是搜索整个图像。它提高了精度(因为眼睛总是在脸上: D)和性能(因为我们在一个小区域内搜索)。
使用Numpy索引再次获得ROI。在这里,我选择球,并将其复制到图像中的另一个区域:'''
ball = img[50:100, 50:200]#横坐标50-100,列坐标50-200的区域
cv.imshow('ball',ball)
cv.waitKey(0)
img[10:60, 0:150] = ball#把图片植入img,注意那个区域一定要和ball尺寸一样
cv.imshow('ball',img)
cv.waitKey(0)
print('----------------------------------------')
'''图像通道的拆分与合并
有时,您需要在图像的B、G、R通道上分别工作。在这种情况下,需要将BGR图像分割成单通道。
在其他情况下,你可能需要加入这些单独的渠道来创建一个BGR图像。你可以简单地做到这一点:'''
# 方法一:使用cv.split拆分,cv.merge可合并(也可只合并2个通道,那么第三维度就是2)
b,g,r = cv.split(img)
print(b.shape,g.shape,r.shape)#(200, 200) (200, 200) (200, 200) 均变为了灰度图单通道
img = cv.merge((b,g,r))
print(img.shape)

# 方法二,直接获取
b = img[:,:,0]
print(b.shape)#(200, 200)

# 假设您想要将所有红色像素设置为零-您不需要首先拆分通道。Numpy索引更快
img[:,:,2] = 0#三个索引是:行,列,通道  所以这里的意思是第三通道(即红通道)的所有行列置为0
print(img.shape)#(200, 200, 3)
cv.imshow('ball',img)
cv.waitKey(0)
'''警告
 Cv . split ( )是一个代价高昂的操作(在时间方面)。所以只在必要时使用它。否则转到Numpy索引。'''



'''为图像制作边框(填充)
如果您想在图像周围创建一个边框,就像一个相框一样,您可以使用cv . copyMakeBorder ( )。
但其在卷积运算、补零等方面有更多的应用。该函数取如下参数:
Src - -输入图像的
top, bottom, left, right--边框宽度在相应方向上的像素数目
borderType - -标志定义要添加什么样的边框。它可以是以下类型:
        cv.BORDER_CONSTANT -添加一个恒定的彩色边框。该值应作为下一个论点给出
        cv.BORDER_REFLECT 边界将是边界元素的镜面反射,如:fedcba | abcdefgh | hgfedcb
        cv.BORDER_REFLECT_101 or cv.BORDER_DEFAULT 与上面相同,但稍有改变,如下所示:gfedcb | abcdefgh | gfedcba(少了最边界的那个)
        cv.BORDER_REPLICATE最后一个元素在整个过程中被复制,如:aaaaa | abcdefgh | hhhhhh
        cv.BORDER_WRAP 无法解释,它看起来会是这样的:cdefgh | abcdefgh | abcdefg(把对面的拿过来补)
        cv.BORDER_CONSTANT+value - 边沿加个value颜色的框
下面是一个示例代码,演示所有这些边界类型,以便更好地理解:
'''
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
BLUE = [255,0,0]
img1 = cv.imread('1.png')
# replicate 复制  wrap 包裹
replicate = cv.copyMakeBorder(img1,30,30,30,30,cv.BORDER_REPLICATE)
reflect = cv.copyMakeBorder(img1,30,30,30,30,cv.BORDER_REFLECT)
reflect101 = cv.copyMakeBorder(img1,30,30,30,30,cv.BORDER_REFLECT_101)

wrap = cv.copyMakeBorder(img1,30,30,30,30,cv.BORDER_WRAP)
constant= cv.copyMakeBorder(img1,30,30,30,30,cv.BORDER_CONSTANT,value=BLUE)
# plt.subplot(2,3,4)简写即plt.subplot(231) 表示分割为2行3列,这是第一个
plt.subplot(231),plt.imshow(img1,'gray'),plt.title('ORIGINAL')
plt.subplot(232),plt.imshow(replicate,'gray'),plt.title('REPLICATE')
plt.subplot(233),plt.imshow(reflect,'gray'),plt.title('REFLECT')
plt.subplot(234),plt.imshow(reflect101,'gray'),plt.title('REFLECT_101')
plt.subplot(235),plt.imshow(wrap,'gray'),plt.title('WRAP')
plt.subplot(236),plt.imshow(constant,'gray'),plt.title('CONSTANT')
plt.show()
# 图像通过matplotlib显示。所以RED和BLUE通道将被交换(bgr->rgb)

图像的算术运算

'''学习图像上的几种算术运算,如加法、减法、按位运算(addition, subtraction, bitwise operations)等。
学习这些函数:Cv.Add ( ),Cv.Addweighted ( )等。
图像添加
您可以使用OpenCV函数cv.add ( )添加两幅图像,或者简单地使用numpy operation res = img1 + img2。两个图像应该具有相同的深度和类型,或者第二个图像只能是一个标量值。

说明
 '''
import cv2 as cv
import numpy as np
# OpenCV添加和Numpy添加之间存在差异。OpenCV加法是一个饱和运算,而Numpy加法是一个模运算。
x = np.uint8([250])
y = np.uint8([10])
print( cv.add(x,y) ) # 250+10 = 260 => 255 最大255,超过也是255

print( x+y )          # 250+10 = 260 % 256 = 4  超过则取模


'''这在添加两幅图像时将更加明显。坚持使用OpenCV函数,因为它们会提供更好的结果。
图像融合
这也是图像添加,但不同的权重赋予图像,以便给人一种混合或透明的感觉。根据下面的等式添加图像:
 g ( x ) = ( 1-α ) f0 ( x ) + αf1 ( x )
通过将α从0→1变化,可以在一个图像到另一个图像之间执行一个很酷的转换。
在这里,我采取了两个图像混合在一起。第一幅图像的权重为0.7,第二幅图像的权重为0.3:
 dst = α⋅img1 + β⋅img2 + γ
这里γ取为零。'''
img1 = cv.imread('1.png')
img2 = cv.imread('2.png')
img3=img2[:,:,0]
print(img2.shape,img3.shape)#(200, 200, 3) (200, 200)
dst = cv.addWeighted(img1,0.7,img2,0.3,0)#注意,2个图大小尺寸必须相等!!!
dst2 = cv.addWeighted(img1,0.7,img2,0.3,0)#通道数可以不等!
cv.imshow('dst',dst)
cv.waitKey(0)
cv.imshow('dst',dst2)
cv.waitKey(0)
cv.destroyAllWindows()

 

 位操作

'''位操作
这包括按位的AND、OR、NOT和XOR操作。它们将在提取图像的任何部分(正如我们在接下来的章节中看到的),
定义和处理非矩形ROI等方面非常有用。下面我们将看到一个如何改变图像中特定区域的例子。

我想把OpenCV的标志放在一幅图像上面。如果我增加两幅图像,就会改变颜色。
如果我把它们混合在一起,我就会得到一个透明的效果。但是我想要它是不透明的。如果是一个矩形区域,我可以像上一章那样使用ROI。
但是OpenCV的标志不是一个矩形的形状。因此,您可以通过按位操作来完成,如下所示:'''
# Load two images
img1 = cv.imread('3people.png')
img2 = cv.imread('3logo.png')
# 我想把标志放在左上角,所以我创建了一个roi
rows,cols,channels = img2.shape
roi = img1[0:rows, 0:cols]#获取img2大小的roi
cv.imshow('res',roi)
cv.waitKey(0)
# Now create a mask of logo and create its inverse mask also
img2gray = cv.cvtColor(img2,cv.COLOR_BGR2GRAY)
'''threshold是“阈值”、“临界值”、“门槛”的意思。
参数:
    第一个:老规律了,首先就是你搞搞事情的对象,你要搞谁,搞哪张图片。
    第二个:阈值,threshold,告诉函数门槛是什么。
    第三个:最大值,有可能会用到的值,取决于你后面选取的type,maxval = max value。
    第四个:type,怎么搞事情,搞事情的方法。
我学到的type有一下几种,现在新版本有很多了。
1 cv.THRESH_BINARY 首先解释一下这个参数的英文含义,这是理解的第一步。
THRESH 其实就是:threshold 也就是门槛的意思,代表cv.threshold()这个函数,然后BINARY 是binary 是二进制、二的意思,意在告诉我们结果只有两个。
用代码说的话就是:destination = (src[i,j]>threshold)? maxval : 0;
也就是:灰度图的在[i,j]位置的像素值是否大于阈值,如果大于的话,那么它的值就是maxval,如果不是的话(哪怕是等于也不行),那么就等于0。
通俗的来说就是:threshold就像是一个正直的巡逻官,他在每个灰度图的像素点去巡视(遍历),如果发现有比他小的像素,就直接把这个没用的像素给判死刑,置为0,如果发现比他还要高,还要牛逼的像素点,那么就直接把这个大哥给升到他所能升到的最高值maxval。

2 cv.THRESH_BINARY_INV 还是解释一下,前面的就不解释了,后面的INV 其实就是invert,是反的意思,也就是说和第一个方法恰恰相反。
用代码解释的话就是:destination = (src[i,j] >threshold)? 0:maxval;
就是说,灰度图图的[i,j]位置的像素点的像素值是否大于阈值,如果大于的话,那么就变成0,否则变成最大值。

3 cv.THRESH_TRUNC,“TRUNC” 可以通过百度查到,是“truncate” ,截断的意思。
用代码理解就是:destination = (src[i,j] >threshold)? maxval : src[i,j]
这个意思恰好解释了其原理的一部分。其原理就是:遍历每一个灰度图的像素,如果遍历到的像素值大于这个阈值,那么就把这个像素值变成你预先输入的maxval,
在这里maxval可以理解成一个像素值可以达到的最大值,如果小于等于,那么就保持不变。
4 cv.THRESH_TOZERO
“TOZERO” 可以看成 “to zero" 可以理解成:变成0的意思。
用代码理解:destination = (src[i,j] >threshold)? src[i,j] : 0;
也就是,遍历灰度图的每一个像素点,如果遍历到的像素值大于这个阈值,那么保持不变,如果小于等于这个阈值,那么不好意思,直接为0。

5 cv.THRESH_TOZERO_INV
”TOZERO_INV" 可以理解为:“to zero invert" 也就是,变成零的反义词,和上一个操作完全相反。
用代码理解:destination = (src[i,j] > threshold)? 0:src[i,j]
也就是:遍历灰度图的每个一像素点,如果遍历到的像素点的像素值大于这个阈值,那么直接为0,否则,如果小于等于这个阈值,那么就保持不变。'''
ret, mask = cv.threshold(img2gray, 10, 255, cv.THRESH_BINARY)
cv.imshow('mask',mask)
cv.waitKey(0)
mask_inv = cv.bitwise_not(mask)#异或运算not,主要就是反转颜色
cv.imshow('mask_inv',mask_inv)
cv.waitKey(0)
#现在对ROI中的logo区域进行遮盖
'''cv.bitwise_and 1:cv.bitwise_and(roi,roi,mask)加mask,然后roi为RGB图像选取掩膜选定的区域(即mask中白色的位置)
                    2:cv.bitwise_and(img1,img2)不加mask 取图片交集'''
img1_bg = cv.bitwise_and(roi,roi,mask = mask_inv)
cv.imshow('imgbg',img1_bg)
cv.waitKey(0)

img2_fg = cv.bitwise_and(img2,img2,mask = mask)# 从标志图像中只取标志区域。
cv.imshow('res',img2_fg)
cv.waitKey(0)
# 将 logo 放入 ROI 并修改主图像(如果直接用roi而不是img1——bg,那么得出的dstlogo区域就会透明,因为考虑了原图像像素
#img——bg的作用就是将标志区域置为0,纯黑色,相加就仅仅是logo区域的色素
dst = cv.add(img1_bg,img2_fg)
img1[0:rows, 0:cols ] = dst
cv.imshow('res',img1)
cv.waitKey(0)
cv.destroyAllWindows()

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值