自己是一个菜鸡,希望通过写博客的方式提升自己,最近正好接触到了opencv,想把学习路程以博客的形式记录下来,也算是学习opencv的一种动力吧,好吧,话不多说,干就完了!
图像ROI:
图像ROI(Region Of Interest),即感兴趣的区域,该操作能够非常轻松的通过numpy的切片操作实现。
注意切片操作后对ROI像素值的更改也会影响到原图,如果不想影响到原图,先将roi做一个copy操作就好,roi_copy = roi.copy()
图像像素值的界限
两个uint8的ndarray相加,值超过255的部分将会以对256取模的方式返回到结果中,在减法中由于无符号减法是两数的补码相减,减完后再返回相应的原码(不想细说这部分了。。几乎没有人会用到无符号整数的越界操作),所以给人一种首尾相连的感觉。
比如:254+10=8,10-20=246
而用opencv的add与subtract对两个uint8 ndarray操作的化会自动clip到[0, 255]上,所以在对像素做加减法的时候最好用opencv的函数,结果一定会符合预期!
比如:254+10=255,10-20=0
图像像素的逻辑操作
像素逻辑操作共有四种,三种为二元操作类型:与,或,异或操作,一种为一元操作类型:非
特点:1. 图像最好是是二值图像,即像素点的值要么是0,要么就是255,没有其他值。不是二值图像的话opencv也支持。 2.像素级的操作,也就是对应像素间的操作,所以两图像大小必须一致。
逻辑与:两个都为真才是真,cv2.bitwise_and(img1, img2, mask)
逻辑或:有一个为真就是真,cv2.bitwise_or(img1, img2, mask)
逻辑异或:两者不同为真,cv2.bitwise_xor(img1, img2, mask)
逻辑非:原先为假结果就是真,原先为真结果就是假,cv2.bitwise_not(img1,mask)
掩膜
上面的函数最后一项都为mask,这就是掩膜,具体作用就是真正要进行操作的区域,因为有的时候我们并不需要对整个图像进行操作。
掩膜的大小与原图像相同,为二值图像,我们真正要操作的区域就是掩膜图像中的非零部分(即灰度值为255的部分),与ROI的功能相同吧。
image = cv2.imread('./trex.png')
cv2.imwrite('image_src.jpg', image)
image_copy = image.copy() # copy一下原图,原因后面会说到
roi = image[30: 120, 240: 335] #注意坐标系顺序,这是在numpy中的操作,纵轴范围[30, 119],横轴范围[240, 335]
cv2.imwrite('cropped.jpg', roi)
# 验证对roi的操作能否影响到原图
cv2.circle(roi, (roi.shape[1]//2, roi.shape[0]//2), 30, (0, 0, 255), -1) # 在roi区域画个实心圆
cv2.imwrite('image_src.jpg', image) # 结果表明会影响到原图!所以要对原图copy一下
print('----------越界加减法操作----------')
x1 = np.uint8([254]) + np.uint8([10])
print('Numpy uint8矩阵加法越界操作:254 + 10 = %d' % x1[0])
x2 = np.uint8([10]) - np.uint8([20])
print('Numpy uint8矩阵减法越界操作:10 - 20 = %d' % x2[0])
y1 = cv2.add(np.uint8([254]), np.uint8([10]))
print('用opencv的方法对Numpy uint8矩阵做加法越界操作:254 + 10 = %d' % y1[0])
y2 = cv2.subtract(np.uint8([10]), np.uint8([20]))
print('用opencv的方法对Numpy uint8矩阵做减法越界操作:10 - 20 = %d' % y2[0])
#------------------------------------------------------
M = np.ones(image.shape, dtype='uint8') * 100 # 声明dtype真的很重要,不声明会报错
res1 = cv2.add(image_copy, M)
cv2.imwrite('加法clip.jpg', res1)
res2 = cv2.subtract(image_copy, M)
cv2.imwrite('减法clip.jpg', res2)
print('----------像素点间的四种逻辑操作----------')
rectangle = np.zeros((300, 300), dtype='uint8')
cv2.rectangle(rectangle, (25, 25), (275, 275), 255, -1) # 黑色背板构建白色实心矩形
cv2.imwrite('rectangle.jpg', rectangle)
circle = np.zeros((300, 300), dtype='uint8')
cv2.circle(circle, (150, 150), 150, 255, -1) #黑色背板下构建白色实心圆形
cv2.imwrite('circle.jpg', circle)
# 开始操作(对全局图像的操作)
bitwiseAnd = cv2.bitwise_and(rectangle, circle)
cv2.imwrite('and.jpg', bitwiseAnd)
bitwiseOr = cv2.bitwise_or(rectangle, circle)
cv2.imwrite('or.jpg', bitwiseOr)
bitwiseXor = cv2.bitwise_xor(rectangle, circle)
cv2.imwrite('xor.jpg', bitwiseXor)
bitwiseNot = cv2.bitwise_not(rectangle)
cv2.imwrite('not.jpg', bitwiseNot)
# 加入掩膜
image = cv2.imread('./beach.png')
mask = np.zeros((image.shape[:2]), dtype='uint8') # 掩膜与原图一样大,只不过是单通道图像
cv2.circle(mask, (mask.shape[1]//2, mask.shape[0]//2), 100, 255, -1) # 要进行操作的部分是一个位于中心的实心圆,因为中心的实心圆的像素值为255,即白色
cv2.imwrite('mask.jpg', mask)
masked = cv2.bitwise_and(image, image, mask=mask) # image与自身的与操作,结果还是image本身,但是有掩膜的存在,所以只在掩膜图像上像素点值为255的地方进行图像的与操作
cv2.imwrite('image_with_mask.jpg', masked)
运行结果
----------越界加减法操作----------
Numpy uint8矩阵加法越界操作:254 + 10 = 8
Numpy uint8矩阵减法越界操作:10 - 20 = 246
用opencv的方法对Numpy uint8矩阵做加法越界操作:254 + 10 = 255
用opencv的方法对Numpy uint8矩阵做减法越界操作:10 - 20 = 0
----------像素点间的四种逻辑操作----------