个人技术分享

图像基本操作

访问和修改像素值

import numpy as np
import cv2
img = cv2.imread('c:/Users/HP/Downloads/basketball.png')
h,w,c = img.shape
#图像大小
print(h,w,c)


### 841 1494 3
# 通过行和列坐标访问像素值
img[100,100]


### 231
### array([231, 140, 146], dtype=uint8)
# 通过行和列坐标访问像素值
img[100,100]


### array([231, 140, 146], dtype=uint8)
# # 仅访问蓝色通道的像素
blue = img[100,100,0]
print(blue)


### 231
# 修改颜色
img[100,100] = [255,255,255]
print(img[100,100])


### [255 255 255]

Numpy 访问每个像素值并修改其值非常缓慢,

更好的访问和编辑像素的方法:

#访问 红色通道 的值
img.item(10,10,2)


### 131
#修改 红色通道 的值
img.itemset((10,10,2),100)
img.item(10,10,2)


### 100

访问图像属性

print(img.shape)
# 如果图像是灰度图像,则返回的元组仅包含行数和列数,因此它是检查加载的图像是灰度图还是彩色图的一种很好的方法


### (841, 1494, 3)
print(img.size)  # 总像素数


### 3769362
print(img.dtype)  # 图像数据类型


### uint8

图像中的感兴趣区域

from matplotlib import pyplot as plt

plt.imshow(img)

在这里插入图片描述

from matplotlib import pyplot as plt

ball = img[450:600,450:650]
plt.xticks([]), plt.yticks([]) # 隐藏 X 和 Y 轴的刻度值
plt.imshow(ball)

在这里插入图片描述

拆分和合并图像通道

b,g,r = cv2.split(img)  # 分割为单通道
img = cv2.merge((b,g,r))  # 合并

b = img[:,:,0]  # 或者使用numpy.array的切片方法

img[:,:,2] = 0  # 要将所有红色像素设置为零,则无需先拆分通道;Numpy 索引更快

## warning:CV.spilt()是一项代价高昂的操作(就时间而言)。所以只在你需要时再这样做,否则使用 Numpy 索引。

制作图像边界(填充)

import cv2 as CV
import numpy as np
from matplotlib import pyplot as plt
BLUE = [255,0,0]
img1 = img
replicate = CV.copyMakeBorder(img1,10,10,10,10,CV.BORDER_REPLICATE)
reflect = CV.copyMakeBorder(img1,10,10,10,10,CV.BORDER_REFLECT)
reflect101 = CV.copyMakeBorder(img1,10,10,10,10,CV.BORDER_REFLECT_101)
wrap = CV.copyMakeBorder(img1,10,10,10,10,CV.BORDER_WRAP)
constant= CV.copyMakeBorder(img1,10,10,10,10,CV.BORDER_CONSTANT,value=BLUE)
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()

在这里插入图片描述

图像的算术运算

图像加法

# 可以通过 cv.add()或简单地通过 numpy 操作将两个图像相加,res = img1 + img2;
# 两个图像应该具有相同的深度和类型,或者第二个图像可以是像素值,比如(255,255,255),白色值。

img1 = cv2.imread('c:/Users/HP/Downloads/basketball.png')
img2 = cv2.imread('c:/Users/HP/Downloads/jump.png')
res = img1 + img2

plt.xticks([]), plt.yticks([]) # 隐藏 X 和 Y 轴的刻度值
plt.imshow(res)

在这里插入图片描述

图像混合

也是加法,但两幅图像的权重不同,就会给人一种混合或者透明的感觉。图像混合的计算公式如下:

g(x) = (1−α)f0(x) + αf1(x)

函数cv2.addWeighted()可以按下面的公式对图片进行混合操作:

dst = α⋅img1 + β⋅img2 + γ

dst = cv2.addWeighted(img1,0.7, img2,0.3, 0)

plt.xticks([]), plt.yticks([]) # 隐藏 X 和 Y 轴的刻度值
plt.imshow(dst)

在这里插入图片描述

按位操作

这包括按位 AND,OR,NOT 和 XOR 运算。它们在提取图像的某一部分(我们将在后面的章节中看到)、定义和使用非矩形 ROI 等方面非常有用。示例:

假如我想加一个OpenCV的 logo在一个图像上,如果只是简单的将两张图像想加,则会改变叠加处的颜色;

如果进行上面所说的混叠操作,则会得到一个有透明效应的结果,但我希望得到一个不透明的logo;

如果logo是一个矩形logo,那可以用上节所讲的ROI来做;

但是OpenCV的logo是不规则形状的,所以用下面的bitwise操作来进行:

#加载两张图片
img1 = cv2.imread('c:/Users/HP/Downloads/basketball.png')
img2 = cv2.imread('c:/Users/HP/Downloads/opencv_logo.png')

#我想在左上角放置一个logo,所以我创建了一个 ROI,并且这个ROI的宽和高为我想放置的logo的宽和高
rows,cols,channels = img2.shape
roi = img1 [0:rows,0:cols]

#现在创建一个logo的掩码,通过对logo图像进行阈值,并对阈值结果并创建其反转掩码
img2gray = cv2.cvtColor(img2,cv2.COLOR_BGR2GRAY)
ret,mask = cv2.threshold(img2gray,10,255,cv2.THRESH_BINARY)
mask_inv = cv2.bitwise_not(mask)

#现在使 ROI 中的徽标区域变黑
img1_bg = cv2.bitwise_and(roi,roi,mask = mask_inv)

plt.xticks([]), plt.yticks([]) # 隐藏 X 和 Y 轴的刻度值
plt.imshow(img1_bg)

#仅从徽标图像中获取徽标区域。
img2_fg = cv2.bitwise_and(img2,img2,mask = mask)

#在 ROI 中放置徽标并修改主图像
dst2 = cv2.add(img1_bg,img2_fg)
res = img1
res [0:rows,0:cols] = dst2

plt.xticks([]), plt.yticks([]) # 隐藏 X 和 Y 轴的刻度值
plt.imshow(res)

在这里插入图片描述