Opencv-python从入门到放弃 —— ROI,掩膜,像素点逻辑操作(5)

自己是一个菜鸡,希望通过写博客的方式提升自己,最近正好接触到了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的功能相同吧。

二、Demo

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)

运行结果
image_src.jpg
cropped.jpg
image_src.jpg
———-越界加减法操作———-
Numpy uint8矩阵加法越界操作:254 + 10 = 8
Numpy uint8矩阵减法越界操作:10 - 20 = 246
用opencv的方法对Numpy uint8矩阵做加法越界操作:254 + 10 = 255
用opencv的方法对Numpy uint8矩阵做减法越界操作:10 - 20 = 0
加法clip.jpg
减法clip.jpg
———-像素点间的四种逻辑操作———-
rectangle.jpgcircle.jpgand.jpgor.jpgxor.jpgnot.jpg
bench.jpgmask.jpgimage_with_mask.jpg

总结

  1. 用numpy的切片操作可以很方便的提取图像ROI
  2. 对图像的加减运算最好用cv2.add()和cv2.subtract()防止出现意想不到的错误
  3. 四种基于像素点的逻辑操作
  4. 掩膜图像上为255的地方进行相应的逻辑操作,掩膜图像的大小应与原图保持一致!
  5. 博客排版有点乱。。。。

猜你喜欢

转载自blog.csdn.net/Annihilation7/article/details/82530899