声明:机械视觉部分的所有图片均来自网络,不保证真实性,与本人无关,仅用于学习。
1.使用下面的图片,拆分为三通道显示。
提示:读取图片使用OpenCV的imread函数,返回值三维数组。
手搓
import cv2
import matplotlib.pylab as plt
import numpy as np
if __name__ == "__main__":
path = "./lena.png"
# path = 'rgb.jpg'
image_np = cv2.imread(path)
image_shape = image_np.shape
# 读取图像后BGR转RGB
image_np_rgb = cv2.cvtColor(
image_np,
cv2.COLOR_BGR2RGB
)
# 拆分颜色通道
r, g, b = cv2.split(image_np_rgb)
# 创建数组用来记录保存下来的三种颜色
# red_channel = np.zeros((256, 256, 3), dtype=np.uint8)
# red_channel[:, :, 0] = r
# green_channel = np.zeros((256, 256, 3), dtype=np.uint8)
# green_channel[:, :, 1] = g
# blue_channel = np.zeros((256, 256, 3), dtype=np.uint8)
# blue_channel[:, :, 2] = b
# rgb
red_channel = np.zeros((image_shape[0], image_shape[1], 3), dtype=np.uint8)
red_channel[:, :, 0] = r
green_channel = np.zeros((image_shape[0], image_shape[1], 3), dtype=np.uint8)
green_channel[:, :, 1] = g
blue_channel = np.zeros((image_shape[0], image_shape[1], 3), dtype=np.uint8)
blue_channel[:, :, 2] = b
# 显示
plt.subplot(131) # 一行三列的第一张图
plt.imshow(blue_channel)
plt.title('Blue Channel')
plt.axis('off')
plt.subplot(132) # 一行三列的第2张图
plt.imshow(green_channel)
plt.title('Green Channel')
plt.axis('off')
plt.subplot(133) # 一行三列的第3张图
plt.imshow(red_channel)
plt.title('Red Channel')
plt.axis('off')
plt.show()
2.手搓灰度化算法
import cv2
import numpy as np
import matplotlib.pyplot as plt
if __name__ == '__main__':
# 1. 图片输入
path = 'lena.png'
image_np = cv2.imread(path)
image_shape = image_np.shape
print(image_shape) # (512, 512, 3)
# print(image_np)
# 2. 三通道图 + 灰度化
# 创建一个纯黑图,分辨率相同,用于后续存储灰度后的数据
image_np_gray = np.zeros((image_shape[0], image_shape[1], 3), dtype=np.uint8)
print(image_np_gray.shape)
# 数据拷贝
image_np_gray = image_np.copy()
# print(image_np_gray)
# 三个权重
wr = 0.299
wg = 0.587
wb = 0.114
# 遍历全局像素
for i in range(image_shape[0]):
for j in range(image_shape[1]):
# print(i,j)
# 加权平均法
avg = image_np[i, j][2] * wr + image_np[i, j][1] * wg + image_np[i, j][0] * wb
# print(avg)
avg = int(avg)
# print(avg)
# 存储到image_np_gray中
image_np_gray[i, j] = avg
print(image_np_gray.shape)
print(image_np_gray) # 如果BGR三通道的数值相同,表示灰度,但真正的灰度只需要一个通道
# 4. 图片输出
# plt.imshow(image_np_gray)
# plt.title('image_np_gray')
# plt.axis('off')
# plt.show()
# 后续彩图可以直接使用OpenCV展示,CV展示图片会收到系统缩放的影响
cv2.imshow('image_np_gray', # 必须:title
image_np_gray) # 展示的图像
cv2.waitKey(0) # 等待按下任意按键关闭弹窗
3.手搓二值化
= 0.114
# 遍历全局像素
for i in range(image_shape[0]):
for j in range(image_shape[1]):
# 加权平均法
avg = image_np[i, j][2] * wr + image_np[i, j][1] * wg + image_np[i, j][0] * wb
avg = int(avg)
# 存储到image_np_gray中
image_np_gray[i, j] = avg
print(image_np_gray)
# 3. 二值化
thresh = 127 # 阈值
maxval = 255 # 最大值
# 遍历全图像素点
for i in range(image_shape[0]):
for j in range(image_shape[1]):
# 如果像素值小于等于阈值,则设定为0
if image_np_gray[i,j][0] <= thresh:
image_np_gray[i,j] = 0
else: # 其他情况下为最大值
image_np_gray[i,j] = maxval
# 4. 图片输出
cv2.imshow('image_np_gray',image_np_gray)
cv2.waitKey(0)
4.手搓 OTSU
COLOR_BGR2GRAY)
maxval = 255
variance = [] # 方差
# L是0-255的灰度值
for L in range(256):
T, n0, n1, w0, w1, u0, u1, u = L, 0, 0, 0, 0, 0, 0, 0
print(T)
sum_fg, sum_bg = 0, 0 # 前景和 背景和
# 全图像素点遍历
for i in range(image_shape[0]):
for j in range(image_shape[1]):
# 如果小于等于T阈值,则算到背景上
if image_np_gray[i, j] <= T:
n1 += 1
sum_bg += image_np_gray[i, j]
# 如果大于阈值,则算到前景上
else:
n0 += 1
sum_fg += image_np_gray[i, j]
w0 = n0 / image_size
w1 = n1 / image_size
# 刨除掉没有前景和没有背景的情况
if n0 != 0:
u0 = sum_fg / n0
if n1 != 0:
u1 = sum_bg / n1
u = (sum_fg + sum_bg) / image_size
rows = image_shape[0]
cols = image_shape[1]
g = w0 * ((u0 - u) ** 2) + w1 * ((u1 - u) ** 2)
variance.append(g)
print(variance)
# 最合适的T值,就是最大的那个
for i in range(256):
if variance[i] == max(variance):
print('OTSU找到的最大类间方差是', variance[i])
print('OTSU对应的灰度值:', i)
T = i
ret, image_np_gray = cv2.threshold(
image_np_gray, # 灰度图
T, # 阈值
maxval, # 最大值
cv2.THRESH_BINARY # 二值化
)
# 4. 图片输出
cv2.imshow('image_np_gray', image_np_gray)
cv2.waitKey(0)
5.自适应二值化
import cv2
import numpy as np
if __name__ == '__main__':
# 1. 图片输入
path = 'lena.png'
image_np = cv2.imread(path)
# 2. 灰度化(为了手搓二值化,暂时手搓灰度化)
image_np_gray = cv2.cvtColor(image_np,
cv2.COLOR_BGR2GRAY) # BGR→灰度
# 3. 自适应二值化
maxval = 255 # 最大值
# 自适应二值化
# 返回值:自适应二值化之后的图像
image_np_adaptive = cv2.adaptiveThreshold(
image_np_gray, # 要处理的灰度化图像
maxval, # 最大值
cv2.ADAPTIVE_THRESH_MEAN_C, # 阈值的权重计算方式
cv2.THRESH_BINARY_INV, # 阈值法还是反阈值法
7, # 核大小
10, # C值大小
)
# 4. 图片输出
cv2.imshow('image_np_adaptive', image_np_adaptive)
cv2.waitKey(0)
6.黑色更黑,白色更白,只保留小人。
import cv2
import numpy as np
# 读取
path = 'people.jpg'
image = cv2.imread(path)
# 准备ROI
x_min, x_max = 700, 1000
y_min, y_max = 515, 1000
# 创建一个数值全为180的一模一样数组,模拟灰度化,与背景颜色相近
image_out = np.full_like(image, 180)
# 将小人覆盖到新数组中
image_out[y_min:y_max, x_min:x_max] = image[y_min:y_max, x_min:x_max]
# 灰度化
image_out = cv2.cvtColor(image_out, cv2.COLOR_BGR2GRAY)
# 二值化
_, image_out = cv2.threshold(image_out, 165, 255, cv2.THRESH_BINARY)
# 手动开运算
kernel = cv2.getStructuringElement(cv2.MORPH_CROSS, (3, 3))
image_out = cv2.dilate(image_out, kernel) # 白色膨胀,相当于黑色腐蚀
kernel = cv2.getStructuringElement(cv2.MORPH_CROSS, (15, 15))
image_out = cv2.erode(image_out, kernel) # 白色腐蚀,相当于黑色膨胀
cv2.imshow('image_np', image_out)
cv2.imwrite('man.png', image_out)
cv2.waitKey(0)
7.识别下图中的蓝色(不包括云的边框)和橙色
import cv2
import numpy as np
if __name__ == '__main__':
path = 'imgs/rainbow.png'
image_np = cv2.imread(path)
# HSV空间转换
hsv_image_np = cv2.cvtColor(image_np, cv2.COLOR_BGR2HSV)
print(hsv_image_np.shape)
# 制作掩膜
orange_low = np.array([11, 43, 46])
orange_high = np.array([25, 255, 255])
# 制作掩膜1
mask1 = cv2.inRange(
hsv_image_np, # 基于哪个图像
orange_low, # 下限
orange_high # 上限
)
blue_low = np.array([110, 43, 46])
blue_high = np.array([124, 255, 255])
# 制作掩膜2
mask2 = cv2.inRange(
hsv_image_np, # 基于哪个图像
blue_low, # 下限
blue_high # 上限
)
# 合并掩膜
mask_image_np = cv2.bitwise_or(mask1, mask2)
# 腐蚀
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
eroded_mask = cv2.erode(mask_image_np, kernel)
# 与操作
final_image = cv2.bitwise_and(image_np, # 原图1
image_np, # 原图2
mask=eroded_mask) # 掩膜
# 图片输出
cv2.imshow('source', image_np)
# cv2.imshow('mask_image_np', mask_image_np)
cv2.imshow('color_image_np', final_image)
# cv2.imwrite('imgs/blue&orange.png', final_image)
cv2.waitKey(0)
8.修改红色圆圈为蓝色,不修改红色噪点
import cv2
import numpy as np
if __name__ == '__main__':
# 1. 图片输入
path = 'Circles.png'
image_np = cv2.imread(path)
# 2. HSV空间转换
hsv_image_np = cv2.cvtColor(image_np, cv2.COLOR_BGR2HSV)
print(hsv_image_np.shape)
# print(hsv_image_np)
# 3. 制作掩膜
# 定义红色范围1
red_low = np.array([0, 43, 46])
red_high = np.array([10, 255, 255])
# 制作掩膜1
mask1 = cv2.inRange(
hsv_image_np, # 基于哪个图像
red_low, # 下限
red_high # 上限
)
print(mask1.shape)
print(mask1)
# 定义红色范围2
red_low = np.array([156, 43, 46])
red_high = np.array([180, 255, 255])
# 制作掩膜2
mask2 = cv2.inRange(
hsv_image_np, # 基于哪个图像
red_low, # 下限
red_high # 上限
)
# 合并掩膜
mask_image_np = cv2.bitwise_or(mask1, mask2)
print(mask_image_np.shape)
print(mask_image_np)
# 4. 开运算
# 创建一个核
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
# 开运算
open_image_np = cv2.morphologyEx(
src=mask_image_np, # 需要计算的二值化图像
op=cv2.MORPH_OPEN, # 开操作还是闭操作cv2.MORPH_CLOSE
kernel=kernel # 核
)
# 7. 颜色替换
for i in range(open_image_np.shape[0]):
for j in range(open_image_np.shape[1]):
# 如果当前遍历的像素点是掩膜的白色
if open_image_np[i, j] == 255:
# 给原图进行颜色替换为蓝色
image_np[i, j] = (255, 0, 0)
# 6. 图片输出
cv2.imshow('mask_image_np', mask_image_np)
cv2.imshow('open_image_np', open_image_np)
cv2.imshow('image_np',image_np)
cv2.waitKey(0)
9.把百事可乐的配色改为可口可乐风格

import cv2
import numpy as np
if __name__ == '__main__':
# 1. 图片输入
path = 'cola.jpg'
image_np = cv2.imread(path)
# 2. BGR转HSV
hsv_image_np = cv2.cvtColor(image_np, cv2.COLOR_BGR2HSV)
# print(hsv_image_np.shape)
# print(hsv_image_np)
# 3. 制作掩膜
# 主色调蓝色
blue_low2 = np.array([90, 90, 90])
blue_high2 = np.array([130, 255, 255])
mask1 = cv2.inRange(
hsv_image_np, # 图像
blue_low2, # 下限
blue_high2 # 上限
)
# 高光蓝色
blue_low2 = np.array([80, 40, 240])
blue_high2 = np.array([130, 90, 255])
mask2 = cv2.inRange(
hsv_image_np, # 图像
blue_low2, # 下限
blue_high2 # 上限
)
mask_image = cv2.bitwise_or(mask1, mask2)
# 4. 颜色变换
for i in range(mask_image.shape[0]):
for j in range(mask_image.shape[1]):
# 如果当前遍历的像素点是掩膜的白色
if mask_image[i, j] == 255:
# 色相偏移
hsv_image_np[i, j, 0] += 72
# 微调饱和度
if hsv_image_np[i, j, 1] <= 250:
hsv_image_np[i, j, 1] += 5
# HSV转BGR
BGR_image = cv2.cvtColor(hsv_image_np, cv2.COLOR_HSV2BGR)
# 6. 图片输出
# cv2.imshow('mask2', mask2)
# cv2.imshow('source', cv2.imread(path))
cv2.imshow('edited', BGR_image)
# cv2.imwrite('imgs/pepsi2coke.png',BGR_image)
cv2.waitKey(0)
10.把越和幸运都换成蓝色,让墙变得更白
import cv2
import numpy as np
if __name__ == '__main__':
path = './img/hw4.jpg'
img = cv2.imread(path)
print(img.shape[:-1])
# 灰度化
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 二值化
ret, img_binary = cv2.threshold(img_gray, 137, 255, cv2.THRESH_BINARY)
# HSV
img_hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# 调高图片的亮度
img_hsv[:, :, 2] = img_hsv[:, :, 2] * 1.5 # 此处注意,不太好
# 提取红色和黄色以及蓝色范围
lower_red1 = np.array([0, 43, 46])
upper_red1 = np.array([10, 255, 255])
lower_red2 = np.array([160, 43, 46])
upper_red2 = np.array([179, 255, 255])
lower_yellow = np.array([26, 40, 46])
upper_yellow = np.array([34, 255, 255])
lower_blue = np.array([100, 145, 46])
upper_blue = np.array([110, 255, 255])
# 掩膜
mask_red = cv2.inRange(img_hsv, lower_red1, upper_red1) + cv2.inRange(img_hsv, lower_red2, upper_red2)
mask_yellow = cv2.inRange(img_hsv, lower_yellow, upper_yellow)
mask_blue = cv2.inRange(img_hsv, lower_blue, upper_blue)
# 膨胀
kernel = np.ones((5, 5), np.uint8)
mask_yellow = cv2.dilate(mask_yellow, kernel, iterations=1)
# 合并掩膜
mask = mask_red + mask_yellow + mask_blue
# 替换颜色
img[mask > 0] = [147, 87, 35] # 掩膜的白色设置为蓝色
img[img_binary > 0] = [255, 255, 255] # 原来的白色变得更白
# 使用CV2绘图
cv2.imshow('img', img)
cv2.waitKey(0)
cv2.imwrite('./img/hw4_ret.jpg', img)
11.把原图噪点去掉
import cv2
if __name__ == '__main__':
# 读取
img = cv2.imread('Circles.png')
# 灰度化
gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 二值化
ret, image_np_gray = cv2.threshold(gray_img, 228, 255, cv2.THRESH_BINARY_INV)
# 核:开运算
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
open_img = cv2.morphologyEx(src=image_np_gray, op=cv2.MORPH_OPEN, kernel=kernel)
# 如果降噪后的二值化图是黑色(原图中的白色),就直接原图替换为白色
for i in range(open_img.shape[0]):
for j in range(open_img.shape[1]):
if open_img[i, j] == 0:
img[i, j] = (255, 255, 255)
# cv2.imshow('s', open_img)
cv2.imshow('a', img)
# cv2.imwrite('a.png', img)
cv2.waitKey(0)
12.使用ROI切割,截取坤坤的篮球。
import cv2
import numpy as np
if __name__ == '__main__':
# 1. 图片输入
path = 'kunkun.png'
# 因为ROI区域可能越界,可以加入异常处理机制
try:
image_np = cv2.imread(path)
# 获得图像尺寸
(h, w, _) = image_np.shape
print(h, w)
# 2. 图片切割
x_min, x_max = 510, 602
y_min, y_max = 271, 361
# 判断ROI区域是否合理
if not ((x_min > 0) and (x_max < w) and (y_min > 0) and (y_max < h)):
raise OverflowError('范围越界!!!')
if (x_min >= x_max) or (y_min >= y_max):
raise ValueError("最值错误!!!")
# 框的宽度
line_width = 2
image_np_copy = image_np.copy()
# 画出ROI区域
cv2.rectangle(
image_np,
(x_min, y_min),
(x_max, y_max),
(0, 0, 255),
line_width
)
# 切片(左闭右开)
ROI_imge = image_np_copy[y_min:y_max, x_min:x_max]
# 3. 图片输出
cv2.imshow('image_np', image_np)
cv2.imshow('ROI_imge', ROI_imge)
cv2.waitKey(0)
except Exception as e:
# 如果出错,弹出错误信息
print('错误信息:', e)
13.把下面的文件通过透视变换恢复扫描样式,尽量优化显示:白的更白、黑的更黑、噪声更少、红色原样。
图片来自于网络,不保证真实性,与本人无关,仅用于学习记录。
import cv2
import numpy as np
if __name__ == '__main__':
# 1. 图片输入
path = './image/document.jpg'
image_np = cv2.imread(path)
# 2. 坐标选取
# 左上、右上、左下、右下
points = [[71, 38], [406, 124], [60, 639], [485, 582]]
# 转换为np数组
pts1 = np.float32(points) # src的四个角点
# 3. 获取透视变换矩阵
# 获得原图分辨率
img_shape = image_np.shape
# 左上、右上、左下、右下
points = [[0, 0], [img_shape[1], 0], [0, img_shape[0]], [img_shape[1], img_shape[0]]]
# 转换为np数组
pts2 = np.float32(points) # dst的四个角点
# 生成透视变换矩阵
M = cv2.getPerspectiveTransform(
pts1, # src的四个角点
pts2 # dst的四个角点
)
# 4. 透视变换 + 5. 插值方法 + 6. 边缘填充
correct_image = cv2.warpPerspective(
image_np, # 原图
M, # 透视变换矩阵
(img_shape[1], img_shape[0]), # dst分辨率
cv2.INTER_LANCZOS4, # 插值方法
cv2.BORDER_WRAP # 边缘填充
)
# 灰度化
image_np_gray = cv2.cvtColor(correct_image, cv2.COLOR_BGR2GRAY)
# 二值化
ret, image_np_gray = cv2.threshold(image_np_gray, 145, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
for i in range(image_np_gray.shape[0]):
for j in range(image_np_gray.shape[1]):
# 如果二值化是白色的(纸)
if image_np_gray[i, j] == 255:
# 让彩图的纸变得更白
correct_image[i, j] = (255, 255, 255)
# 如果二值化是黑色的,且不是在红色区域的黑色
elif (image_np_gray[i, j] == 0) and (100 < i < 376 or 526 < i < image_np_gray.shape[0]):
# 让彩图的黑色变得更黑
correct_image[i, j] = (0, 0, 0)
# 7. 图片输出
cv2.imshow('correct_image', correct_image)
# cv2.imshow('image_np_gray',image_np_gray)
cv2.waitKey(0)