小杰机械视觉(finally)——题库上——gray、thresh、erode、dilate、HSV、开运算、ROI切割、矫正。
声明:机械视觉部分的所有图片均来自网络,不保证真实性,与本人无关,仅用于学习。
1.使用下面的图片,拆分为三通道显示。
提示:读取图片使用OpenCV的imread函数,返回值三维数组。
手搓
import cv2
import matplotlib.pylab as plt
import numpy as npif __name__ == "__main__":path = "./lena.png"# path = 'rgb.jpg'image_np = cv2.imread(path)image_shape = image_np.shape# 读取图像后BGR转RGBimage_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# rgbred_channel = np.zeros((image_shape[0], image_shape[1], 3), dtype=np.uint8)red_channel[:, :, 0] = rgreen_channel = np.zeros((image_shape[0], image_shape[1], 3), dtype=np.uint8)green_channel[:, :, 1] = gblue_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 pltif __name__ == '__main__':# 1. 图片输入path = 'lena.png'image_np = cv2.imread(path)image_shape = image_np.shapeprint(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.299wg = 0.587wb = 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] = avgprint(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', # 必须:titleimage_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] * wbavg = int(avg)# 存储到image_np_gray中image_np_gray[i, j] = avgprint(image_np_gray)# 3. 二值化thresh = 127 # 阈值maxval = 255 # 最大值# 遍历全图像素点for i in range(image_shape[0]):for j in range(image_shape[1]):# 如果像素值小于等于阈值,则设定为0if image_np_gray[i,j][0] <= thresh:image_np_gray[i,j] = 0else: # 其他情况下为最大值image_np_gray[i,j] = maxval# 4. 图片输出cv2.imshow('image_np_gray',image_np_gray)cv2.waitKey(0)
4.手搓 OTSU
COLOR_BGR2GRAY)maxval = 255variance = [] # 方差# L是0-255的灰度值for L in range(256):T, n0, n1, w0, w1, u0, u1, u = L, 0, 0, 0, 0, 0, 0, 0print(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 += 1sum_bg += image_np_gray[i, j]# 如果大于阈值,则算到前景上else:n0 += 1sum_fg += image_np_gray[i, j]w0 = n0 / image_sizew1 = n1 / image_size# 刨除掉没有前景和没有背景的情况if n0 != 0:u0 = sum_fg / n0if n1 != 0:u1 = sum_bg / n1u = (sum_fg + sum_bg) / image_sizerows = 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 = iret, 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 npif __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 npif __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])# 制作掩膜1mask1 = cv2.inRange(hsv_image_np, # 基于哪个图像orange_low, # 下限orange_high # 上限)blue_low = np.array([110, 43, 46])blue_high = np.array([124, 255, 255])# 制作掩膜2mask2 = 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, # 原图1image_np, # 原图2mask=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 npif __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. 制作掩膜# 定义红色范围1red_low = np.array([0, 43, 46])red_high = np.array([10, 255, 255])# 制作掩膜1mask1 = cv2.inRange(hsv_image_np, # 基于哪个图像red_low, # 下限red_high # 上限)print(mask1.shape)print(mask1)# 定义红色范围2red_low = np.array([156, 43, 46])red_high = np.array([180, 255, 255])# 制作掩膜2mask2 = 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_CLOSEkernel=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 npif __name__ == '__main__':# 1. 图片输入path = 'cola.jpg'image_np = cv2.imread(path)# 2. BGR转HSVhsv_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转BGRBGR_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 npif __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)# HSVimg_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 cv2if __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 npif __name__ == '__main__':# 1. 图片输入path = 'kunkun.png'# 因为ROI区域可能越界,可以加入异常处理机制try:image_np = cv2.imread(path)# 获得图像尺寸(h, w, _) = image_np.shapeprint(h, w)# 2. 图片切割x_min, x_max = 510, 602y_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 = 2image_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 npif __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)